From 60cc83bf91bfc9bb02f6304b5d6c8234ba6d210f Mon Sep 17 00:00:00 2001 From: Andrew Lee Date: Sun, 15 Aug 2021 00:34:05 -0400 Subject: Added gcc --- gcc-1.40/.dbxinit | 10 + gcc-1.40/.gdbinit | 58 + gcc-1.40/COPYING | 249 + gcc-1.40/ChangeLog | 7378 ++++++++++++++++++++++++++++ gcc-1.40/INSTALL | 860 ++++ gcc-1.40/Makefile | 708 +++ gcc-1.40/OChangeLog | 6671 +++++++++++++++++++++++++ gcc-1.40/PROBLEMS | 128 + gcc-1.40/PROJECTS | 364 ++ gcc-1.40/README | 15 + gcc-1.40/README-ALTOS | 53 + gcc-1.40/README-NS32K | 150 + gcc-1.40/README-VMS | 447 ++ gcc-1.40/README-X11 | 111 + gcc-1.40/SERVICE | 1154 +++++ gcc-1.40/TAGS | 1948 ++++++++ gcc-1.40/alloca.c | 191 + gcc-1.40/assert.h | 32 + gcc-1.40/basic-block.h | 62 + gcc-1.40/c-convert.c | 397 ++ gcc-1.40/c-decl.c | 4103 ++++++++++++++++ gcc-1.40/c-parse.gperf | 56 + gcc-1.40/c-parse.h | 49 + gcc-1.40/c-parse.output | 8092 ++++++++++++++++++++++++++++++ gcc-1.40/c-parse.tab.c | 4280 ++++++++++++++++ gcc-1.40/c-parse.y | 2882 +++++++++++ gcc-1.40/c-tree.h | 154 + gcc-1.40/c-typeck.c | 3807 ++++++++++++++ gcc-1.40/caller-save.c | 666 +++ gcc-1.40/cccp.c | 5795 ++++++++++++++++++++++ gcc-1.40/cexp.c | 1468 ++++++ gcc-1.40/cexp.y | 656 +++ gcc-1.40/combine.c | 2796 +++++++++++ gcc-1.40/conditions.h | 99 + gcc-1.40/config-gcc.com | 26 + gcc-1.40/config.gcc | 418 ++ gcc-1.40/config/alliant.md | 2784 +++++++++++ gcc-1.40/config/convex.md | 1266 +++++ gcc-1.40/config/i386.md | 2021 ++++++++ gcc-1.40/config/i860.md | 2046 ++++++++ gcc-1.40/config/m68k.md | 4156 ++++++++++++++++ gcc-1.40/config/m88k.md | 2273 +++++++++ gcc-1.40/config/mips.md | 1957 ++++++++ gcc-1.40/config/ns32k.md | 2636 ++++++++++ gcc-1.40/config/out-alliant.c | 291 ++ gcc-1.40/config/out-convex.c | 219 + gcc-1.40/config/out-i386.c | 1418 ++++++ gcc-1.40/config/out-i860.c | 1507 ++++++ gcc-1.40/config/out-m68k.c | 560 +++ gcc-1.40/config/out-m88k.c | 605 +++ gcc-1.40/config/out-mips.c | 1086 ++++ gcc-1.40/config/out-ns32k.c | 575 +++ gcc-1.40/config/out-pyr.c | 849 ++++ gcc-1.40/config/out-sparc.c | 2092 ++++++++ gcc-1.40/config/out-spur.c | 316 ++ gcc-1.40/config/out-tahoe.c | 550 +++ gcc-1.40/config/out-vax.c | 152 + gcc-1.40/config/pyr.md | 1377 ++++++ gcc-1.40/config/sparc.md | 2370 +++++++++ gcc-1.40/config/spur.md | 1119 +++++ gcc-1.40/config/tahoe.md | 1497 ++++++ gcc-1.40/config/tm-3b1.h | 482 ++ gcc-1.40/config/tm-3b1g.h | 63 + gcc-1.40/config/tm-aix386.h | 129 + gcc-1.40/config/tm-alliant.h | 1440 ++++++ gcc-1.40/config/tm-altos3068.h | 107 + gcc-1.40/config/tm-apollo68.h | 177 + gcc-1.40/config/tm-att386.h | 244 + gcc-1.40/config/tm-bsd386.h | 202 + gcc-1.40/config/tm-compaq.h | 39 + gcc-1.40/config/tm-conv1os7.h | 6 + gcc-1.40/config/tm-conv2os7.h | 6 + gcc-1.40/config/tm-convex.h | 1034 ++++ gcc-1.40/config/tm-convex1.h | 24 + gcc-1.40/config/tm-convex2.h | 24 + gcc-1.40/config/tm-decstatn.h | 27 + gcc-1.40/config/tm-delta68k.h | 486 ++ gcc-1.40/config/tm-encore.h | 202 + gcc-1.40/config/tm-genix.h | 163 + gcc-1.40/config/tm-harris.h | 96 + gcc-1.40/config/tm-hp9k2bsd.h | 53 + gcc-1.40/config/tm-hp9k310.h | 32 + gcc-1.40/config/tm-hp9k310g.h | 12 + gcc-1.40/config/tm-hp9k320.h | 598 +++ gcc-1.40/config/tm-hp9k320g.h | 12 + gcc-1.40/config/tm-hp9k3bsd.h | 36 + gcc-1.40/config/tm-i386.h | 1088 ++++ gcc-1.40/config/tm-i386esix.h | 36 + gcc-1.40/config/tm-i386gas.h | 106 + gcc-1.40/config/tm-i386isc.h | 24 + gcc-1.40/config/tm-i386sco.h | 39 + gcc-1.40/config/tm-i386v.h | 86 + gcc-1.40/config/tm-i386v4.h | 62 + gcc-1.40/config/tm-i386vgas.h | 121 + gcc-1.40/config/tm-i860.h | 1228 +++++ gcc-1.40/config/tm-i860bsdg.h | 4 + gcc-1.40/config/tm-i860g.h | 4 + gcc-1.40/config/tm-iris.h | 48 + gcc-1.40/config/tm-isi68-nfp.h | 5 + gcc-1.40/config/tm-isi68.h | 79 + gcc-1.40/config/tm-m68k.h | 1643 +++++++ gcc-1.40/config/tm-m88k.h | 1128 +++++ gcc-1.40/config/tm-mips-bsd.h | 3 + gcc-1.40/config/tm-mips-news.h | 19 + gcc-1.40/config/tm-mips-sysv.h | 5 + gcc-1.40/config/tm-mips.h | 2309 +++++++++ gcc-1.40/config/tm-news.h | 408 ++ gcc-1.40/config/tm-newsgas.h | 7 + gcc-1.40/config/tm-next.h | 98 + gcc-1.40/config/tm-ns32k.h | 1457 ++++++ gcc-1.40/config/tm-pyr.h | 1406 ++++++ gcc-1.40/config/tm-seq386.h | 79 + gcc-1.40/config/tm-sequent.h | 110 + gcc-1.40/config/tm-sparc.h | 1435 ++++++ gcc-1.40/config/tm-spur.h | 1033 ++++ gcc-1.40/config/tm-sun2.h | 67 + gcc-1.40/config/tm-sun2os4.h | 57 + gcc-1.40/config/tm-sun3-nfp.h | 5 + gcc-1.40/config/tm-sun3.h | 186 + gcc-1.40/config/tm-sun386.h | 218 + gcc-1.40/config/tm-sun386i.h | 105 + gcc-1.40/config/tm-sun3mach.h | 8 + gcc-1.40/config/tm-sun3os3.h | 5 + gcc-1.40/config/tm-sun3os3nf.h | 5 + gcc-1.40/config/tm-sun4os3.h | 15 + gcc-1.40/config/tm-tahoe.h | 850 ++++ gcc-1.40/config/tm-tower-as.h | 616 +++ gcc-1.40/config/tm-tower.h | 100 + gcc-1.40/config/tm-ultrix.h | 7 + gcc-1.40/config/tm-vax.h | 1080 ++++ gcc-1.40/config/tm-vaxv.h | 62 + gcc-1.40/config/tm-vms.h | 117 + gcc-1.40/config/vax.md | 2166 ++++++++ gcc-1.40/config/xm-3b1.h | 7 + gcc-1.40/config/xm-aix386.h | 53 + gcc-1.40/config/xm-alliant.h | 48 + gcc-1.40/config/xm-altos3068.h | 7 + gcc-1.40/config/xm-convex.h | 61 + gcc-1.40/config/xm-delta68k.h | 8 + gcc-1.40/config/xm-genix.h | 9 + gcc-1.40/config/xm-hp9k320.h | 13 + gcc-1.40/config/xm-i386.h | 42 + gcc-1.40/config/xm-i386v.h | 47 + gcc-1.40/config/xm-i860.h | 38 + gcc-1.40/config/xm-iris.h | 7 + gcc-1.40/config/xm-m68k.h | 43 + gcc-1.40/config/xm-m88k.h | 37 + gcc-1.40/config/xm-mips.h | 44 + gcc-1.40/config/xm-ns32k.h | 41 + gcc-1.40/config/xm-pyr.h | 43 + gcc-1.40/config/xm-sparc.h | 44 + gcc-1.40/config/xm-spur.h | 37 + gcc-1.40/config/xm-sun386i.h | 48 + gcc-1.40/config/xm-tahoe.h | 57 + gcc-1.40/config/xm-tower.h | 8 + gcc-1.40/config/xm-umips.h | 44 + gcc-1.40/config/xm-vax.h | 42 + gcc-1.40/config/xm-vaxv.h | 9 + gcc-1.40/config/xm-vms.h | 61 + gcc-1.40/cpp.aux | 82 + gcc-1.40/cpp.cps | 30 + gcc-1.40/cpp.dvi | Bin 0 -> 127892 bytes gcc-1.40/cpp.fns | 51 + gcc-1.40/cpp.info | 69 + gcc-1.40/cpp.info-1 | 1254 +++++ gcc-1.40/cpp.info-2 | 881 ++++ gcc-1.40/cpp.texinfo | 2194 +++++++++ gcc-1.40/cse.c | 3936 +++++++++++++++ gcc-1.40/dbranch.c | 449 ++ gcc-1.40/dbxout.c | 1201 +++++ gcc-1.40/ecoff-cmp | 12 + gcc-1.40/emit-rtl.c | 1633 ++++++ gcc-1.40/explow.c | 575 +++ gcc-1.40/expmed.c | 1888 +++++++ gcc-1.40/expr.c | 5617 +++++++++++++++++++++ gcc-1.40/expr.h | 386 ++ gcc-1.40/final.c | 1652 +++++++ gcc-1.40/fixcpp | 109 + gcc-1.40/fixincludes | 378 ++ gcc-1.40/fixincludes-V4 | 261 + gcc-1.40/fixincludes.old | 165 + gcc-1.40/flags.h | 191 + gcc-1.40/flow.c | 2094 ++++++++ gcc-1.40/fold-const.c | 1838 +++++++ gcc-1.40/gcc.1 | 1310 +++++ gcc-1.40/gcc.aux | 192 + gcc-1.40/gcc.c | 2131 ++++++++ gcc-1.40/gcc.dvi | Bin 0 -> 547688 bytes gcc-1.40/gcc.hlp | 153 + gcc-1.40/gcc.info | 137 + gcc-1.40/gcc.info-1 | 518 ++ gcc-1.40/gcc.info-10 | 1161 +++++ gcc-1.40/gcc.info-11 | 74 + gcc-1.40/gcc.info-2 | 913 ++++ gcc-1.40/gcc.info-3 | 1258 +++++ gcc-1.40/gcc.info-4 | 1022 ++++ gcc-1.40/gcc.info-5 | 1117 +++++ gcc-1.40/gcc.info-6 | 1162 +++++ gcc-1.40/gcc.info-7 | 970 ++++ gcc-1.40/gcc.info-8 | 1152 +++++ gcc-1.40/gcc.info-9 | 1066 ++++ gcc-1.40/gcc.texinfo | 10363 +++++++++++++++++++++++++++++++++++++++ gcc-1.40/gdbfiles.h | 15 + gcc-1.40/gencodes.c | 154 + gcc-1.40/genconfig.c | 267 + gcc-1.40/genemit.c | 480 ++ gcc-1.40/genextract.c | 348 ++ gcc-1.40/genflags.c | 138 + gcc-1.40/genoutput.c | 786 +++ gcc-1.40/genpeep.c | 437 ++ gcc-1.40/genrecog.c | 1095 +++++ gcc-1.40/global-alloc.c | 1091 +++++ gcc-1.40/gnulib.c | 465 ++ gcc-1.40/gnulib2.c | 922 ++++ gcc-1.40/gstab.h | 16 + gcc-1.40/gstdarg.h | 44 + gcc-1.40/gvarargs.h | 68 + gcc-1.40/hard-params.c | 1734 +++++++ gcc-1.40/hard-reg-set.h | 229 + gcc-1.40/input.h | 22 + gcc-1.40/integrate.c | 2049 ++++++++ gcc-1.40/jump.c | 1618 ++++++ gcc-1.40/limits.h | 43 + gcc-1.40/local-alloc.c | 1227 +++++ gcc-1.40/loop.c | 5436 ++++++++++++++++++++ gcc-1.40/machmode.def | 120 + gcc-1.40/make-cc1.com | 153 + gcc-1.40/make-cccp.com | 48 + gcc-1.40/make.com | 5 + gcc-1.40/masm386.c | 225 + gcc-1.40/math-68881.h | 475 ++ gcc-1.40/move-if-change | 15 + gcc-1.40/obstack.c | 326 ++ gcc-1.40/obstack.h | 410 ++ gcc-1.40/optabs.c | 2228 +++++++++ gcc-1.40/output.h | 95 + gcc-1.40/print-self.c | 1 + gcc-1.40/print-self1.c | 1 + gcc-1.40/print-tree.c | 510 ++ gcc-1.40/proto.h | 4 + gcc-1.40/real.h | 94 + gcc-1.40/recog.c | 1106 +++++ gcc-1.40/recog.h | 78 + gcc-1.40/regclass.c | 905 ++++ gcc-1.40/regs.h | 146 + gcc-1.40/reload.c | 3291 +++++++++++++ gcc-1.40/reload.h | 69 + gcc-1.40/reload1.c | 3524 +++++++++++++ gcc-1.40/rtl.c | 811 +++ gcc-1.40/rtl.def | 542 ++ gcc-1.40/rtl.h | 544 ++ gcc-1.40/rtlanal.c | 681 +++ gcc-1.40/sdbout.c | 1102 +++++ gcc-1.40/stab.def | 115 + gcc-1.40/stddef.h | 58 + gcc-1.40/stmt.c | 5076 +++++++++++++++++++ gcc-1.40/stor-layout.c | 1091 +++++ gcc-1.40/stupid.c | 528 ++ gcc-1.40/symout.c | 1267 +++++ gcc-1.40/symseg.h | 350 ++ gcc-1.40/texinfo.tex | 2357 +++++++++ gcc-1.40/toplev.c | 2072 ++++++++ gcc-1.40/tree.c | 2223 +++++++++ gcc-1.40/tree.def | 619 +++ gcc-1.40/tree.h | 930 ++++ gcc-1.40/typeclass.h | 14 + gcc-1.40/va-i860.h | 53 + gcc-1.40/va-mips.h | 30 + gcc-1.40/va-pyr.h | 100 + gcc-1.40/va-sparc.h | 35 + gcc-1.40/va-spur.h | 45 + gcc-1.40/varasm.c | 2030 ++++++++ gcc-1.40/version.c | 1 + 273 files changed, 225218 insertions(+) create mode 100644 gcc-1.40/.dbxinit create mode 100644 gcc-1.40/.gdbinit create mode 100644 gcc-1.40/COPYING create mode 100644 gcc-1.40/ChangeLog create mode 100644 gcc-1.40/INSTALL create mode 100644 gcc-1.40/Makefile create mode 100644 gcc-1.40/OChangeLog create mode 100644 gcc-1.40/PROBLEMS create mode 100644 gcc-1.40/PROJECTS create mode 100644 gcc-1.40/README create mode 100644 gcc-1.40/README-ALTOS create mode 100644 gcc-1.40/README-NS32K create mode 100644 gcc-1.40/README-VMS create mode 100644 gcc-1.40/README-X11 create mode 100644 gcc-1.40/SERVICE create mode 100644 gcc-1.40/TAGS create mode 100644 gcc-1.40/alloca.c create mode 100644 gcc-1.40/assert.h create mode 100644 gcc-1.40/basic-block.h create mode 100644 gcc-1.40/c-convert.c create mode 100644 gcc-1.40/c-decl.c create mode 100644 gcc-1.40/c-parse.gperf create mode 100644 gcc-1.40/c-parse.h create mode 100644 gcc-1.40/c-parse.output create mode 100644 gcc-1.40/c-parse.tab.c create mode 100644 gcc-1.40/c-parse.y create mode 100644 gcc-1.40/c-tree.h create mode 100644 gcc-1.40/c-typeck.c create mode 100644 gcc-1.40/caller-save.c create mode 100644 gcc-1.40/cccp.c create mode 100644 gcc-1.40/cexp.c create mode 100644 gcc-1.40/cexp.y create mode 100644 gcc-1.40/combine.c create mode 100644 gcc-1.40/conditions.h create mode 100644 gcc-1.40/config-gcc.com create mode 100755 gcc-1.40/config.gcc create mode 100644 gcc-1.40/config/alliant.md create mode 100644 gcc-1.40/config/convex.md create mode 100644 gcc-1.40/config/i386.md create mode 100644 gcc-1.40/config/i860.md create mode 100644 gcc-1.40/config/m68k.md create mode 100644 gcc-1.40/config/m88k.md create mode 100644 gcc-1.40/config/mips.md create mode 100644 gcc-1.40/config/ns32k.md create mode 100644 gcc-1.40/config/out-alliant.c create mode 100644 gcc-1.40/config/out-convex.c create mode 100644 gcc-1.40/config/out-i386.c create mode 100644 gcc-1.40/config/out-i860.c create mode 100644 gcc-1.40/config/out-m68k.c create mode 100644 gcc-1.40/config/out-m88k.c create mode 100644 gcc-1.40/config/out-mips.c create mode 100644 gcc-1.40/config/out-ns32k.c create mode 100644 gcc-1.40/config/out-pyr.c create mode 100644 gcc-1.40/config/out-sparc.c create mode 100644 gcc-1.40/config/out-spur.c create mode 100644 gcc-1.40/config/out-tahoe.c create mode 100644 gcc-1.40/config/out-vax.c create mode 100644 gcc-1.40/config/pyr.md create mode 100644 gcc-1.40/config/sparc.md create mode 100644 gcc-1.40/config/spur.md create mode 100644 gcc-1.40/config/tahoe.md create mode 100644 gcc-1.40/config/tm-3b1.h create mode 100644 gcc-1.40/config/tm-3b1g.h create mode 100644 gcc-1.40/config/tm-aix386.h create mode 100644 gcc-1.40/config/tm-alliant.h create mode 100644 gcc-1.40/config/tm-altos3068.h create mode 100644 gcc-1.40/config/tm-apollo68.h create mode 100644 gcc-1.40/config/tm-att386.h create mode 100644 gcc-1.40/config/tm-bsd386.h create mode 100644 gcc-1.40/config/tm-compaq.h create mode 100644 gcc-1.40/config/tm-conv1os7.h create mode 100644 gcc-1.40/config/tm-conv2os7.h create mode 100644 gcc-1.40/config/tm-convex.h create mode 100644 gcc-1.40/config/tm-convex1.h create mode 100644 gcc-1.40/config/tm-convex2.h create mode 100644 gcc-1.40/config/tm-decstatn.h create mode 100644 gcc-1.40/config/tm-delta68k.h create mode 100644 gcc-1.40/config/tm-encore.h create mode 100644 gcc-1.40/config/tm-genix.h create mode 100644 gcc-1.40/config/tm-harris.h create mode 100644 gcc-1.40/config/tm-hp9k2bsd.h create mode 100644 gcc-1.40/config/tm-hp9k310.h create mode 100644 gcc-1.40/config/tm-hp9k310g.h create mode 100644 gcc-1.40/config/tm-hp9k320.h create mode 100644 gcc-1.40/config/tm-hp9k320g.h create mode 100644 gcc-1.40/config/tm-hp9k3bsd.h create mode 100644 gcc-1.40/config/tm-i386.h create mode 100644 gcc-1.40/config/tm-i386esix.h create mode 100644 gcc-1.40/config/tm-i386gas.h create mode 100644 gcc-1.40/config/tm-i386isc.h create mode 100644 gcc-1.40/config/tm-i386sco.h create mode 100644 gcc-1.40/config/tm-i386v.h create mode 100644 gcc-1.40/config/tm-i386v4.h create mode 100644 gcc-1.40/config/tm-i386vgas.h create mode 100644 gcc-1.40/config/tm-i860.h create mode 100644 gcc-1.40/config/tm-i860bsdg.h create mode 100644 gcc-1.40/config/tm-i860g.h create mode 100644 gcc-1.40/config/tm-iris.h create mode 100644 gcc-1.40/config/tm-isi68-nfp.h create mode 100644 gcc-1.40/config/tm-isi68.h create mode 100644 gcc-1.40/config/tm-m68k.h create mode 100644 gcc-1.40/config/tm-m88k.h create mode 100644 gcc-1.40/config/tm-mips-bsd.h create mode 100644 gcc-1.40/config/tm-mips-news.h create mode 100644 gcc-1.40/config/tm-mips-sysv.h create mode 100644 gcc-1.40/config/tm-mips.h create mode 100644 gcc-1.40/config/tm-news.h create mode 100644 gcc-1.40/config/tm-newsgas.h create mode 100644 gcc-1.40/config/tm-next.h create mode 100644 gcc-1.40/config/tm-ns32k.h create mode 100644 gcc-1.40/config/tm-pyr.h create mode 100644 gcc-1.40/config/tm-seq386.h create mode 100644 gcc-1.40/config/tm-sequent.h create mode 100644 gcc-1.40/config/tm-sparc.h create mode 100644 gcc-1.40/config/tm-spur.h create mode 100644 gcc-1.40/config/tm-sun2.h create mode 100644 gcc-1.40/config/tm-sun2os4.h create mode 100644 gcc-1.40/config/tm-sun3-nfp.h create mode 100644 gcc-1.40/config/tm-sun3.h create mode 100644 gcc-1.40/config/tm-sun386.h create mode 100644 gcc-1.40/config/tm-sun386i.h create mode 100644 gcc-1.40/config/tm-sun3mach.h create mode 100644 gcc-1.40/config/tm-sun3os3.h create mode 100644 gcc-1.40/config/tm-sun3os3nf.h create mode 100644 gcc-1.40/config/tm-sun4os3.h create mode 100644 gcc-1.40/config/tm-tahoe.h create mode 100644 gcc-1.40/config/tm-tower-as.h create mode 100644 gcc-1.40/config/tm-tower.h create mode 100644 gcc-1.40/config/tm-ultrix.h create mode 100644 gcc-1.40/config/tm-vax.h create mode 100644 gcc-1.40/config/tm-vaxv.h create mode 100644 gcc-1.40/config/tm-vms.h create mode 100644 gcc-1.40/config/vax.md create mode 100644 gcc-1.40/config/xm-3b1.h create mode 100644 gcc-1.40/config/xm-aix386.h create mode 100644 gcc-1.40/config/xm-alliant.h create mode 100644 gcc-1.40/config/xm-altos3068.h create mode 100644 gcc-1.40/config/xm-convex.h create mode 100644 gcc-1.40/config/xm-delta68k.h create mode 100644 gcc-1.40/config/xm-genix.h create mode 100644 gcc-1.40/config/xm-hp9k320.h create mode 100644 gcc-1.40/config/xm-i386.h create mode 100644 gcc-1.40/config/xm-i386v.h create mode 100644 gcc-1.40/config/xm-i860.h create mode 100644 gcc-1.40/config/xm-iris.h create mode 100644 gcc-1.40/config/xm-m68k.h create mode 100644 gcc-1.40/config/xm-m88k.h create mode 100644 gcc-1.40/config/xm-mips.h create mode 100644 gcc-1.40/config/xm-ns32k.h create mode 100644 gcc-1.40/config/xm-pyr.h create mode 100644 gcc-1.40/config/xm-sparc.h create mode 100644 gcc-1.40/config/xm-spur.h create mode 100644 gcc-1.40/config/xm-sun386i.h create mode 100644 gcc-1.40/config/xm-tahoe.h create mode 100644 gcc-1.40/config/xm-tower.h create mode 100644 gcc-1.40/config/xm-umips.h create mode 100644 gcc-1.40/config/xm-vax.h create mode 100644 gcc-1.40/config/xm-vaxv.h create mode 100644 gcc-1.40/config/xm-vms.h create mode 100644 gcc-1.40/cpp.aux create mode 100644 gcc-1.40/cpp.cps create mode 100644 gcc-1.40/cpp.dvi create mode 100644 gcc-1.40/cpp.fns create mode 100644 gcc-1.40/cpp.info create mode 100644 gcc-1.40/cpp.info-1 create mode 100644 gcc-1.40/cpp.info-2 create mode 100644 gcc-1.40/cpp.texinfo create mode 100644 gcc-1.40/cse.c create mode 100644 gcc-1.40/dbranch.c create mode 100644 gcc-1.40/dbxout.c create mode 100755 gcc-1.40/ecoff-cmp create mode 100644 gcc-1.40/emit-rtl.c create mode 100644 gcc-1.40/explow.c create mode 100644 gcc-1.40/expmed.c create mode 100644 gcc-1.40/expr.c create mode 100644 gcc-1.40/expr.h create mode 100644 gcc-1.40/final.c create mode 100644 gcc-1.40/fixcpp create mode 100755 gcc-1.40/fixincludes create mode 100644 gcc-1.40/fixincludes-V4 create mode 100755 gcc-1.40/fixincludes.old create mode 100644 gcc-1.40/flags.h create mode 100644 gcc-1.40/flow.c create mode 100644 gcc-1.40/fold-const.c create mode 100644 gcc-1.40/gcc.1 create mode 100644 gcc-1.40/gcc.aux create mode 100644 gcc-1.40/gcc.c create mode 100644 gcc-1.40/gcc.dvi create mode 100644 gcc-1.40/gcc.hlp create mode 100644 gcc-1.40/gcc.info create mode 100644 gcc-1.40/gcc.info-1 create mode 100644 gcc-1.40/gcc.info-10 create mode 100644 gcc-1.40/gcc.info-11 create mode 100644 gcc-1.40/gcc.info-2 create mode 100644 gcc-1.40/gcc.info-3 create mode 100644 gcc-1.40/gcc.info-4 create mode 100644 gcc-1.40/gcc.info-5 create mode 100644 gcc-1.40/gcc.info-6 create mode 100644 gcc-1.40/gcc.info-7 create mode 100644 gcc-1.40/gcc.info-8 create mode 100644 gcc-1.40/gcc.info-9 create mode 100644 gcc-1.40/gcc.texinfo create mode 100644 gcc-1.40/gdbfiles.h create mode 100644 gcc-1.40/gencodes.c create mode 100644 gcc-1.40/genconfig.c create mode 100644 gcc-1.40/genemit.c create mode 100644 gcc-1.40/genextract.c create mode 100644 gcc-1.40/genflags.c create mode 100644 gcc-1.40/genoutput.c create mode 100644 gcc-1.40/genpeep.c create mode 100644 gcc-1.40/genrecog.c create mode 100644 gcc-1.40/global-alloc.c create mode 100644 gcc-1.40/gnulib.c create mode 100644 gcc-1.40/gnulib2.c create mode 100644 gcc-1.40/gstab.h create mode 100644 gcc-1.40/gstdarg.h create mode 100644 gcc-1.40/gvarargs.h create mode 100644 gcc-1.40/hard-params.c create mode 100644 gcc-1.40/hard-reg-set.h create mode 100644 gcc-1.40/input.h create mode 100644 gcc-1.40/integrate.c create mode 100644 gcc-1.40/jump.c create mode 100644 gcc-1.40/limits.h create mode 100644 gcc-1.40/local-alloc.c create mode 100644 gcc-1.40/loop.c create mode 100644 gcc-1.40/machmode.def create mode 100644 gcc-1.40/make-cc1.com create mode 100644 gcc-1.40/make-cccp.com create mode 100644 gcc-1.40/make.com create mode 100644 gcc-1.40/masm386.c create mode 100644 gcc-1.40/math-68881.h create mode 100755 gcc-1.40/move-if-change create mode 100644 gcc-1.40/obstack.c create mode 100644 gcc-1.40/obstack.h create mode 100644 gcc-1.40/optabs.c create mode 100644 gcc-1.40/output.h create mode 100644 gcc-1.40/print-self.c create mode 100644 gcc-1.40/print-self1.c create mode 100644 gcc-1.40/print-tree.c create mode 100644 gcc-1.40/proto.h create mode 100644 gcc-1.40/real.h create mode 100644 gcc-1.40/recog.c create mode 100644 gcc-1.40/recog.h create mode 100644 gcc-1.40/regclass.c create mode 100644 gcc-1.40/regs.h create mode 100644 gcc-1.40/reload.c create mode 100644 gcc-1.40/reload.h create mode 100644 gcc-1.40/reload1.c create mode 100644 gcc-1.40/rtl.c create mode 100644 gcc-1.40/rtl.def create mode 100644 gcc-1.40/rtl.h create mode 100644 gcc-1.40/rtlanal.c create mode 100644 gcc-1.40/sdbout.c create mode 100644 gcc-1.40/stab.def create mode 100644 gcc-1.40/stddef.h create mode 100644 gcc-1.40/stmt.c create mode 100644 gcc-1.40/stor-layout.c create mode 100644 gcc-1.40/stupid.c create mode 100644 gcc-1.40/symout.c create mode 100644 gcc-1.40/symseg.h create mode 100644 gcc-1.40/texinfo.tex create mode 100644 gcc-1.40/toplev.c create mode 100644 gcc-1.40/tree.c create mode 100644 gcc-1.40/tree.def create mode 100644 gcc-1.40/tree.h create mode 100644 gcc-1.40/typeclass.h create mode 100644 gcc-1.40/va-i860.h create mode 100644 gcc-1.40/va-mips.h create mode 100644 gcc-1.40/va-pyr.h create mode 100644 gcc-1.40/va-sparc.h create mode 100644 gcc-1.40/va-spur.h create mode 100644 gcc-1.40/varasm.c create mode 100644 gcc-1.40/version.c diff --git a/gcc-1.40/.dbxinit b/gcc-1.40/.dbxinit new file mode 100644 index 0000000..5018f99 --- /dev/null +++ b/gcc-1.40/.dbxinit @@ -0,0 +1,10 @@ +alias l list +alias p print +alias c cont +alias s step +alias n next +alias bt where +alias r run +alias f file +alias si stepi +alias q quit diff --git a/gcc-1.40/.gdbinit b/gcc-1.40/.gdbinit new file mode 100644 index 0000000..ca93679 --- /dev/null +++ b/gcc-1.40/.gdbinit @@ -0,0 +1,58 @@ +define pr +set debug_rtx ($) +end + +document pr +Print the full structure of the rtx that is $. +Works only when an inferior is executing. +end + +define pt +set debug_tree ($) +end + +document pt +Print the full structure of the tree that is $. +Works only when an inferior is executing. +end + +define ptc +output (enum tree_code) $.common.code +echo \n +end + +document ptc +Print the tree-code of the tree node that is $. +end + +define pdn +output $.decl.name->identifier.pointer +echo \n +end + +document pdn +Print the name of the decl-node that is $. +end + +define prc +output (enum rtx_code) $.code +echo \ ( +output $.mode +echo )\n +end + +document prc +Print the rtx-code and machine mode of the rtx that is $. +end + +define pi +print $.fld[0].rtx@7 +end + +document pi +Print the fields of an instruction that is $. +end + +# Don't let abort actually run, as it will make +# stdio stop working and therefore the `pr' command below as well. +b abort diff --git a/gcc-1.40/COPYING b/gcc-1.40/COPYING new file mode 100644 index 0000000..9a17037 --- /dev/null +++ b/gcc-1.40/COPYING @@ -0,0 +1,249 @@ + + GNU GENERAL PUBLIC LICENSE + Version 1, February 1989 + + Copyright (C) 1989 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The license agreements of most software companies try to keep users +at the mercy of those companies. By contrast, our 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. The +General Public License applies to the Free Software Foundation's +software and to any other program whose authors commit to using it. +You can use it for your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Specifically, the General Public License is designed to make +sure that you have the freedom to give away or sell copies of free +software, 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 a 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 tell them 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. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement 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 work containing the +Program or a portion of it, either verbatim or with modifications. Each +licensee is addressed as "you". + + 1. 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 +General Public License and to the absence of any warranty; and give any +other recipients of the Program a copy of this General Public License +along with the Program. You may charge a fee for the physical act of +transferring a copy. + + 2. You may modify your copy or copies of the Program or any portion of +it, and copy and distribute such modifications under the terms of Paragraph +1 above, provided that you also do the following: + + a) cause the modified files to carry prominent notices stating that + you changed the files and the date of any change; and + + b) cause the whole of any work that you distribute or publish, that + in whole or in part contains the Program or any part thereof, either + with or without modifications, to be licensed at no charge to all + third parties under the terms of this General Public License (except + that you may choose to grant warranty protection to some or all + third parties, at your option). + + c) If the modified program normally reads commands interactively when + run, you must cause it, when started running for such interactive use + in the simplest and most usual 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 General + Public License. + + d) 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. + +Mere aggregation of another independent work with the Program (or its +derivative) on a volume of a storage or distribution medium does not bring +the other work under the scope of these terms. + + 3. You may copy and distribute the Program (or a portion or derivative of +it, under Paragraph 2) in object code or executable form under the terms of +Paragraphs 1 and 2 above provided that you also do one of the following: + + a) accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of + Paragraphs 1 and 2 above; or, + + b) accompany it with a written offer, valid for at least three + years, to give any third party free (except for a nominal charge + for the cost of distribution) a complete machine-readable copy of the + corresponding source code, to be distributed under the terms of + Paragraphs 1 and 2 above; or, + + c) accompany it with the information you received as to where the + corresponding source code may be obtained. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form alone.) + +Source code for a work means the preferred form of the work for making +modifications to it. For an executable file, complete source code means +all the source code for all modules it contains; but, as a special +exception, it need not include source code for modules which are standard +libraries that accompany the operating system on which the executable +file runs, or for standard header files or definitions files that +accompany that operating system. + + 4. You may not copy, modify, sublicense, distribute or transfer the +Program except as expressly provided under this General Public License. +Any attempt otherwise to copy, modify, sublicense, distribute or transfer +the Program is void, and will automatically terminate your rights to use +the Program under this License. However, parties who have received +copies, or rights to use copies, from you under this General Public +License will not have their licenses terminated so long as such parties +remain in full compliance. + + 5. By copying, distributing or modifying 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. + + 6. 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. + + 7. 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 the 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 +the license, you may choose any version ever published by the Free Software +Foundation. + + 8. 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. + + NO WARRANTY + + 9. 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. + + 10. 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 OF TERMS AND CONDITIONS + + Appendix: 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 humanity, 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. + + + Copyright (C) 19yy + + 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. + + 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. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19xx name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the +appropriate parts of the General Public License. Of course, the +commands you use may be called something other than `show w' and `show +c'; they could even be mouse-clicks or menu items--whatever suits your +program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + program `Gnomovision' (a program to direct compilers to make passes + at assemblers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/gcc-1.40/ChangeLog b/gcc-1.40/ChangeLog new file mode 100644 index 0000000..c0ce575 --- /dev/null +++ b/gcc-1.40/ChangeLog @@ -0,0 +1,7378 @@ +Sat Jun 1 01:10:32 1991 Richard Stallman (rms at mole.gnu.ai.mit.edu) + + * Version 1.40 released. + + * i386.md (divmodsi4, udivmodsi4): Add separate define_expands + to force duplicated args into registers. + +Thu May 30 00:32:18 1991 Richard Stallman (rms at mole.gnu.ai.mit.edu) + + * expr.c (expand_expr): + Don't lose volatility of fields in COMPONENT_REF. + + * fixincludes (stdtypes.h): Handle wchar_t like the other types. + +Tue May 28 12:34:24 1991 Richard Stallman (rms at mole.gnu.ai.mit.edu) + + * cse.c (canon_hash): Don't hash hard regs if SMALL_REGISTER_CLASSES. + * tm-i386.h (SMALL_REGISTER_CLASSES): Define it. + + * expr.c (store_one_arg): Set used after calling push_rounding. + + * tm-decstatn.h (CPP_PREDEFINES): Add __ versions of macros. + + * tm-apollo68.h (LIB_SPEC): Renamed from LINK_SPEC. + +Sun May 26 00:52:32 1991 Richard Stallman (rms at mole.gnu.ai.mit.edu) + + * cse.c (refers_to_mem_p): Handle constants as addresses. + +Thu May 23 12:35:25 1991 John Vasta (vasta at apollo.hp.com) + + * tm-apollo68.h (STARTFILE_SPEC): Remove unneeded + conditional and use correct file for ANSI mode. + (LIB_SPEC): Deleted. + (LINK_SPEC): Specify -e switch. + +Wed May 22 14:35:13 1991 Richard Stallman (rms at mole.gnu.ai.mit.edu) + + * tm-i386isc.h (STARTFILE_SPEC): Add missing %s. + + * tm-vaxv.h (ASM_OUTPUT_LOCAL): Use data_section. + +Mon May 20 12:38:39 1991 Richard Stallman (rms at mole.gnu.ai.mit.edu) + + * Makefile (float.h): Pass certain vars down to nested make. + + * hard-params.c [NO_LONG_DOUBLE]: Inhibit handling of long double. + + * m68k.md (trunc*): Clear cc if use wider insn. + +Sun May 19 14:45:46 1991 Ron Guilmette (rfg at ncd.com) + + * Makefile.in (clean): Delete stage1...stage4. + (realclean): Delete cexp.output. + + * fixincludes: Handle BSD43__IO* and BSD43_CTRL like IO* and CTRL. + +Sun May 19 15:00:05 1991 Richard Stallman (rms at mole.gnu.ai.mit.edu) + + * fixincludes (machine/cpu.h): + Create in proper dir. Fix mips/cpu.h too. + +Fri May 17 15:41:22 1991 James Van Artsdalen (james at bigtex.cactus.org) + + * tm-i386v4.h (ASM_OUTPUT_COMMON): Don't attempt alignment on a + three byte boundary. + +Thu May 16 12:46:37 1991 Richard Stallman (rms at mole.gnu.ai.mit.edu) + + * expr.c (convert_to_mode): Don't use gen_lowpart on most constants. + +Mon May 13 23:42:03 1991 Richard Stallman (rms at mole.gnu.ai.mit.edu) + + * expmed.c (store_bit_field, extract_bit_field): + Temporarily set volatile_ok when checking predicates. + + * explow.c (force_not_mem): Do nothing for BLKmode. + + * tree.c (real_value_from_int_cst): Add parens to fix misparsings. + +Sun May 12 22:39:42 1991 Richard Stallman (rms at mole.gnu.ai.mit.edu) + + * tree.c (real_value_from_int_cst): Make MASK unsigned. + +Wed May 8 11:19:32 1991 Richard Stallman (rms at mole.gnu.ai.mit.edu) + + * rtl.c (reg_note_name): Put in REG_UNSET. Remove dead ones. + + * tree.c (real_value_from_int_cst): Avoid converting unsigned to float. + + * stor-layout.c (round_size): Cast to int when comparing modes. + + * tm-ultrix.h (CPP_PREDEFINES): Define __vax. + +Mon May 6 13:29:48 1991 Richard Stallman (rms at mole.gnu.ai.mit.edu) + + * out-i386.c (fp_top_dead_p1): Look past any number of labels. + + * tm-aix386.h (ASM_FILE_START): Discard directories from .file arg. + +Sat May 4 14:36:26 1991 Richard Stallman (rms at mole.gnu.ai.mit.edu) + + * tm-hp9k320.h (CPP_SPEC): Always define _HPUX_SOURCE. + Move other standard predefs with underscores here. + (CPP_PREDEFINES): Standard predefs moved from here. + + * hard-params.c (EPROP): Avoid comparing a with out if bad is 1. + +Thu May 2 14:43:48 1991 Richard Stallman (rms at mole.gnu.ai.mit.edu) + + * math-68881.h (pow): Negate x if negative when taking log. + + * c-decl.c (finish_enum): Don't store the enum as the type of any of + its enumerator values. + +Wed May 1 15:02:15 1991 Richard Stallman (rms at mole.gnu.ai.mit.edu) + + * c-decl.c (finish_enum): Rewrite handling of min and max values. + Rewrite handling of flag_short enums. + * stor-layout.c (round_size): New subroutine. + + * out-i386.c (fp_top_dead_p1): Use mentions_fp_top to check dest. + +Tue Apr 30 14:41:58 1991 Richard Stallman (rms at mole.gnu.ai.mit.edu) + + * expr.c (expand_call): Copy value to mem via a pseudo. + + * tm-decstatn.h (CPP_PREDEFINES): Define __mips and __LANGUAGE_C. + + * fixincludes (machine/cpu.h): Delete superfluous `static'. + + * Makefile (maketest): Don't stop on error in `if' statement. + +Mon Apr 29 12:29:16 1991 (Eric Youngdale at youngdale@v6550c.nrl.navy.mil) + + * cccp.c (hack_vms_include_specification): Modified conversion of + unix filenames to VMS filenames, if no VMS device or directory is + present and a unix style directory name is present. In this case, use + the first unix directory name as the VMS device spec. This is only + used in '#include <...>' type includes, when the include file has + not been found in the standard locations. + +Mon Apr 29 22:18:47 1991 James Van Artsdalen (james at bigtex.cactus.org) + + * tm-att386.h (ASM_OUTPUT_LOCAL): Align static local variables. + +Mon Apr 29 13:50:55 1991 Richard Stallman (rms at mole.gnu.ai.mit.edu) + + * reload1.c (emit_reload_insns): When changing the mode, + make a REG, not a SUBREG. + + * out-i386.c (print_operand): For non-'c', print prefix for LABEL_REF. + + * c-decl.c (pushdecl): Just a warning for type of extern not global. + +Wed Apr 17 12:44:16 1991 Richard Stallman (rms at apple-gunkies) + + * stmt.c (use_variable, use_variable_after): Handleg subregs. + +Sat Apr 13 10:10:28 1991 Eric Youngdale (youngdale@v6550c.nrl.navy.mil) + + * cccp.c (hack_vms_include_specification) Made parsing more + intelligent when confronted with something like: + "SYS$SYSROOT:[SYSLIB.]/foo.h". Previously this routine would + return a file specification that had a syntax error. This example + will now parsed to "SYS$SYSROOT:[SYSLIB]foo.h". + +Fri Apr 12 02:37:07 1991 Richard Stallman (rms at mole.gnu.ai.mit.edu) + + * expmed.c (store_bit_field): Don't die if VALUE is constant + for a field bigger than a word. + + * tm-sparc.h (FUNCTION_BLOCK_PROFILER): Must set %o0 to the address + LPBX0 by adding in the low part of the address before calling + ___bb_init_func. + + * cccp.c (skip_to_end_of_comment): Handle warn_comment. + + * out-m68k.c (output_move_double): Really test HOST_WORDS_BIG_ENDIAN. + + * config.gcc (i386-isc): New target. + * tm-i386isc.h: New file. + + * m68k.md (dbra patterns): Use `=' in constraint of op 0. + +Sat Mar 30 15:16:16 1991 Richard Stallman (rms at mole.gnu.ai.mit.edu) + + * ns32k.md (andcbhi3, andcbqi3): Constraint shouldn't say commutative. + + * tm-mips.h, tm-sparc.h, tm-spur.h (CONST_DOUBLE_OK_FOR_LETTER_P): + Use CONST_DOUBLE_LOW and CONST_DOUBLE_HIGH. + +Fri Mar 29 16:17:59 1991 Richard Stallman (rms at mole.gnu.ai.mit.edu) + + * tm-hp9k2bsd.h: New file. + * config.h (hp9k200-bsd): New target. + +Thu Mar 28 16:31:50 1991 Richard Stallman (rms at mole.gnu.ai.mit.edu) + + * tm-vax.h (CHECK_FLOAT_VALUE): Change float max to ...444e+38. + +Wed Mar 27 19:57:33 1991 Richard Stallman (rms at mole.gnu.ai.mit.edu) + + * integrate.c (access_parm_map): Use /, not %, in setting WORD. + +Sun Mar 24 23:47:19 1991 Richard Stallman (rms at mole.gnu.ai.mit.edu) + + * gcc.c (store_arg): Use xrealloc. + (xrealloc, xmalloc): Change error message. + +Sat Mar 23 03:42:20 1991 Richard Stallman (rms at mole.gnu.ai.mit.edu) + + * gnulib.c [GNULIB_NEEDS_DOUBLE]: Override FLOAT_ARG_TYPE, FLOATIFY. + +Fri Mar 22 00:46:42 1991 Richard Stallman (rms at mole.gnu.ai.mit.edu) + + * integrate.c (frame_pointer_sum_p): New function. + (copy_rtx_and_substitute): Use that. + + * cccp.c (bzero, etc.): Don't test for BSD--it's never defined. + +Tue Mar 19 21:25:52 1991 Richard Stallman (rms at mole.gnu.ai.mit.edu) + + * gstab.h: Renamed from stab.h. + * dbxout.c, symout.c, final.c: Include under that name. + + * stddef.h (wchar_t): New typedef. + +Sun Mar 17 21:01:56 1991 Richard Stallman (rms@mole.ai.mit.edu) + + * fixincludes (dnetdb.h): Fix missing semi in nodeent. + (rusers.h): Code to fix this file was duplicated. + +Sat Mar 16 15:25:56 1991 Richard Stallman (rms@mole.ai.mit.edu) + + * toplev.c (compile_file): Write out all static consts that are used. + +Thu Mar 14 16:56:03 1991 Richard Stallman (rms at mole.ai.mit.edu) + + * tm-att386.h (ASM_OUTPUT_SKIP): Delete duplicate #define. + + * out-sparc.c (output_block_move): + Conditionalize templates at end on NO_UNDERSCORES. + +Tue Mar 12 23:48:11 1991 Richard Stallman (rms at mole.ai.mit.edu) + + * fixincludes: Quote the # in an echo. + +Sun Mar 10 20:11:04 1991 Richard Stallman (rms at mole.ai.mit.edu) + + * expr.c (emit_library_call): Support GNULIB_NEEDS_DOUBLE. + * tm-i860.h (GNULIB_NEEDS_DOUBLE): Define it. + +Sun Mar 3 15:13:50 1991 Michael Meissner (meissner at osf.org) + + * out-mips.c (function_arg_partial_nregs): Fix passing two + structures, each of which contains two doubles to a function which + returns a structure -- the problem was caused when the 1.37.1 code + was modified to have two fields for the FUNCTION_ARG routines, + arg_number which is the number of arguments, and arg_words which is + the total number of words passed, instead of the old arg_number + which counted the words. The function_arg_partial_nregs routine was + returning -1 for the second call. In 1.37.1, the macro + FUNCTION_ARG_PARTIAL_NREGS was only called one time, if it returned + non-zero. This no longer seems the case for 1.39. + +Sun Mar 10 19:06:36 1991 Richard Stallman (rms at mole.ai.mit.edu) + + * tm-harris.h (ASM_FILE_START): Output a .file. + + * tm-mips.h (TARGET_MEM_FUNCTIONS): Define on certain systems. + +Fri Mar 8 15:51:15 1991 Richard Stallman (rms at mole.ai.mit.edu) + + * gcc.c (delete_temp_files): Delete only ordinary files. + +Thu Mar 7 17:51:11 1991 Richard Stallman (rms at mole.ai.mit.edu) + + * c-typeck.c (build_array_ref): Notice if array expression + is const or volatile. + +Tue Mar 5 14:21:57 1991 Richard Stallman (rms at mole.ai.mit.edu) + + * c-decl.c (store_parm_decls): If -traditional, + allow unsigned int in prototype in place of int. + + * stmt.c (fixup_gotos): Handle jumping to end of rtl. + + * tm-mips-news.h (DECSTATION): Definition deleted. + (MIPS_NEWS): Define it. + + * config.gcc (i860-gas): New target. + * tm-i860g.h: New file. + +Mon Mar 4 00:39:11 1991 Richard Stallman (rms at mole.ai.mit.edu) + + * fixincludes: Fix typos handling size_t and ptrdiff_t. + + * out-mips.c: Include sys/types.h. + +Sun Mar 3 01:11:46 1991 Richard Stallman (rms at mole.ai.mit.edu) + + * cccp.c (include_defaults, cplusplus_include_defaults): + Use CC_INCLUDE_DIR. + (CC_INCLUDE_DIR): Define by default as /use/include. + * tm-mips.h (CC_INCLUDE_DIR): Define, if MIPS_BSD43. + (CPP_SPEC): Don't do -I to handle -ZSYSV, -ZBSD43. + +Sat Mar 2 16:22:59 1991 Richard Stallman (rms at mole.ai.mit.edu) + + * expr.c (expand_call): Use argpos, not i, where appropriate. + +Wed Feb 27 15:46:54 1991 Richard Stallman (rms at mole.ai.mit.edu) + + * gnulib.c (FLOAT_ARG_TYPE, FLOATIFY): New macros. + (__*sf*): Use them for `float' args. + + * stmt.c (fixup_gotos): Check that jump into bindings + really comes from before the start of the bindings. + Use TREE_REGDECL to indicate error message printed. + +Tue Feb 26 15:46:35 1991 Richard Stallman (rms at mole.ai.mit.edu) + + * c-decl.c (grokdeclarator): Check for errors before warnings. + +Mon Feb 25 20:46:43 1991 Richard Stallman (rms at mole.ai.mit.edu) + + * sdbout.c (SDB_NO_FORWARD_REFS): Renamed from MAYBE. + (plain_type_1): Don't call sdb_record_type_name if no forward refs. + + * integrate.c (expand_inline_function): Copy REG_USERVAR_P to new regs. + (copy_rtx_and_substitute): Likewise. + + * c-typeck.c (digest_init): Handle STRING_CST before same-type case. + + * make-cc1.com, make-cccp.com: Set default dir for batch use. + +Sun Feb 24 17:14:09 1991 Richard Stallman (rms at mole.ai.mit.edu) + + * out-sparc.c (output_fp_move_double): Typo choosing inc_reg. + If we use %g1, then put that into the memref. + + * loop.c (check_dbra_loop): Win if loop biv is used only for counting. + +Sat Feb 23 13:36:13 1991 Richard Stallman (rms at mole.ai.mit.edu) + + * sdbout.c (sdbout_one_type): Changed #ifndef MAYBE controlling + call to sdbout_field_types into #ifdef. It seems it was backwards. + + * c-decl.c (grokdeclarator): Error for `signed void', etc. + Warning for `signed my_int', and only if pedantic. + +Fri Feb 22 12:45:06 1991 Richard Stallman (rms at mole.ai.mit.edu) + + * tm-i386sco.h (STRUCT_RETURN_CALLER_POP): Define it. + + * stmt.c (expand_end_loop): Don't be fooled by notes at loop end. + +Thu Feb 21 21:34:12 1991 Richard Stallman (rms at mole.ai.mit.edu) + + * tm-sun2os4.h (LINK_SPEC): New macro. + * tm-sun386i.h (LINK_SPEC): Undef before redefining. + +Mon Feb 11 00:06:19 1991 Richard Stallman (rms at mole.ai.mit.edu) + + * Makefile (libg): Rule deleted. + (install): Don't create libg.a. + + * out-mips.c (mips_asm_file_start, make_temp_file): New functions. + * tm-mips.h (ASM_FILE_START): Use those functions. + + * gcc.c (do_spec_1): Handle %G. + (LIBG_SPEC): New macro. + (link_spec): Use %G. + * tm-mips.h (LIBG_SPEC): Define this as empty string. + +Sun Feb 10 23:03:45 1991 Richard Stallman (rms at mole.ai.mit.edu) + + * integrate.c (copy_parm_decls): Set TREE_INLINE before pushdecl. + +Sat Feb 9 16:31:28 1991 Richard Stallman (rms at mole.ai.mit.edu) + + * loop.c (eliminate_biv, can_eliminate_biv_p): + For compare insn and constant coeffs, check for overflow. + For variable coeffs, or variable endpoint, don't allow inequality. + +Fri Feb 8 18:04:43 1991 Richard Stallman (rms at mole.ai.mit.edu) + + * Makefile (libg): Put one (null) member in the library. + +Thu Feb 7 22:20:24 1991 Richard Stallman (rms at mole.ai.mit.edu) + + * tm-i386v4.h (ASM_OUTPUT_COMMON): Override; put alignment in output. + + * tm-news.h (FUNCTION_PROLOGUE): Correct syntax of link insn. + (PRINT_OPERAND_ADDRESS): Use period, not colon, before index reg width. + +Wed Feb 6 23:59:42 1991 Richard Stallman (rms at mole.ai.mit.edu) + + * config.gcc (mips-sysv): Use xm-umips.h. + * tm-mips-sysv.h (TARGET_MEM_FUNCTIONS): Define it. + +Tue Feb 5 00:45:58 1991 Richard Stallman (rms at mole.ai.mit.edu) + + * c-parse.y (combine_strings): Finish fixing wide strings. + + * reload1.c (possible_group_p): New subroutine. + (reload): Don't kill last group when looking for a non-group. + + * expmed.c (expand_divmod): If emit a cmp, must copy op0 to a reg. + + * expr.c (expand_builtin): For ffs, get mode from TREE_TYPE. + + * tm-att386.h (ASM_OUTPUT_SKIP): In text seg, make explicit zeros. + +Mon Feb 4 17:39:36 1991 Richard Stallman (rms at mole.ai.mit.edu) + + * c-typeck.c (digest_init): Error if init array with another array. + +Sun Feb 3 22:05:40 1991 Richard Stallman (rms at mole.ai.mit.edu) + + * m68k.md (extend QI to HI): Typo in clr insn. + + * c-parse.y (combine_strings): Subtract properly from LEN when copying. + (init_lex, yylex): max_wide is now measured in wide chars, not bytes. + +Sat Feb 2 12:32:41 1991 Richard Stallman (rms at mole.ai.mit.edu) + + * xm-m68k.h (HOST_WORDS_BIG_ENDIAN): Define it. + +Thu Jan 31 00:33:33 1991 Richard Stallman (rms at mole.ai.mit.edu) + + * tm-aix386.h (ASM_OUTPUT_LOCAL): Ok to use bss, since no shared libs. + (LINK_SPEC): Pass through all -K and -T options. + * xm-aix386.h (TRUE, FALSE): Undef if already def, to avoid warning. + + * c-decl.c (pushdecl): Don't make an extern global for -traditional + if it uses any local types. + + * tm-sun386i.h (PCC_BITFFIELD_TYPE_MATTERS): Use 1 as value. + (LINK_SPEC): Copy definition from xm-sun386i.h. + * xm-sun386i.h (LINK_SPEC): Definition deleted. + + * tm-hp9k320.h (STANDARD_STARTFILE_PREFIX): Once again always redefine. + +Wed Jan 30 16:27:14 1991 Richard Stallman (rms at mole.ai.mit.edu) + + * fixincludes (sys/stdtypes.h): Edit this to handle _SIZE_T, etc. + +Mon Jan 28 12:48:20 1991 Richard Stallman (rms at mole.ai.mit.edu) + + * loop.c (loop_reg_used_before_p): Scan explicitly, don't use luids. + +Thu Jan 24 18:15:08 1991 Richard Stallman (rms at mole.ai.mit.edu) + + * expr.c (expand_expr, case for ARRAY_REF): Use build_pointer_type. + + * loop.c (strength_reduce): Substitute regs inside some reg notes. + +Wed Jan 16 15:34:38 1991 Richard Stallman (rms at mole.ai.mit.edu) + + * Version 1.39 released. + + * config.gcc (i386-esix): New alternative. + * tm-i386esix.h: New file. + + * expr.c (expand_call): Don't put libcall notes on const function call + unless there is a suitable value-copying insn at the end. + + * config.gcc (delta68k): New alternative. + * tm-delta68k.h, xm-delta68k.h: New files. + +Tue Jan 15 01:37:21 1991 Richard Stallman (rms at mole.ai.mit.edu) + + * loop.c (scan_loop): Condition for movability was wrong. + A reg that isn't necessarily set may be unsafe + even if used only inside the loop. + However, a reg used only in the same basic block after the set is safe. + So is a reg that isn't a user-level variable. + + * combine.c (try_distrib): Don't push + thru negative-count shift. + * tm-vax.h (NEGATIVE_SHIFT_COUNT): Define to enable that change. + +Mon Jan 14 18:17:58 1991 Richard Stallman (rms at mole.ai.mit.edu) + + * stmt.c (assign_parms) [FIRST_PARM_CALLER_OFFSET]: + If that's negative, adjust first_parm_offset rather than + stack_args_size for size of structure value address. + (Kludge to make sparc work.) + + * fixincludes-V4: Handle #lint. + + * tm-i386sco.h (CPP_PREDEFINES): Get rid of the %-spec. + (CPP_SPEC): Override this; handle -scointl here. + +Sun Jan 13 23:06:25 1991 Richard Stallman (rms at mole.ai.mit.edu) + + * fixincludes (sys/file.h): Fix incorrect conditional in Ultrix. + +Sat Jan 12 14:25:02 1991 Richard Stallman (rms at mole.ai.mit.edu) + + * i386.md (movsf, movdf): Change constraints to ensure opt reload. + +Fri Jan 11 13:22:22 1991 Richard Stallman (rms at mole.ai.mit.edu) + + * tm-tower-as.h (ASM_OUTPUT_COMMON, ASM_OUTPUT_LOCAL, ASM_OUTPUT_SKIP): + Use %u. + (PUT_SDB_START_DIM): New macro. + (PUT_SDB_DIM): Deleted. + + * tm-next.h (LIB_SPEC, STARTFILE_SPEC): Don't support -p. + +Thu Jan 10 13:05:46 1991 Richard Stallman (rms at mole.ai.mit.edu) + + * tm-sun2.h (CC1_SPEC): Define to ignore -sun2 and -target. + (WORD_SWITCH_TAKES_ARG): Define to recognize -target. + (LIB_SPEC): Define; handle -a. + * tm-sun3os4.h: New file. + + * tm-mips-news.h (CPP_SPEC): Update include directory version. + (MACHINE_TYPE): Change this string. + + * tm-next.h (LIB_SPEC): Use -lsys_s, not -lc. + + * Makefile (gnulib): Depend on config.status. + +Mon Jan 7 15:03:53 1991 Richard Stallman (rms at mole.ai.mit.edu) + + * c-typeck.c (process_init_constructor): Error if values + provided for an array of empty elements. + Rename variable `error' to `error_flag'. + + * out-i386.c (function_epilogue) [STRUCT_RETURN_CALLER_POP]: + Don't pop struct value arg if -fpcc-struct-return. + * expr.c (expand_call) [STRUCT_RETURN_CALLER_POP]: + Change handling of structure_value_addr. + + * cse.c (cse_insn): In special case for (set REG0 REG1), + change any REG_EQUIV notes to REG_EQUAL. + +Sun Jan 6 13:51:59 1991 Richard Stallman (rms at mole.ai.mit.edu) + + * tm-sun386i.h (PCC_BITFIELD_TYPE_MATTERS): Define it. + + * out-i386.c (fp_top_dead_p1): Follow jump only if optimizing. + +Fri Jan 4 23:17:41 1991 Richard Stallman (rms at mole.ai.mit.edu) + + * tm-att386.h (ASM_OUTPUT_LOCAL): Change back to data section. + +Thu Jan 3 13:31:41 1991 Richard Stallman (rms at mole.ai.mit.edu) + + * loop.c (move_movables): Do reg substitutions on REG_EQUAL, REG_EQUIV. + + * out-i386.c (fp_top_dead_p1): Follow one jump or label. + + * rtl.c (read_rtx): Cast type of NULL vector. + +Wed Jan 2 18:59:34 1991 Richard Stallman (rms at mole.ai.mit.edu) + + * out-i386.c (fp_call_internal): Use fp_top_dead_p1, not top_dead_p. + * reload1.c (emit_reload_insns): Undo previous change. + +Tue Jan 1 12:01:43 1991 Richard Stallman (rms at mole.ai.mit.edu) + + * integrate.c (expand_inline_function): + Handle parms passed in reg but stored in memory. + + * ecoff-cmp: Specify `c' in option to tail. + + * reload1.c (emit_reload_insns) [PRESERVE_DEATH_INFO_REGNO_P]: + Move notes to output reload even if dest is reg. + Check for notes matching by hard reg, even if different origin. + Really scan all the output reload insns. + +Mon Dec 31 16:04:11 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * stupid.c (stupid_find_reg): Don't use reg if OVERLAPPING_REGNO_P. + + * i386.md (push for SFmode): Operand of fst was missing. + * out-i386.c (fp_call_internal): Discard result if unused. + +Sat Dec 29 16:37:10 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * Makefile (install): Use basename on eachfile; BSD make adds dirs. + + * cccp.c (macroexpand): Test traditional when computing expansion size. + +Thu Dec 27 23:42:42 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * reload.c (find_reloads_address_1): For auto-increment, save the reg + before replacing it with something being reloaded. + +Fri Dec 21 18:31:38 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * Version 1.38. + + * tm-i386vgas.h (STARTFILE_SPEC, LIB_SPEC): Deleted. + +Sun Dec 16 18:10:20 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * tm-i386vgas.h (ASM_OUTPUT_LABELREF): Do prepend `_' again. + + * tm-sun3.h (ASM_OUTPUT_FLOAT*, ASM_OUTPUT_DOUBLE*): + Use double_is_minus_zero to test for -0.0. + * out-m68k.c (double_is_minus_zero): New function. + +Fri Dec 14 00:57:30 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * tm-sun3.h (ASM_OUTPUT_FLOAT*, ASM_OUTPUT_DOUBLE*): + Use `iszero' and `signbit' to check for -0.0. + + * recog.c (offsettable_address_p): Use OFFSETTABLE_ADDRESS_P. + * tm-i860.h (OFFSETTABLE_ADDRESS_P): Define this. + +Wed Dec 12 16:11:05 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * gvarargs.h: Avoid duplicate inclusion using _VARARGS_H. + + * c-decl.c (grokdeclarator): Always promote short even if -mshort. + +Tue Dec 11 23:12:51 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * expr.c (convert_move): Do compare before slt. + Handle destination not valid in slt. + +Mon Dec 10 00:27:04 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * out-sparc.c (output_fp_move_double): Bugs in last change: + Use adj_offsettable_operand when possible. + Choose a reg other than fp to increment. + +Sun Dec 9 23:21:05 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * cccp.c (collect_expansion): Don't check for /* */ concat here. + (macroexpand): Always use raw arg if traditional. + +Wed Dec 5 13:52:16 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * optabs.c (expand_binop): Handle insn_before == 0. + + * Makefile (includes): Export LIB. + +Tue Dec 4 21:27:00 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * loop.c (consec_sets_giv): Give proper type to force, force2. + +Mon Dec 3 15:57:19 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * cccp.c (special_symbol): Use time_t as type of t. + +Sun Dec 2 16:43:31 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * config.gcc (tower): New alternative. + * tm-tower.h, tm-tower-as.h, xm-tower.h: New files. + + * stddef.h (ptrdiff_t): Prevent redefinition, as with size_t. + (size_t): Define all the macros used to prevent redefinition. + +Fri Nov 30 14:25:49 1990 Michael Meissner (meissner at osf.org) + + * out-mips.c (init_cumulative_args, function_arg_advance, + function_arg, function_arg_partial_nregs): Type CUMULATIVE_ARGS is + now a pointer to a structure instead of a structure. New field + arg_words tracks number of words consumed so far and arg_number just + tracks physical numbers of arguments. Make four single precision + floating point arguments passed via prototypes use $f12, $f14, $6, + and $7, just like mips cc. + + * tm-mips.h (INIT_CUMULATIVE_ARGS, FUNCTION_ARG_ADVANCE, + FUNCTION_ARG, FUNCTION_ARG_PARTIAL_NREGS): Type CUMULATIVE_ARGS is + now a pointer to a structure instead of a structure, and storage is + allocated via alloca. + +Thu Nov 29 22:03:57 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * tm-vax.h (BLOCK_PROFILER, FUNCTION_BLOCK_PROFILER): New macros. + +Tue Nov 27 12:03:36 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * tm-hp9k320.h (STANDARD_STARTFILE_PREFIX): Don't alter if already set. + +Tue Nov 27 12:28:45 1990 Michael Meissner (meissner at osf.org) + + * out-mips.c (function_arg, function_arg_advance): Pass single + precision floating point numbers to prototyped functions by assuming + only one word is passed rather than two unless the argument is + passed in a floating point register. This behavior matches the MIPS + C compiler. + + * tm-mips.h (CPP_SPEC): Add -D_MIPSEB -D_SYSTYPE_SYSV -D_LANGUAGE_C + to SGI's CPP_SPEC. + (MIPS_DEBUGGING_INFO): New macro. + (PUT_SDB_*): Write debug information to the temporary file that + buffers the text section, instead of using the current output file. + + * tm-iris.h (CPP_PREDEFINES): Move -D_LANGUAGE_C from CPP_PREDEFINES + to CPP_SPEC since it's in the compiler name space, -ansi should not + disable it. + +Mon Nov 26 18:37:39 1990 Michael Meissner (meissner at osf.org) + + * mips.md (stack compressor peephole): Remove check against + stack_args_preallocated, since nobody sets it. + (anonymous add/subtract patterns): Explicitly use the assembler + temporary register if adding/subtracting a constant that won't fit + in 16 bits -- Silicon Graphics asm complains. + (fix_truncdfsi2, fix_truncsfsi2) Rewrite so that optimization of + repeated conversions of the same number do not generate an insn not + found error message (the generated insn was optimized to a gp->gp + register move inside of a parallel with a clobber of a hard fp + register). The new insns describe the machine more faithfully, and + allow things like clobbering the fp register containing the value, + if it is the last use rather than using a specific hard register. + (fixuns_truncsfsi2, fixuns_truncdfsi2): New patterns to + automatically convert {single,double} precision to unsigned. + (anonymous move df/sf patterns): Put the operands to mfc1 in the + order the assembler likes them (always put gp reg first, even if + moving from gp register to fp register). + (wild_insn): Remove bogus insn which is commented out. + (jump): Remove TARGET_PIC code for now. + + * out-mips.c (toplevel, function_epilogue, mips_asm_file_end, + mips_output_external): If optimizing for the global pointer, emit + all code after processing the entire program, rather than emitting + the code at the end of the function. Also, properly sized .extern's + are emitted for variables that are not defined in the current + module. This is because the MIPS assembler uses single pass + semantics, and will emit a 2 instruction sequence for externals it + doesn't know anything about, and GCC emits data definitions at the + end of the program. You can't just emit a properly sized .extern + either, because the assembler will complain if it sees an .extern + followed by a definition. The ADDRESSABLE bit in the identifier + node for the external name is used to indicate whether a definition + for the name exists or not. This replaces code which told the + assembler to preprocess the source, and include the same source + twice. + (sym_lineno): Add a new variable to keep trace of labels emitted + after each .loc for Silicon Graphics. + (function_prologue, function_epilogue, toplevel): Explicitly use + temporary registers for stack frames > 32K, since the Silicon + Graphics system doesn't automatically use $at if the value overflows, + also save an instruction or two for large stack frames. + (init_cumulative_args): Fix to work with the method types G++ + produces as well as normal function types. + (compare_collect): In debug code, print the mode symbolically. + (trace): Take two additional arguments which are passed to fprintf. + (override_options): Remove unsupported -mpic code. + + * tm-decstatn.h (toplevel): Add a GNU copyright. + + * tm-iris.h (toplevel): Add a GNU copyright. + (CPP_SPEC): If -ansi, define __EXTENSIONS__. + (SGI_TARGET): Define this for other mips files. + (LABEL_AFTER_LOC): New macro to put a label after .loc. + (SET_FILE_NUMBER): New macro to force .file/.loc file # to be 1. + (ADJUST_STACK_SIZE): Don't deal with variable arguments. + + * tm-mips.h (*_SPEC): Add #ifdef's so other files can define their + own, without #undef. + (LINK_SPEC, ASM_SPEC): Pass -EB/-EL to assembler, linker so cross + compilers can be made from little endian mips to big endian mips and + vica versa. Generate an error message if the wrong flag is used. + Do not pass -EB/-EL to Silicon Graphics assembler/linker. + (CPP_SPEC, MACHINE_NAME): Add Silicon Graphics defaults. + (MIPS_TEMP?_REGNUM): New macros for temporary registers used in the + prologue and epilogue if the stack frame is > 32K. + (ASM_OUTPUT_LABEL): If optimizing the global pointer, set the + addressable bit in the indentifier node, so that mips_asm_file_end + and mips_output_external can figure out if a particular identifier + really is external to the compiliation unit. + (ASM_OUTPUT_COMMON): Same change as ASM_OUTPUT_LABEL. + (ASM_OUTPUT_LOCAL): Same change as ASM_OUTPUT_LABEL. + (MACHINE_TYPE): Key off of OSF_OS and SGI_TARGET macros. + (TARGET_DEFAULT): For OSF/1 make -mgas and -G 0 default. + (STACK_POINTER_OFFSET): Define as 0. + (external variables): Declare flag_omit_frame_pointer, + sdb_label_count, mips_section_threshold, and sym_lineno. + (STACK_ARGS_ADJUST): Protect with an #ifndef. + (FUNCTION_PROFILER): Talk to the MIPS profiling routines the same + way the MIPS compiler does. + (INDIRECTABLE_ADDRESS_P): Allow disp+reg in addition to reg+disp. + (ASM_FILE_START): If optimizing for the global pointer, create a + temporay stream to hold text until program ends. Put gcc_compiled. + in the data section. + (ASM_DECLARE_FUNCTION_NAME): Switch file streams used to the text + stream if optimizing for the global pointer. + (ASM_FILE_END): New macro to invoke mips_asm_file_end function. + (ASM_OUTPUT_SOURCE_LINE): Invoke macro LABEL_AFTER_LOC after .loc, + so that Silicon Graphics can put out a label after each .loc. + (ASM_OUTPUT_SOURCE_FILENAME): Invoke macro SET_FILE_NUMBER to set + the file number, so Silicon Graphics can hardwire this to 1. + (LABEL_AFTER_LOC, SET_FILE_NUMBER): Provide defaults if not Silicon + Graphics. + (ASM_OUTPUT_ASCII): Assign parameter to local variable, and remove + special \a, \v support. + (ASM_OUTPUT_IDENT): Dump #ident directives into .data. + +Mon Nov 26 16:50:57 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * cccp.c (main): Handle -w. + (warning): Do nothing if -w. + * gcc.c (compilers): Pass -w to cpp. + +Sun Nov 25 16:37:10 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * expr.c (emit_push_insn): Don't pad at all if space already allocated + and padding is upward. + + * gcc.c (do_spec_1): Handle %W{...}. + (compilers): Use %W{...} when passing -o option. + +Sat Nov 24 16:50:11 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * va-mips.h (va_list): Don't typedef if _VA_LIST_ is defined. + +Wed Nov 21 15:57:48 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * expr.c (expand_expr, expand_assignment): + Check for TREE_THIS_VOLATILE in ARRAY_REF. + expand_assignment failed to handle volstruct at all. + +Tue Nov 20 17:47:22 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * out-sparc.c (output_fp_move_double): Handle reg+reg address + when moving each word separately. + + * ns32k.md (addsi3): Don't use `addr' for very large displacements. + + * recog.c (address_operand): Don't allow volatile mem as indirect. + +Mon Nov 19 14:55:44 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * out-sparc.c (output_fp_move_double): Don't assume arrays are aligned. + +Sun Nov 18 19:21:10 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * expr.c (emit_push_insn): set extra to 0 once the padding is done, + to avoid padding twice. + +Thu Nov 15 21:56:07 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * math-68881.h (HUGE_VAL): Add extra braces on Sun. + +Wed Nov 14 14:30:29 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * c-decl.c (grokdeclarator): Don't ignore prototype if -traditional. + +Tue Nov 13 18:16:47 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * out-i860.c (output_block_move): Move .Lm%3 down one insn. + +Wed Nov 7 00:01:18 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * c-parse.y (component_decl_list): Allow missing semi at end. + +Tue Nov 6 20:49:57 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * expr.c (expand_builtin): For ffs, use mode of operand. + + * xm-iris.h (alloca): Don't define it. + * tm-iris.h (CPP_SPEC): Define variant symbols starting with _. + Define __EXTENSIONS__. + + * config.gcc (editing .gdbinit): Search current dir, not just srcdir. + +Sun Nov 4 12:55:03 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * i386.md (extend*): Take out last change. + Unix assembler rejects movsx... + + * expr.c (expand_expr): Special case for ignored volatile + failed to return. + +Fri Nov 2 15:30:48 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * va-i860.h (_VA_LIST): New macro avoids duplicate typedefs. + + * gnulib2.c (__builtin_saveregs): Add version for i860. + + * out-i860.c (output_block_move): Rearrange the copy loop. + Now uses two labels and a more complicated lead-in. + +Thu Nov 1 18:15:11 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * config.gcc (sun3, etc.): Assume os4 as default for Sun 3 and Sun 4. + + * math-68881.h (HUGE_VAL): Alternate definition for Suns. + + * tm-i386v.h (STARTFILE_SPEC, LIB_SPEC): Handle -posix. + (CPP_SPEC): New macro. + (LIB_SPEC): Handle -shlib. + +Wed Oct 31 22:12:33 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * config.gcc (ultrix): New alternative. + + * i386.md (extend*): Change opcode to movsx. Was movs. + +Tue Oct 30 17:03:46 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * tm-aix386.h (ASM_FILE_START): Don't do .noopt or .optim. + + * cccp.c (make_definition): Convert newline to newline-newline. + +Mon Oct 29 11:43:46 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * fixincludes: Fix missing semi in rusers.h. + +Sun Oct 28 17:23:50 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * cccp.c (macarg1): Don't skip the char after */. + + * Makefile: Put an `else' in every shell `if'. + + * m68k.md (zero-extend QI): Use gen_rtx, not change_address. + + * Makefile (USER_H): List va-*.h explicitly. + (toplev.o): Depend on RTL_H. + (expr.o): Depend on typeclass.h. + (stamp-*): Depend on move-if-change. + (install): Depend on various header files and gcc.1. + (gcc.o): Depend on gvarargs.h and obstack.h. + + * i860.md (movsf): Handle moving CONST_DOUBLE to cpu reg. + +Fri Oct 26 11:16:03 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * Makefile (libg): Add else to the if. + +Thu Oct 25 21:17:05 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * integrate.c (access_parm_map): Handle refs to all words of DF reg. + +Wed Oct 24 13:50:13 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * c-typeck.c (build_array_ref): Use main variant for value type. + + * expr.c (expand_expr): For ARRAY_REF, preserve const and volatile. + + * cccp.c (macarg1): Skip the */ that ends a comment. + + * cccp.c (rescan): Use newline_fix testing for comments before #. + (handle_directive): Likewise, in comments before directive name. + (rescan): Process macro when terminated by comment. + Ignore backslash-newline in C++ comment. + +Tue Oct 23 20:35:13 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * cccp.c (collect_expansion): Remove newline from error message. + Error for ## at beginning or end of definition. + + * m68k.md (zero-extend QI): When pushing, store value at 1(sp). + +Mon Oct 22 13:07:31 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * cccp.c (rescan): In the loop that handles numbers, discard \newline. + + * cccp.c (S_ISREG): Fix typo: do use the argument. + + * xm-sparc.h (alloca.h): Don't include if alloca already defined. + +Sun Oct 21 16:28:04 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * reload.c (find_equiv_regs): Reject reg that overlaps goal. + + * expmed.c (extract_bit_field): For big fields, make sure + value really goes in the target. + +Fri Oct 19 13:21:25 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * fold-const.c (split_tree): Use NEGATE_EXPR to negate *conp. + + * expr.c (emit_push_insn): Allow const0_rtx for multi-word constant. + +Thu Oct 18 17:38:17 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * reload1.c (choose_reload_regs): Cast reg class used as index. + +Wed Oct 17 00:21:25 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * stmt.c (push_structure_value, pop_structure_value): New fns. + * expr.c (expand_call): Use them if structure value needed. + + * gcc.c (do_spec_1): Null-terminate error message. + + * sdbout.c (sdbout_symbol): Handle subreg as DECL_RTL. + This happens for vars from the parms of inline functions. + * dbxout.c (dbxout_symbol): Likewise. + +Tue Oct 16 13:22:05 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * expmed.c (extract_bit_field, store_bit_field): + Handle fields wider than a word. + Restrict special case for word-sized field to aligned words. + + * stddef.h (size_t): Also inhibit if _SIZE_T_. + + * cccp.c (macarg1): If traditional, let backslash quote always. + + * fixincludes (CTRL): Don't put quotes around a quote. + +Sun Oct 14 21:28:32 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * flow.c (life_analysis): No hard regs for any pseudos live at setjmp. + + * c-decl.c (duplicate_decls): Don't suppress warning for fn defn + after implicit declaration, if fn has already been defined. + +Thu Oct 11 13:15:36 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * expr.c (saveregs_value): New variable. + (init_expr): Init the variable. + (expand_builtin): Don't call __builtin_saveregs twice in one function. + + * va-*.h: Rename all structure fields to start with __. + * va-pyr.h: Rename variables also. + (va_start): Delete the unmatched {. + (va_end): Now a nop. + +Wed Oct 10 22:01:59 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * va-sparc.h (__va_ctl): Rename fields to start with __. + +Tue Oct 9 14:47:53 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * flow.c (propagate_block): Include NOTE at end of block in scan. + + * fixincludes: Fix missing semicolon in rstat.h. + +Mon Oct 8 13:09:40 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * loop.c (eliminate_biv): Handle mult_val < 0 by reversing compare. + + * cccp.c (main): Handle .S when removing suffix for deps output. + +Sun Oct 7 23:33:24 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * tm-i386v.h (STARTFILE_SPEC): Handle -p here. + (LIB_SPEC): Not here. + +Sun Sep 30 21:35:52 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * print-tree.c (print_node_brief): Declare i for printing REAL_CST. + +Sat Sep 29 18:40:08 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * fixincludes: For link pointing outside /usr/include, + use $x rather than $dest. + +Wed Sep 26 12:44:54 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * tm-mips-news.h: New file. + + * out-i860.c (output_size_for_block_move): Don't decrement. + (output_block_move): Decrement initial storing address instead. + + * c-parse.y (yylex): Always try unsigned int if `u' is written. + + * tm-seq386.h (LINK_SPEC): Define it. + + * c-typeck.c (build_unary_op): Don't let &* make an lvalue. + +Sun Sep 23 14:59:21 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * cccp.c (S_ISREG): Define it unless overridden. + (main, finclude): Use that. + + * reload1.c (reload): If insn after a function call uses the + function value, and that reg is spilled, and the insn might + use it for reloading, add an extra need. + (reload_as_need): Detect such insns for new arg to choose_reload_regs. + (choose_reload_regs): In that case, don't choose function value reg. + + * tm-convex1.h, tm-convex2.h (CPP_SPEC): Define __NO_INLINE_MATH. + +Sat Sep 22 14:01:00 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * tree.c (build_index_type): Don't hash variable-bound type. + + * tm-aix386.h (LIB_SPEC): Different library name for -p. Always -lc. + (LINK_SPEC): Don't pass -lg or -g. + (CPP_PREDEFINES): Define _I386 and _AIX; don't define unix. + (SDB_DEBUGGING_INFO): Define it. + (DBX_DEBUGGING_INFO): Undefine it. + (ASM_FILE_START): Output .noopt if not optimizing. + (PCC_BITFIELD_TYPE_MATTERS): Define it. + (FUNCTION_PROFILER): Add definition. + +Thu Sep 20 13:16:39 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * tm-hp9k320.h (PROFILE_BEFORE_PROLOGUE): Define it. + (FUNCTION_PROFILER): Don't redefine if not HPUX_ASM. + +Tue Sep 18 22:46:02 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * sdbout.c (sdbout_one_type): Don't output undefined structs, etc. + +Mon Sep 17 13:35:45 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * mips.md (movdf): Move words in opposite order if overlap. + +Sun Sep 16 16:27:29 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * toplev.c (rest_of_decl_compilation): Output TYPE_DECL here for sdb + only if top_level. + + * expr.c (expand_builtin): Error for __builtin_nextarg + if function definition doesn't have `...'. + + * c-typeck.c (build_conditional_expr): Don't skip arg promotion. + +Fri Sep 14 17:26:59 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * sdbout.c (plain_type_1): Save up array dims on the way out + in the reverse order. + (plain_type): Print the innermost ones, reversing them. + +Thu Sep 13 16:00:05 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * gstdarg.h: New name for stdarg.h. + * Makefile (install): Rename gstdarg.h while installing it. + + * fixincludes: Discard `.' from value of `files'. + + * sdbout.c (PUT_SDB_LAST_DIM): Get rid of SDB_DELIM. + (plain_type): Output accumulated array dims and size. + (plain_type_1): Eliminate arg NOSIZE. Save up dims and size. + Call self rather than plain_type for pointers and functions. + (sdbout_array_type, sdbout_array_depth): Functions deleted. + +Wed Sep 12 18:47:30 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * expmed.c (expand_divmod): Use divmod insn for divide if appro. + +Tue Sep 11 13:24:58 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * gnulib.c (_bb_init_func): Library member now named _bb. + +Mon Sep 10 13:07:39 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * sdbout.c (plain_type_1): New argument NOSIZE. Inhibits size output. + (sdbout_array_type): Call plain_type_1 directly; set NOSIZE. + + * sdbout.c (sdbout_array_type): New argument DEPTH. + Don't output more than SDB_MAX_DIM dimensions. + (sdbout_array_depth): New function. + (plain_type_1): Start DEPTH by calling sdbout_array_depth. + +Sun Sep 9 18:05:56 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * tm-mips.h (CPP_SPEC): Error for -EL and -EB. + + * sdbout.c (plain_type_1): Test KNOWN_TYPE_TAG with TREE_ASM_WRITTEN. + (sdbout_symbol): Call sdbout_one_type before the switch. + (sdbout_field_types): Look at targets of pointers. + (sdbout_one_type): Call sdbout_field_types. + + * stor-layout.c (layout_record): Update size_unit adding var to var. + + * tm-i386v4.h: New file. + +Fri Sep 7 13:10:24 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * cccp.c (STDC_VALUE): New macro, defaulting to 1. + (intialize_builtins): Use that. + + * print-tree.c (print_node): Correct first_rtl for SAVE_EXPR. + + * m68k.md (movqi): `st' does not set cc's. + +Wed Sep 5 16:18:04 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * Makefile (includes): Use proper directory. + +Tue Sep 4 13:01:37 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * c-decl.c (store_parm_decls): Let extra_warnings control + warnings about parms not declared. + + * local-alloc.c (block_alloc): Don't try to lower qty_birth + if reg_qty is negative. + + * flow.c (life_analysis): Move code to detect stack-adjust insns. + It was unreachable. + + * reload1.c (reload): Don't complete group with explicitly used reg. + +Mon Sep 3 14:37:41 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * Makefile (RANLIB): Don't specify the directory. + + * local-alloc.c (reg_classes_overlap_p): Cast enums to ints. + +Fri Aug 31 17:09:38 1990 Michael Meissner (meissner at osf.org) + + * mips.md (anonymous add insn before addsi3): Allow offsets from the + frame pointer to be >16 bits, just like the stack pointer. This is + to prevent insn's not found generated when optimizing programs that + have stack frames more than 32K, and the optimizer wants to load the + address of an array into a register, it does so by generating a PLUS + insn with the appropriate offset. This PLUS insn is never checked + to see if the machine can handle the offset. + (anonymous subtract insn before subsi3): same change as above. + (addsi3): Don't accept large constants with a !n constraint. Just + reject any large constants, the anonymous add pattern before addsi + will catch references to the stack and frame pointers. + (subsi3): Same change as addsi3. + +Sat Sep 1 16:14:31 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * expr.c (convert_move): Don't forget to set `target'. + +Fri Aug 31 14:37:36 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * sdbout.c (sdbout_begin_block): Delete excess arg to sdbout_block. + +Wed Aug 29 17:01:55 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * local-alloc.c (combine_regs): Don't combine regs if classes + fail to overlap usefully, if either reg says preferred or nothing. + (reg_classes_overlap_p): New function. + +Tue Aug 28 21:28:54 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * sdbout.c (plain_type_1): Output .dim X,Y...; for multi-dim array. + (sdbout_array_dim): New recursive subroutine. + (PUT_SDB_DIM): Macro eliminated. + (PUT_SDB_START_DIM, PUT_SDB_NEXT_DIM, PUT_SDB_LAST_DIM): New macros. + * tm-3b1.h: Override PUT_SDB_START_DIM. + +Sun Aug 26 21:28:20 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * cccp.c (make_definition): Eliminate any backslash-newline. + +Sat Aug 25 17:20:47 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * tm-att386.h (EXTRA_SECTIONS, EXTRA_SECTION_FUNCTIONS): New macros. + (BSS_SECTION_ASM_OP): New macro. + (ASM_OUTPUT_LOCAL): Call bss_section, don't just print .bss. + +Fri Aug 24 17:16:28 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * cse.c (rtx_cost): Cost of MEM depends on number of words. + + * i860.md (movsf, movdf): Allow moving G to m in constraints. + * tm-i860.h (CONST_COSTS): Make SFmode constant cheaper. + +Thu Aug 23 14:19:20 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * c-typeck.c (digest_initializer): No pedantic warning for string + and array of unsigned char. + + * tree.c (get_identifier): Do id_clash_len stuff if length equals that. + +Wed Aug 22 15:06:11 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * loop.c (scan_loop): Don't use REG_EQUAL notes as invariants + unless they come with REG_RETVAL notes. + +Tue Aug 21 20:03:51 1990 Michael Meissner (meissner at osf.org) + + * Makefile (install): Add code to build libg.a if it doesn't exist + when installing GCC. + + * out-mips.c (toplevel): add external declaration for asm_out_file, + and 2 new FILE *'s (asm_out_data_file, asm_out_text_file) so we can + switch between two files when optimizing for the global pointer. + Also add a structure type to hold the linked list of externs that + GCC wishes to emit. + + Everything between the function prologue and epilogue are written to + a temporary file, which is written to the normal output file after + the entire program is processed. This is needed because the MIPS + assembler assumes that all externals should be referenced with a 2 + instruction sequence instead of the faster 1 instruction sequence + off of the GP, unless a proper .extern proceeds any use. We can't + emit the .extern because the assembler will complain if later there + is a definition for the variable, such as GCC puts out at the end of + the program. + + (compare_collect): print mode symbolically in debug code. + + (mips_output_external): Remove code which used the preprocessor to + handle the global pointer, and remember all externs in a linked list + for use at the end of the program. + + (mips_asm_file_end): If optimizing the global pointer, emit all + externals which don't have definitions as the appropriate sized + .extern, and then emit the code for functions that was written to a + temporary file, so that the code comes after the appropriate + definition or declaration. + + (function_epilogue): If optimizing for the global pointer, switch + the current output file to the data file after all of the epilogue + is written out. + + * tm-mips.h (ASM_SPEC): Duplicate ASM_SPEC into 2 #ifdef sections (one + for the little endian DECstation, and the other for everybody else + who uses the MIPS in a big endian mode), and pass the appropriate + -EL and -EB switches to the assembler. This allows building a cross + compiler for a different endian MIPS. + + (LINK_SPEC): Pass -EL and -EB to linker, just like ASM_SPEC. + + (MACHINE_TYPE): For DECstation, specify "Ultrix Dec Mips" instead of + just "Dec Mips". + + (FUNCTION_PROFILER): Call _mcount in the appropriate MIPS fashion. + + (ASM_FILE_START): If optimizing for the global pointer, open a + temporary file to write the code to (see out-mips.c above). + + (ASM_DECLARE_FUNCTION_NAME): If optimizing for the global pointer, + switch the current output file to asm_out_text_file. + + (ASM_OUTPUT_COMMON): Remove the old code which used the preprocessor + to optimize for the global pointer. + +Tue Aug 21 17:44:49 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * make-cc1.com: Compile and link version.c. + + * expr.c (convert_move): Handle expand_unop retval not same as target. + + * reload.c (find_reloads): For register letters, don't win if BLK. + + * flow.c (mark_set_1, mark_used_regs): Update reg_first_use. + (allocate_for_life_analysis): Allocate and clear it. + * local-alloc.c (block_alloc): Calculate INSN_MAP. + Get first use of each reg from reg_first_use. + + * tm-vms.h (MAYBE_VMS_FUNCTION_PROLOGUE): Distinguish C from C++. + (EXTRA_SECTIONS, EXTRA_SECTION_FUNCTIONS): Add a const data section. + (ASM_OUTPUT_EXTERNAL): Use that section. + (SELECT_SECTION): Go to that section when appropriate. + +Mon Aug 20 13:00:53 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * gcc.c (process_command): Split -oFOO into two arguments. + + * out-mips.c, tm-mips.h: Changes by Meissner. + + * stmt.c (expand_asm_operands): Handle COMPONENT_REF and + ARRAY_REF directly as output operands. Avoids crash if BLKmode. + + * tm-i386vgas.h: New file, copied from tm-i386gas.h. + (ASM_OUTPUT_LABELREF): Eliminate leading underscores. + (STARTFILE_SPEC, LIB_SPEC): Define as in tm-i386v.h. + (PCC_BITFIELD_TYPE_MATTERS): Likewise. + * config.gcc (i386-sysv-gas): Use the new file. + + * tm-i860.h (PRINT_OPERAND): Convert double to float + for SFmode operand. + (PRINT_OPERAND_EXTRACT_FLOAT): New macro. + +Sun Aug 19 17:23:10 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * c-parse.y (lineno): Delete definition--it's in toplev. + + * output.h: Make all variables extern. + + * tm-hp9k320bsd.h (CPP_SPEC): Def __HAVE_68881__ like __HAVE_FPU__. + + * fixincludes: Handle uses of _IO* followed by spaces. + Change redirections for cd when testing that directory exists. + +Thu Aug 16 22:44:35 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * out-sparc.c (output_scc_insn): Clear CC_IN_FCCR after + operation since setting a register to the result of a + floating-point comparision affects the INTEGER condition code + register. + + * stmt.c: fixup_gotos must ignore blocks started after the goto. + (block_start_count): New variable, and slot in some structures. + (expand_function_start): Initialize it. + (expand_start_bindings): Increment it and store in struct nesting. + (expand_goto): Store it in struct goto_fixup. + (fixup_gotos): Compare fixup's count with block's count. + +Wed Aug 15 16:46:04 1990 Richard Stallman (rms at mole.ai.mit.edu) + + * out-i860.c (output_size_for_block_move): Do subtract ALIGN. + +Mon Aug 13 17:45:13 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * tm-i860.h (GO_IF_LEGITIMATE_ADDRESS): Typo testing offset alignment. + + * config.gcc (sun3-mach): New alternative. + * tm-sun3mach.h: New file. + + * m68k.md (bfextu patterns): Set CC_NOT_NEGATIVE. + +Sun Aug 12 14:25:23 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * tree.h (enum built_in_function): Delete comma after last name. + * c-parse.h (enum rid): Likewise. + * expr.h (enum optab_methods): Likewise. + + * config.gcc (genix): Set target_machine. + * tm-genix.h (ASM_OUTPUT_DOUBLE): New overriding definition. + +Thu Aug 9 15:19:17 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * tm-hp9k320.h (CPP_SPEC): Define _HPUX_SOURCE if not ANSI. + (CPP_PREDEFINES): Don't define it here. + Do define alternatives with __ prepended. + + * tm-mips.h (CPP_SPEC): Don't do -I if -nostdinc. + +Wed Aug 8 13:35:00 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * cccp.c (do_define, do_undef): Warn if macro name is `defined'. + + * tm-mips.h (ASM_INT_OP): Add missing space. + + * tm-sun386i.h (ASM_IDENTIFY_GCC): If profiling, put a NOP after + gcc_compiled. + +Tue Aug 7 12:19:46 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * out-mips.c (need_ent_after_loc): Variable deleted. + (function_prologue): Output initial .ent and initial label. + * tm-mips.h: Add extern declarations. + (ASM_SPEC): No -nocpp if optimizing. + (STACK_ARGS_ADJUST): Round size up to 16. Nothing else. + (PRINT_OPERAND_ADDRESS): Eliminate irrelevant things + such as scaled indexing. + (ASM_OUTPUT_SOURCE_FILENAME): Simplify code. + (ASM_OUTPUT_SOURCE_LINE): Flush code to handle need_ent_after_loc. + (ASM_DECLARE_FUNCTION_NAME): Likewise. + (*_SECTION_ASM_OP): Delete the \n. + + * pyr.md (extendsfdf2, truncsfdf2, float*, fix*): Use `&'. + +Mon Aug 6 12:46:07 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * c-decl.c (grokdeclarator): Don't warn if initialized fcn is extern. + (start_decl): Don't warn at all for initialized extern. + + * final.c (final_start_function): Handle PROFILE_BEFORE_PROLOGUE. + (profile_function): New subroutine. + + * tm-i386sco.h: New file. + * config.gcc (i386-sco): New alternative. + +Sun Aug 5 12:36:46 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * stor-layout.c (layout_record, layout_union): Test value of + PCC_BITFIELD_TYPE_MATTERS for being nonzero, if it is defined. + * tm-*.h: Define with value 1. + * tm-vax.h (PCC_BITFIELD_TYPE_MATTERS): Depends on -mvaxc-alignment. + + * proto.h: New file. + * Makefile.in (USER_H): Add that file. + + * loop.c (other_reg_use_p): Change && to || in test at beginning. + +Fri Aug 3 00:18:35 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * gcc.c (ENDFILE_SPEC): New macro. + (do_spec_1): Handle %E. + (link_spec): Use %E. + + * xm-i386.h (alloca): Define without arg. + + * Makefile (RANLIB): New var, used in various places. + + * gnulib2.c (__bb_init_func): Add dummy function to prevent warning. + + * Makefile (install): Look for ranlib in both places. + (stage1, ...): Likewise. And run ranlib even after ln. + +Tue Jul 31 23:59:45 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * tm-encore.h (FUNCTION_PROFILER): Override, putting `.' in label. + +Mon Jul 30 13:52:45 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * gnulib2.c (__floatdidf): Fix typo. + +Sun Jul 29 16:05:27 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * tm-vms.h (ASM_OUTPUT_EXTERNAL): Check TREE_READONLY. + + * xm-vms.h (alloca): Use built-in alloca. + +Fri Jul 27 15:07:00 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * combine.c (subst): Handle (ASHIFT 1 x) in (EQ (AND ... y) 0) + only if little-endian. + +Thu Jul 26 17:22:56 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * tm-mips.h (ASM_OUTPUT_SOURCE_LINE): Delete pic stuff (was for v2). + + * fold-const.c (rshift_double): Reset carry after each shift of + one bit. + +Wed Jul 25 16:21:08 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * tm-vms.h (ASM_OUTPUT_EXTERNAL): Use assemble_name. + +Tue Jul 24 15:35:04 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * c-typeck.c (build_binary_op_nodefault): Allow compare of any + pointer with const void *, etc. + + * reload1.c (reload): Don't use fixed reg or frame pointer in group. + + * c-decl.c (grokdeclarator): Error for initialized parm. + +Mon Jul 23 14:33:53 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * Makefile (install): chmod only the header files. + +Sat Jul 21 13:58:16 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * cccp.c (O_RDONLY): Define it if not defined. + + * c-decl.c (finish_decl): No error for nonstatic incomplete array. + +Sat Jul 14 14:59:33 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * gcc.c (compilers): Pass -P to cpp. + + * tm-mips.h (ASM_OUTPUT_SOURCE_LINE): Handle TARGET_GAS, TARGET_PIC. + +Thu Jul 12 12:28:16 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * stor-layout.c (layout_record): Handle BITFIELD_NBYTES_LIMITED. + + * stmt.c (group_case_nodes): Don't group across an overflow. + + * combine.c (subst, case LSHIFT): Use gen_lowpart_for_combine. + +Wed Jul 11 15:17:32 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * combine.c (subst, case LSHIFT): + Fix condition for (lshift ... (sign_extend ...)). + +Tue Jul 10 17:02:54 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * c-decl.c (pushdecl): No shadow warning if TREE_INLINE is set. + * integrate.c (copy_parm_decls): Set TREE_INLINE in the copies. + (copy_decl_tree): Likewise. + + * c-parse.y (yylex): Terminate token_buf after integer. + +Mon Jul 9 16:56:55 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * expr.c (expand_call): Don't check args[i].partial when bumping + negative args_size up to 0. + + * sparc.md (call recognizers): Don't allow address arithmetic. + +Sun Jul 8 14:22:22 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * c-typeck.c (build_c_cast): Reinsert missing default_conversion call. + + * gnulib.c (__bb_init_func): Ensure this defines >=1 symbol. + +Fri Jul 6 12:28:44 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * c-typeck.c (build_indirect_ref): + No error if result is incomplete array. + + * m68k.md (casesi2 recognizer): Handle new ASM_RETURN_CASE_JUMP macro. + + * expmed.c (store_bit_field, extract_bit_field): New arg TOTAL_SIZE. + Don't extract a bigger unit from memory than this. + * expr.c: Callers changed. + (store_field): New arg TOTAL_SIZE; callers changed. + + * xm-ns32k.h: Use built in alloca. + * ns32k.md (movsf): Output float constants only if GAS_SYNTAX. + (call, call_value): Support JSR_ALWAYS. + Change handling of bsr for GAS_SYNTAX. + +Thu Jul 5 15:05:19 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * mips.md (divdf3): Fix spacing in output. + (movdf): Fix bad output storing CPU regs into memory. + * out-mips.c (function_prologue): Bug testing fmask. + (function_epilogue): Bug in spacing in output. + + * c-typeck.c (build_conditional_expr): Handle ((void *) 0). + Allow 0 versus function pointer. + +Tue Jul 3 21:43:40 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * c-decl.c (finish_struct): Lay out any array typedefs now completed. + (layout_array_type): New function. + (grokdeclarator): Don't warn for incomplete array in typedef. + + * tm-*.h (ASM_OUTPUT_COMMON): Use %u, not %d. + (ASM_OUTPUT_LOCAL, ASM_OUTPUT_SKIP): Likewise. + +Mon Jul 2 12:07:08 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * i386.md (tstsf): Clobber reg 0 in SImode. + +Sun Jul 1 14:28:58 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * stddef.h: Check __SIZE_T also. + + * toplev.c: Include types.h first. + + * i386.md (trunc*2): Don't allow moving symbolic constant to memory. + Use wider move only for symbolic constant. + + * tm-convex.h (LINK_SPEC): Posix link flags. + * tm-convex.h (STARTFILE_SPEC): Posix start files. + * tm-convex[12].h (CPP_SPEC): Posix defines. + * tm-convex[12].h (LIB_SPEC): Posix libraries. + * tm-conv[12]os7.h: New files. + * config.gcc: use tm-conv*os7 if /usr/include/stdlib.h isn't there. + + * xm-convex.h (S_IFMT, S_IFREG): make visible if hidden for posix. + * xm-convex.h (_PROTO): define to keep 8.0 includes from screwing up. + + * tm-convex.h (ASM_OUTPUT_{FLOAT,DOUBLE}, PRINT_OPERAND): + use %e instead of %#g, which is broken or non-posix. + + * tm-convex.h (current_section_is_text): make extern. + * out-convex.c (current_section_is_text): define here. + * tm-convex.h (OVERRIDE_OPTIONS), out-convex.c (override_options): + useless; remove. + * tm-convex.h (CPP_PREDEFINES): remove parsec, long gone from + system includes. + +Fri Jun 29 12:42:16 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * tm-vax.h (LEGITIMATE_CONSTANT_P): Fix typo. + + * out-mips.c (function_arg_partial_nregs): Round size up to words. + +Thu Jun 28 12:50:44 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * cse.c (cse_insn): Replace src only with general_operand + unless moving to a register. + + * expr.c (expand_expr): Use assign_stack_local for constructors. + + * Makefile (STAGESTUFF): Change names of stamp files. + + * pyr.md (tstqi): Change comma to semicolon. + + * out-mips.c (init_cumulative_args): Fix name of debug_tree. + + * vax.md (movsi special case): Fix assembler syntax. + * tm-vax.h (LEGITIMATE_CONSTANT_P): Add missing backslashes. + * tm-ultrix.h (DOLLARS_IN_IDENTIFIERS): Define as 1. + +Wed Jun 27 14:04:51 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * expr.c (emit_move_insn): Force constants to mem only if predicate + fails. + * out-vax.c (supergeneral_operand): New function. + * vax.md (movsi): Use that predicate. + + * out-mips.c (function_prologue): Don't use sp_str in .frame. + Use sw rather than sd in cases 5 and 7. + +Tue Jun 26 14:21:36 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * rtl.h (EXTERNAL_SYMBOL_P): New macro. + * varasm.c (make_decl_rtl): Set it if variable is external. + * tm-vms.h (NO_EXTERNAL_INDIRECT_ADDRESS): Define this. + * tm-vax.h (INDIRECTABLE_CONSTANT_ADDRESS_P): New macro. + Value depends on NO_EXTERNAL_INDIRECT_ADDRESS. + (INDIRECTABLE_ADDRESS_P, LEGITIMATE_CONSTANT_P): Value depends... + (NONINDIRECT_ADDRESS_P): New macro. + (GO_IF_NONINDEXED_ADDRESS): Use NONINDIRECT_ADDRESS_P sometimes. + * vax.md (movsi special case): New pattern for loading + illegitimate constants. + * out-vax.c (print_operand_address): Handle reg+(reg+const). + + * tm-sparc.h (LINK_SPEC): Delete spurious `-'. + * tm-sun386i.h (LINK_SPEC): Define it, handling -Bstatic and aliases. + * tm-sun3.h (ASM_OUTPUT_FLOAT_OPERAND): Delete spurious `\n'. + (ASM_OUTPUT_DOUBLE_OPERAND): Likewise. + +Mon Jun 25 18:45:51 1990 Michael Meissner (meissner at osf.org) + + * sdbout.c: If not on a COFF system, define COFF symbols by hand. + + * out-mips.c (legitimize_constant_expr): Delete unused function. + (output_load_immediate, addr_compensate): Delete unused functions. + (compare_restore): Redo code based on eliminating peepholes. + (function_prologue): New function, emit correct entry sequence. + (function_epilogue): New function, emit correct exit sequence. + Also output .ent, .frame, .mask, .fmask, and .end, for back tracing. + (mips_fix_frame_pointer): New function to eliminate frame. + (function_arg_partial_nregs, function_arg, function_arg_advance): + (init_cumulative_args): New funtions. + + * stdarg.h (va_arg): Alternate definition for mips. + * va-mips.h: Total rewrite. + These changes in tm-mips.h have not yet been done. + * tm-mips.h (ASM_OUTPUT_DOUBLE): Put floating point out in hex. + (ASM_OUTPUT_FLOAT): Put floating point out in hex. + (PRINT_OPERAND): Add 'D', 'L', and 'M' codes. + (STRUCTURE_SIZE_BOUNDARY): Set this to 8 for MIPS cc compatibility. + (CC1_SPEC): Add -O1 which is same as -O. + (CC1_SPEC): Add -O3 which is -O2 + -finline-functions. + (TARGET_SWITCHES): Use hex for options. + (TARGET_SWITCHES): Rename -munix to -mmips-as. + (TARGET_SWITCHES): Add -mgas as oppisite of -mmips-as. + (TARGET_SWITCHES): Add -mpic, -mpic-large-object (but no code yet). + (TARGET_SWITCHES): Make -mdebug* comments match reality. + (PROMOTE_PROTOTYPES): Define this macro. + (FIXED_REGISTERS): Allow $f0, $f2, and $f14 to be allocated. + (NO_LIBG): Define this macro. + (TARGET_VERSION): Be more specific about which vendors MIPS system. + (ASM_FILE_START): Call ASM_OUTPUT_SOURCE_FILENAME, print_options. + (ASM_OUTPUT_SOURCE_FILENAME): Emit correct .file directive. + (ASM_OUTPUT_SOURCE_LINE): Emit correct .loc directive. + (EXTRA_SECTIONS): Add rdata_section. + (SELECT_SECTION, SELECT_SECTION_MODE): Use .rdata if feasible. + (SDB_DEBUGGING): Define this, but only line #'s supported now. + (FRAME_POINTER_REQUIRED): Allow no frame ptr in leaf procedures. + (GO_IF_LEGITIMATE_ADDRESS): Don't allow REG+70000 as address. + (various): Use MIPS profiling (no _mcount). + (various): Add new macros to classify registers. + (NO_UNDERSCORES): Define this for G++. + + * mips.md (peepholes): Merge 4 peepholes, delete 24 unneeded ones. + Replaced with an anonymous pattern for a test insn. + (call_value): Change to a define_insn. + (movsi, movhi, movqi): Don't fall through at end, to avoid a warning. + (movsf special case for immediate args): Pattern deleted. + (movdf special case for immediate args): Pattern deleted. + (movsf, movdf): Use new macros to distinguish fp regs. + Add letter `y' to constraints. + (cmpsi): Allow arith_operand for second operand. + (hi and qi tests): Patterns deleted. + (jump): Handle TARGET_PIC. + (tablejump): Pattern moved. + (conditional branches): Align the comments that are output. + (call, call_value): Make predicates more specific. + Don't output any comments. + + * out-mips.c: Include flags.h. Include tree.h at beginning. + Define numerous variables counting things used in this compilation. + (my_print_rtx): Deleted. Callers use debug_rtx. + (output_load_immediate): Simply output an li instruction. + (print_options): Body rewritten. Now always defined, but body + is in an #if 0. + (abort_show_logged, my_print_insncode): Functions deleted. + (abort_with_insn): Now use `error' to print the message. + (mips_section_get): Function deleted. + (override_options): Update mips_section_threshold, once and for all. + +Mon Jun 25 16:54:13 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * integrate.c (output_inline_function): Pass dummies for new args + to init_function_start. + + * stddef.h: Check _T_SIZE as well as _SIZE_T. + +Sun Jun 24 17:15:34 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * stmt.c (init_function_start): New args give file/line for first note. + * c-decl.c (store_parm_decls): Pass them. + * final.c (final_start_function): For sdb, don't output a line number, + just set last_linenum. + + * tm-att386.h (ASM_OUTPUT_LOCAL): Put it in .bss section. + +Fri Jun 22 12:40:07 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * cccp.c (handle_directive): Always ignore empty directive. + + * tree.h (BUILT_IN_NEXT_ARG): Define it. + * c-decl.c (init_decl_processing): Declare __builtin_next_arg. + * expr.h (current_function_arg_offset_rtx): Declare it. + * stmt.c (assign_parms): Set that variable at end. + * expr.c (expand_builtin): Implement __builtin_next_arg. + * stdarg.h (va_start): Use __builtin_next_arg. + * function.c (push_function_context, pop_function_context): + Save and restore current_function_arg_offset_rtx. + * function.h (struct function): New field for this. + +Wed Jun 20 15:26:16 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * tm-apollo68.h (FUNCTION_ARG_PADDING): Never pad. + (STACK_BOUNDARY): Make it 32. + (CPP_SPEC): Add spaces. Define _APOLLO_SOURCE if not -ansi. + + * expr.c (expand_call): If have STACK_BOUNDARY and push insns, + compute stack_align when size is rounded, and use later + to push the space for the rounding. + +Tue Jun 19 15:41:53 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * genextract.c (gen_peephole): Use sizeof (rtx), not UNITS_PER_WORD. + + * reload1.c (reload_inheritance_insn): New variable. + (reg_reloaded_insn): New variable. + (choose_reload_regs): Update those variables. + (emit_reload_insns): Use them to remove deaths from insns + that used input reloads. + (reload_as_needed): Clear reg_reloaded_insn when necessary. + +Mon Jun 18 13:25:59 1990 Michael Meissner (meissner at osf.org) + + * mips.md (probe): Make a single insn, just a memref. + + * mips.md (ashlqi3, ashlhi3, one_cmplqi2, one_cmplhi2): Deleted. + (ashlsi3, ashrsi3, lshrsi3, neg*, one_cmplsi2): Simplified. + Don't output comments. Use more specific predicates. + + * mips.md (movsf, movdf): Use L, M codes to avoid #ifdef's. + Also simplify and don't output comments. + (anonymous patterns for those insns): Deleted. + (loading floating constant): New patterns added. + (move qi to si pattern): Deleted; ridiculous. + (movdi, movsi, movhi, movqi): No need to check for moving reg to self. + + * mips.md (nop): Use .set noreorder to placate assembler. + +Sun Jun 17 01:19:26 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * Makefile (stamp-*.c, stamp-*.h): Remove .c or .h from names. + + * tm-i860.h (GO_IF_LEGITIMATE_ADDRESS): Displacement must be multiple + of the alignment of the operand. + + * i860.md (signed bit field recognizers): Don't shift by >31 bits. + + * out-i860.c (output_delayed_branch): Pass register properly to + load_opcode. + + * sdbout.c (sdbout_symbol): Get right regno for var-length object. + + * c-decl.c (duplicate_decls): Types don't "match" if one is error. + + * cexp.y (yylex): Ignore carriage return. + * cccp.c (initialize_char_syntax): Likewise. + +Sun Jun 17 01:19:26 1990 Michael Meissner (meissner at osf.org) + + * mips.md (general/fp reg move patterns): Use codes L, M, D. + (movdi): Likewise. And don't output useless comments. + Use the assembler temp reg for non-offsettable address. + (movsi, movhi, movqi): Output nothing for move from reg to itself. + Output li to load a constant. Use `move' instead of `add'. + Don't output useless comments. + (load-address pattern): Deleted; handled by addsi3 pattern. + + * mips.md (addsi3, mulsi3): Make both input predicates arith_operand + since they are commutative. + (andsi3, iorsi3, xorsi3): Likewise. + + * tm-mips.h (MOST_SIGNIFICANT_WORD, LEAST_SIGNIFICANT_WORD): New. + + * tm-mips.h (PRINT_OPERAND): New codes D, L, M. + * mips.md (anddi3, iordi3, xordi3): Use earlyclobber to stop overlap. + Use new print code D. + + * mips.md (andsi3, iorsi3, xorsi3): Make predicates more specific. + (andhi3, ..., andqi3, ...): Patterns deleted. + (patterns for nor): New anonymous patterns. + * out-mips.c (uns_arith_operand): New function. + + * mips.md (trunc*, zero_extend*, extend*, fix_trunc*, float*): + Use more specific predicates. + + * mips.md (addhi3, ..., addqi3, ...): Patterns deleted. + (addsi3, subsi3, mulsi3, divsi3): Make predicates more specific. + Delete useless comments from assembler code. + Use more generic op codes rather than special cases such as addiu. + (divmodsi4, udivmodsi4, udivsi3, modsi3, umodsi3): New patterns. + (abssf2, absdf2): New patterns. + +Sat Jun 16 22:52:44 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * c-typeck.c (process_init_constructor): Handle unions. + (digest_init): Use that for union inits. + +Wed Jun 6 19:20:20 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * loop.c (move_movables): In insn-deleting loop, check p != 0. + +Sun Jun 3 22:44:12 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * c-decl.c (grokdeclarator): Warn about extern with initializer. + +Sat Jun 2 14:46:18 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * c-decl.c (grokdeclarator): Handle const and volatile with parm + specified as function type. + + * varasm.c (immed_real_const_1): Don't confuse -0.0 with 0.0. + + * tm-sun3.h (ASM_OUTPUT_FLOAT, ASM_OUTPUT_DOUBLE): Handle -0.0. + (ASM_OUTPUT_FLOAT_OPERAND, ASM_OUTPUT_DOUBLE_OPERAND): Likewise. + Note: Sun 4 (under SunOS 4) seems to work okay without this change. + Perhaps printf works better in that version. + +Fri Jun 1 13:38:41 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * expr.c (expand_call): For const function, pop stack before and aft. + +Thu May 31 12:59:28 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * expr.c (expand_call): Don't round stack block if size negative. + + * fold-const.c (fold): Preserve sign on constant when other terms + cancel (after call to split_tree). + +Wed May 30 20:49:10 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * c-parse.y (primary, fndef): Use YYFAIL, since YYERROR was changed. + + * out-m68k.c (output_move_double): Don't test HOST_WORDS_BIG_ENDIAN + since that only exists in version 2. + * tm-m68k.h (PRINT_OPERAND_EXTRACT_FLOAT): New macro wasn't mentioned. + Don't test HOST_WORDS_BIG_ENDIAN. + (PRINT_OPERAND_PRINT_FLOAT): New macro wasn't mentioned before. + (PRINT_OPERAND): Use them. + +Tue May 29 21:35:23 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * optabs.c (expand_float): Don't use hard reg for intermediate result. + + * c-parse.y (yylex): Fix typo in handling of ERANGE. + + * sparc.md (tstdf, tstsf): Use a CLOBBER, not a USE, on f0. + + * sparc.md (eager branch peepholes): Fix typos. + * tm-sparc.h (OUTPUT_JUMP): Define this. + + * print-tree.c (print_lang_identifier): New function. + +Sat May 26 13:42:04 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * sdbout.c (sdb_begin_function_line): Now -1 if not in use. + (sdbout_end_function): Set it to -1. + +Fri May 25 00:18:29 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * print-tree.c: Total rewrite. + +Thu May 24 21:26:08 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * cccp.c (macarg): When popping frame, free via free_ptr, not buf. + +Tue May 22 21:41:08 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * c-decl.c (finish_decl): Discard any variable sizes in the decl. + + * pyr.md (mulsi3, adddi3, ...): Use symmetrical predicates in + commutative patterns. + (tsthi, tstqi): Set CC_NO_OVERFLOW + * out-pyr.c (notice_update_cc): Don't do that here for + explicit cc-setting insns. + +Sat May 19 12:41:44 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * tm-i386gas.h (ASM_OUTPUT_ALIGN): Use log as arg to .align. + (ASM_OUTPUT_ALIGN_CODE): Likewise. + +Wed May 16 16:09:47 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * tm-pyr.h (FIXED_REGISTERS, CALL_USED_REGISTERS): + Reserve register lr15 as fixed, for test instructions. + * pyr.md (tsthi, tstqi): Use cvtXw into lr15 rather than test. + + * expr.c (expand_expr): Make sure a volatile value is referenced + even if value is ignored. + + * c-typeck.c (truthvalue_conversion): Result COND_EXPR gets type int. + (invert_truthvalue): Simplify COND_EXPR. + +Tue May 15 16:51:41 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * c-decl.c (complete_array_type): Compensate for wide string constants. + +Mon May 14 15:31:07 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * c-parse.y (combine_strings): Fix errors computing wide string length. + +Sat May 12 15:17:37 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * i386.md (trunc**): Use long move if source is constant. + * out-i386.c (PRINT_REG): Handle CODE == 'k'. + + * ns32k.md (signed bitfield extract): Don't output assembler comment. + +Fri May 11 14:45:06 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * tm-i860.h (ASM_OUTPUT_CASE_LABEL): Align to multiple of 4. + +Thu May 10 23:43:31 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * out-i860.c (single_insn_src_p, strict_single_insn_src_p): + Correct conditions for needing multiple instructions. + (output_delayed_branch): Likewise. + +Tue May 8 13:54:37 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * tm-ultrix.h: New file. + +Mon May 7 18:47:47 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * i386.md (test... recognizers): Output symbolic constant first. + +Sat May 5 12:18:05 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * rtlanal.c (dead_or_set_p): Compare register numbers, not addresses. + +Thu May 3 16:56:43 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * expmed.c (store_bit_field): Maximum size for loading mem struct + into reg comes from the mode of the value to be stored. + Alignment is no restriction if it matches BIGGEST_ALIGNMENT. + Always do the real work in SImode if couldn't use MEM. + (extract_bit_field): Likewise. + + * tm-sparc.h (PRINT_OPERAND): Handle new codes I and U. + * sparc.md (delay slot peepholes): Use them to handle CC_NO_OVERFLOW. + (negated jump recognizer): Likewise. + * sparc.md (addcc and subcc recognizers): Test for validity of + ignoring overflow with ignore_overflow_conditional_p. + * out-sparc.c (ignore_overflow_conditional_p): New function. + + * pyr.md (bitw recognizer): Set CC_NO_OVERFLOW. + +Mon Apr 30 01:39:14 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * stor-layout.c (build_int): Make arg unsigned. + + * cccp.c (macarg1): `\' not special outside strings. + + * c-typeck.c (build_unary_op): In increment ops, + typo checking for ptr to void/function. + Check original type for this and for amount of increment. + +Sat Apr 28 16:43:08 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * c-typeck.c (build_indirect_ref): Error if target is incomplete type. + +Fri Apr 27 13:02:10 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * reload1.c (order_regs_for_reload): Count multi-word pseudos right. + + * flow.c (mark_set_1): Handle nested SUBREG, SIGN_EXTRACT, + STRICT_LOW_PART, etc. Also, always set subreg_p when setting + a bit field, even if modes are same. + +Thu Apr 26 17:52:17 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * cccp.c (handle_directive): Don't pass directive through if no_output. + +Tue Apr 24 13:40:25 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * pyr.md (addsi3): Use general_operand for both inputs. + + * i860.md: Add missing = in some output constraints. + +Mon Apr 23 16:37:21 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * combine.c (subst): When checking reg_last_set, verify nonzero. + + * ns32k.md (ashlhi3): Avoid using %1. + +Sat Apr 21 21:05:51 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * stmt.c (assign_parms): Don't make entry_parm and stack_parm valid. + Leave them explicit stack slots. + (validize_mem): Copy it, don't alter it. + +Thu Apr 19 15:23:51 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * out-sparc.c (find_addr_reg): Avoid using frame pointer. + +Sun Apr 15 13:42:24 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * expr.c (emit_library_call): Precompute reg and partial of all parms, + to do it in proper order. + + * integrate.c (save_for_inline): Copy reg notes after all insns. + + * final.c (final_scan_insn): No block profiling before jump table. + +Sat Apr 14 00:19:47 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * i386.md (tstdf): Clobber reg in SImode, like cmpdf. + (blt, ble): New define_expands. RTL like before except, + for floats, reverse prev compare or test and do bgt/bge. + +Thu Apr 12 21:27:18 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * expr.c (expand_call): New variable argpos counts args in the + order written. For comparison with n_named_args. + + * c-decl.c (duplicate_decls): Preserve DECL_INITIAL from old + function def to new one. + + * cccp.c (macroexpand): Count Newline Space as part of whitespace + sequence when stringifying. + +Tue Apr 10 21:08:06 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * cccp.c (do_line): No error if string follows number without space. + +Mon Apr 9 15:37:11 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * Makefile (install): Turn off x bit on headers and man page. + + * i860.md (cmpeqsf, etc.): Change opcode name to pfeq.ss, etc. + + * tm-m68k.h (PRINT_OPERAND_PRINT_FLOAT): Delete spurious backslash. + + * c-decl.c (store_parm_decls): Don't do storedecls in prototype case. + That was discarding the enumerators already pushdecl'd. + + * tm-m68k.h (NOTICE_UPDATE_CC): Undo last change. + +Sun Apr 8 19:00:09 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * out-m68k.c (output_move_double, standard_68881_constant_p): + Do word-swap when cross-compiling from little-endian machine. + +Sat Apr 7 00:45:49 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * sparc.md (addcc and subcc patterns): Set CC_NO_OVERFLOW. + + * out-mips.c (output_load_immediate): Fix bug for values + between -2**15 and -2**16; don't use addi. + +Thu Apr 5 14:00:41 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * stdarg.h (va_start): Round initial pointer value down + to double boundary. This is to eliminate big-endian adjustment. + + * c-typeck.c (build_c_cast): Reject array types for result. + + * fixincludes: Don't ignore errors when making dirs. + But check whether dir already exists. + +Wed Apr 4 01:59:03 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * c-decl.c (grokdeclarator): Complain if fn defn has `typedef' etc. + +Tue Apr 3 22:09:12 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * expmed.c (store_bit_field): Don't do big-endian adjust twice. + Do this by changing the mode whenever it is done. + Some places must now cope with subregs. + (extract_bit_field): Likewise. + +Fri Mar 30 15:54:43 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * c-decl.c (c_build_type_variant): New function. + (grokdeclarator): Call that, for ARRAY_TYPE only, in fields and vars. + * c-decl.c, c-typeck.c: All calls to build_type_variant use that now. + +Wed May 2 16:34:25 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * tm-sun3.h (CC1_SPEC): Ignore -target. + (WORD_SWITCH_TAKES_ARG): Define it. + * tm-sparc.h (CC1_SPEC): Ignore -target and -dalign. + (WORD_SWITCH_TAKES_ARG): Define it. + +Thu Mar 29 15:34:53 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * final.c (end_final): For basic block profiling, don't output + source file name. Instead, append ".d", and remove ".c". + * gnulib.c (__bb_init_func): New name for __bb_init_function. + Conditionalize on mc68000, not m68k. + Fix other typos. + * Makefile (LIBFUNCS): Add _bb_init_func. + + * xm-sun386i.h (LINK_SPEC): Handle -static. + +Wed Mar 28 16:21:53 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * c-decl.c (duplicate_decls): Preserve DECL_FRAME_SIZE from definition + past subsequent declarations. + + * c-decl.c (xref_tag): If global_binding_level, make nodes permanent. + + * expr.c (expand_call): Handle STACK_BOUNDARY when using push insns. + + * stmt.c (assign_parms): Note how PUSH_ROUNDING affects stack + parm size. + + * tm-mips.h (STRUCTURE_SIZE_BOUNDARY): Changed from 16 to 8. + +Tue Mar 27 14:24:00 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * m68k.md (movsi, movhi, movstricthi, movqi, movstrictqi): + Avoid both clr and st on volatile mem, but only on 68000. + (SImode store 0 recognizer): Likewise. + +Mon Mar 26 15:01:02 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * m68k.md (movqi): Don't use `st' insn on volatile memory. + + * tm-m68k.h (NOTICE_UPDATE_CC): addq and subq do update cc's + even if destination is an address register. + + * cccp.c (discard_comments): Handle backslash-newline. + +Sun Mar 25 20:21:58 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * cccp.c (handle_directive): Discard backslash-newline within <...>. + +Fri Mar 23 00:52:34 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * c-decl.c (grokdeclarator): Warn if array element is incomplete. + + * xm-hp9k320.h (USE_C_ALLOCA): Define if not compiling with GCC. + + * expr.c (emit_call_1): Pass FUNTYPE directly to RETURN_POPS_ARGS. + +Thu Mar 22 22:33:36 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * c-decl.c (get_parm_info): Void parm is special only if no name. + + * loop.c (may_not_optimize): Static var replaces local `may_not_move'. + (strength_reduce): Don't accept those regs as givs. + +Wed Mar 21 17:14:00 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * ns32k.md (stack adjust insn): Don't use cmpd or cmpqd on Sequent. + * tm-sequent.h (SEQUENT_ADJUST_STACK): Define this. + + * Makefile (gnulib): Use OLDAR, not AR. + (OLDAR): New variable. + + * expr.c (expand_call): Don't reuse pending_stack_adjust for argblock + if inhibit_defer_pop. + +Tue Mar 20 02:41:15 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * va-sparc.h: New file, handles changed calling convention. + + * expr.c (push_block): New argument EXTRA. All callers changed. + (emit_push_insn): Use that for the padding when using push_block. + + * ns32k.md (ashlsi3): `return' was missing. + + * tm-sparc.h (FUNCTION_ARG, FUNCTION_INCOMING_ARG): + Only word-aligned BLKmodes can go in registers. + (FUNCTION_ARG_PARTIAL_NREGS): Likewise. + * tm-spur.h (FUNCTION_ARG, FUNCTION_INCOMING_ARG): Likewise. + * expr.c (expand_call): If encounter a stack parm before offset + gets up to zero, make it zero. + * stmt.c (assign_parms): Likewise. + +Mon Mar 19 00:06:35 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * assert.h (__assert) [not __GNUC__]: Rename arg to avoid stringify. + + * gcc.c (main): Handle SIGPIPE. + +Sat Mar 17 14:13:43 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * loop.c (general_induction_var): When adding sub-giv to ARG, + don't produce an add_val that can't be the source of an add insn. + +Fri Mar 16 15:26:41 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * tm-vms.h (NO_DOLLAR_IN_LABEL): Define this. + + * sparc.md (andncc, orncc, xorncc patterns): Delete `%' in constraint. + +Thu Mar 15 22:02:02 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * expmed.c (extract_bit_field, store_bit_field): + When changing mode of a reg to SImode, also do big-endian correction. + Consistently use BYTES_BIG_ENDIAN to decide how bits are numbered. + Fix stray ref to CODE_FOR_extzv in case for extv. + + * c-typeck.c (build_unary_op): Allow function type args to `!', + since they convert to pointers. + + * stmt.c (init_function_start): Set max_structure_value_size to -1. + +Sun Mar 11 18:39:40 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * reload1.c (spill_hard_reg): + Typo: index regs_explicitly_used with regno. + + * cse.c (cse_insn): When replacing constant with reg+const, + don't make a REG_EQUIV note unless there already is one. + + * gcc.c (fatal): Flush spurious arg to delete_temp_files. + + * Makefile (gnulib, stamp-gnulib2): Ignore error in ranlib. + +Sat Mar 10 16:07:27 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * loop.c (other_reg_use_p): New name for only_reg_use_p. + Return 0 if IN == EXPR. + (check_eliminate_biv, strength_reduce): Re-invert the test + using other_reg_use_p. + +Thu Mar 8 02:17:50 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * ns32k.md (movsi, movdi): Handle floating point registers. + + * reload.c (find_reloads_toplev): Do BYTES_BIG_ENDIAN offset + only within a word. + + * stdarg.h: Use _VA_LIST_ as macro to indicate already loaded. + + * tm-alliant.h (FUNCTION_PROLOGUE): Use `linkl' on 68020. + +Tue Mar 6 23:44:15 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * cccp.c (macroexpand): Fix bug in scanning strings for stringify. + +Fri Mar 2 00:27:14 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * out-mips.c (tree_code_name): Declaration deleted. + +Thu Mar 1 22:59:18 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * assert.h (__assert): Don't call abort; use 0 as value. + * gnulib.c (__eprintf): Call abort here. + +Wed Feb 28 13:11:24 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * Makefile (install): When installing $${eachfile}, use basename. + +Fri Feb 23 13:21:27 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * c-parse.y (readescape): For x, avoid overflow when shifting in if. + +Thu Feb 22 19:09:48 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * fixincludes: Delete directories before creating them. + When making internal symbolic directory links, chase + chain of existing links to the end. + + * dbxout.c (dbxout_type): Always use main variant. + +Wed Feb 21 00:25:39 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * Version 1.37.1 released. + + * tm-mips.h (ASM_OUTPUT_ADDR_VEC_ELT and ASM_OUTPUT_ADDR_DIFF_ELT): + Start label names with $. + +Sun Feb 18 13:58:04 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * tm-mips.h (ASM_GENERATE_INTERNAL_LABEL, ASM_OUTPUT_INTERNAL_LABEL): + Start name with $. + + * integrate.c (expand_inline_function): Round up size of parm_map. + +Sat Feb 17 20:56:05 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * tm-hp9k320.h (CPP_SPEC): Remove _INCLUDE__STDC__. + +Sun Feb 11 20:11:25 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * Version 1.37 released. + + * c-decl.c (complete_array_type): In permanent type, add perm nodes. + + * out-i386.c (print_operand_address): Handle a MULT by itself. + +Sat Feb 10 14:35:03 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * ns32k.md (movsf): Convert double constant to float. + +Fri Feb 9 00:02:43 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * c-decl.c (duplicate_decls): Don't lose alignment of OLDDECL. + + * cccp.c (handle_directive): Keep comments by copying them explicitly. + + * cccp.c (rescan): When scanning for open-paren after macro name, + discard comments if appropriate. + +Thu Feb 8 14:19:41 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * c-decl.c (build_enumerator): Error if value outside range of int. + + * tm-hp9k320.h (CPP_SPEC): Define _INCLUDE__STDC__ if not traditional. + * tm-hp9k310.h: Missing file brought back. + +Mon Feb 5 12:49:36 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * reload1.c (spill_hard_reg): Return 1 if reg is explicitly used. + (reload): Cancel dummy reloads using regs subject to spill. + +Sun Feb 4 12:37:00 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * tm-3b1g.h: New file. + * config.gcc (3b1g, 3b1-gas): New alternative. + + * tm-att386.h (ASM_OUTPUT_COMMON): Don't use rounded size. + +Fri Feb 2 17:04:37 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * integrate.c (copy_for_inline): Use real width of rtunion in bcopy. + * emit-rtl.c (copy_rtx_if_shared): Likewise. + + * assert.h (assert) [__STDC__]: Use comma operator to avoid warning. + + * c-decl.c (grokdeclarator): Traditionally change return type float + to double. + + * cse.c (predecide_loop_entry): Give up unless simple jump enters loop. + +Thu Feb 1 02:02:21 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * tm-convex.h (FASCIST_ASSEMBLER, VTABLE_USES_MASK, VINDEX_MAX): + New definitions to control c++ files. + + * reload1.c (inc_for_reload): Forget reg_last_reload_reg + for the reg being inc'd. + + * limits.h (INT_MIN): Define so it has type `int', not unsigned. + (CHAR_MIN, SCHAR_MIN, SHRT_MIN): Put arens around value. + +Wed Jan 31 12:54:07 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * tm-mips.h (FUNCTION_PROLOGUE): Use CONST_OK_FOR_LETTER_P to see + if can update fp in one addiu insn. + + * reload1.c (reload): Reject fixed regs when finding groups to spill. + + * assert.h (assert) [NDEBUG]: Make value nonempty. + (assert) [no NDEBUG]: Split into a version for __STDC__ and one not. + (_assert) [__STDC__]: Pass expression and file separately to _eprintf. + (_assert) [not __STDC__]: Likewise, but implemented differently. + * gnulib.c (__eprintf): Handle 3 args plus format string. + + * tm-i386.h (STACK_BOUNDARY): Define it. + +Sat Jan 27 17:58:30 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * hard-params.c: Use explicit file name to include self. + +Fri Jan 26 01:38:29 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * cccp.c (rescan): Set beg_of_line when string ends at newline. + (skip_quoted_string): Don't swallow newline that ends a string. + (handle_directive): No need to back up here. + Pass LIMIT as second arg to skip_quoted_string. + + * cccp.c (rescan): If traditional, end preproc number after expt sign. + +Thu Jan 25 01:57:34 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * loop.c (general_induction_var): Reject widening multiply. + + * i860.md (andsi3): Truncate xop2 constant to 16 bits. + +Wed Jan 17 12:33:52 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * tm-mips.h (CC1_SPEC): Don't complain about -g. + + * c-typeck.c (build_compound_expr): Delete special case + that ignores expressions without side effects. + + * stor-layout.c (layout_type): Struct requires BLKmode if any field + crosses a word boundary. + + * reload1.c (choose_reload_regs): Refix Sequent problem correctly. + +Tue Jan 16 12:03:42 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * c-parse.y (unary_expr): If sizeof or alignof gets a comma expr + which has array or function type, coerce it to pointer. + + * fold-const.c (combine): Propagate carry when subtracting from 0. + + * fold-const.c (fold): For x++==const, do arith in type of const. + +Mon Jan 15 19:24:04 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * cexp.y (exp): Accept unary +. + +Sun Jan 14 12:18:49 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * fold-const.c (lshift_double, rshift_double, lrotate_double): + (rrotate_double): Don't shift more than width of operand. + +Fri Jan 12 18:50:43 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * recog.c (next_insns_test_no_inequality): Return 1 at end of rtl. + +Thu Jan 11 14:09:47 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * cccp.c (skip_if_group): Skip strings even if -traditional. + (handle_directive): Likewise, when handling copy_command. + + * i860.md (movsf): Ensure F to f is reloaded via r. + +Wed Jan 10 15:03:08 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * Makefile [3b1]: Propose redefinition of CCLIBFLAGS. + + * reload1.c (choose_reload_regs): Break down hairy if expression. + + * loop.c (loop_skip_over): Do nothing if don't find expected compare. + +Sun Jan 7 00:58:06 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * config.gcc: Add i386-mach. + * xm-i386.h: Use built-in alloca if compiling with GCC. + + * optabs.c (emit_cmp_insn): Set CLASS after MODE. + +Sat Jan 6 15:33:32 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * out-mips.c (function_arg, function_arg_advance): + Define typedef for CUMULATIVE_ARGS, and use it here. + + * cccp.c (main): Recognize `.C' for -M. + + * c-parse.y (yylex): Put 0 at end of wide string. + + * tm-mips.h (CC1_SPEC): Don't distort meaning of -O. + +Fri Jan 5 12:12:31 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * gcc.c (link_command_spec): If LIBS_COMPILED_WITH_GCC, gnulib is last. + +Thu Jan 4 23:58:59 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * Makefile (c-parse.tab.o): Add explicit compilation cmd. + +Wed Jan 3 00:27:53 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * Makefile (install): Use nested foreach-loop to expand va*.h. + +Mon Jan 1 19:36:49 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * expr.c (store_one_arg): Round size up for move_block_to_reg. + (expand_call): Round up when emitting USE insns. + * stmt.c (assign_parms): Round size up for move_block_from_reg. + + * reload1.c (alter_reg): Undo big-endian conversion from + assign_stack_local. + +Sun Dec 31 20:10:52 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * tree.h (struct tree_common): Declare `code' as char, not int. + +Thu Dec 28 13:49:43 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * gnulib.c (__fixunsdfsi): Turn large numbers to small for conversion. + + * Makefile (includes): Set variable LIB. Run from `./'. + +Wed Dec 27 18:54:25 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * Makefile (CCLIBFLAGS): Add -O. + (gnulib): Remove -O here. + (HARD_PARAMS_FLAGS): Like CCLIBFLAGS but no -O. + (hard-params, hard-params.o): Use that. + + * loop.c (can_eliminate_biv_p, eliminate_biv): If add_val non zero, + it must be a constant or register. + +Mon Dec 25 00:02:31 1989 Torbj|rn Granlund (tege at zevs.sics.se) + + * tm-pyr.h (FIXUNS_TRUNC_LIKE_FIX_TRUNC): Should not be defined. + The cvtdw instruction causes a trap for floating point values + that are out-of-range for a signed int. + + * out-pyr.c (has_direct_base): Don't accept 0 as a base, if there + is a register displacement. This is a workaround of a bug in + /bin/as. (/bin/as changes things like "cmpw 8(reg),0(reg)" into + "cmpw 8(reg),(reg)", which is invalid assembler.) + +Sun Dec 24 11:51:52 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * expr.c (emit_move_insn): Lossage validating mem addr of constant. + + * varasm.c (record_constant_1): Missing `return' in ADDR_EXPR case. + +Sat Dec 23 10:54:22 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * ns32k.md (extract byte from register): Delete #if conditionals. + Assume 32532 always. + (adjust stack): Likewise. + +Thu Dec 21 10:24:05 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * i860.md (load DF constant to reg): Typo: extra percent sign. + (floatsidf2): Two words of a double were backwards. + + * reload1.c (alter_reg): + Always do big-endian correction on slot address. + + * gnulib.c (__fixunsdfsi): Don't rely on host compiler for unsigned. + + * i386.md (float push recognizers): Don't pop fpreg if not dead. + +Sun Dec 17 12:13:37 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * tm-hp9k320.h (CPP_PREDEFINES): Add __hp9000s300, _HPUX_SOURCE. + +Sat Dec 16 17:49:30 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * loop.c (strength_reduce): When writing insn to init a biv, + update life range of reg used to init it. + + * combine.c (try_combine): Do combine (y = x, x = y). + + * loop.c (strength_reduce): When finding initial value of a biv, + notice assignments to subregs of it, etc. + +Fri Dec 15 00:42:31 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * m68k.md (fpa float and float-trunc): Accept general_operand. + + * integrate.c (expand_inline_function): + Put caller's line number after inline stuff. + Put callee's line number before parm manipulation. + + * If local-alloc assumes a reg does not conflict, + don't use it as dummy reload. + * local-alloc.c (wipe_dead_reg): Add REG_UNSET note. + * reload.c (find_dummy_reload): Check for that note. + + * vax.md (casesi): New pattern for super-trivial cse case. + + * jump.c (jump_optimize): Realize that more things can follow + the NOTE_INSN_FUNCTION_END note. Change in two places, + for optimized and one for unoptimized. + +Sat Dec 9 15:21:07 1989 Richard M. Stallman (rms at ccvi) + + * expr.c (expand_expr): For conversion ops, copy CONST_INT to reg + to avoid lossage on VOIDmode in convert_move or expand_float. + * optabs.c (expand_float): Abort if FROM has VOIDmode. + + * final.c (final_scan_insn): Delete unused label. + +Thu Dec 7 01:42:30 1989 Richard M. Stallman (rms at ccvi) + + * sdbout.c (MAKE_LINE_SAFE): Ensure arg is > sdb_begin_function_line. + (sdbout_begin_block, sdbout_end_block, sdbout_end_function): Use it. + + * jump.c (jump_optimize): Leave block-beg, block-end notes + in old context when swapping two ranges of insns. + (squeeze_block_notes): New function. + + * expr.c (expand_call): For pcc struct, return reg mode is Pmode. + + * c-typeck.c (build_conditional_expr): + Only explicit ints allow predetermined choice. + +Wed Dec 6 19:02:07 1989 Richard M. Stallman (rms at ccvi) + + * toplev.c: Undef FFS after including param.h. + +Tue Dec 5 16:01:18 1989 Richard M. Stallman (rms at ccvi) + + * mips.md (movsf): Use mtc1 where needed. + + * reload1.c (choose_reload_regs): If run out of spill regs, + set must_reuse and try again. + +Mon Dec 4 00:18:24 1989 Richard M. Stallman (rms at ambroise) + + * reload1.c (alter_reg): + Don't set spill_stack_slot_width if from_reg is -1. + + * cse.c (cse_end_of_basic_block): Typos checking NOTE insns. + + * math-68881.h (pow): Add parens around `&'. + + * loop.c (can_eliminate_biv_p, eliminate_biv): + In COMPARE, verify the biv is one of the arguments. + (strength_reduce): When eliminating biv, check for use + in a giv in an address, just as in check_eliminate_biv. + + * stupid.c (reg_order): Make it int, in case reg # is large. + (stupid_reg_compare, stupid_life_analysis): Implement this. + +Sun Dec 3 14:17:36 1989 Richard M. Stallman (rms at ambroise) + + * tm-att386.h (ASM_OUTPUT_LOCAL): Don't generate .lcomm. + Go back to putting the variable in the data section. + + * expr.c (do_jump): Cast XVECLEN to int for subtracting 1. + + * reload.c (decompose): Handle SUBREGs. + + * c-typeck.c (build_modify_expr): Prevent -Wall warning + when we generate a COMPOUND_EXPR for (?:)=. + +Mon Nov 27 15:39:40 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * Makefile [pyramid]: Use CLIB, not ALLOCA, to access libPW.a. + Use -lc explicitly first. + + * pyr.md (SI test recognizer): Fix syntax error, + + * c-decl.c (grokdeclarator): Don't test size of error_mark_node + as type of a field. + +Sun Nov 26 12:36:01 1989 Richard Stallman (rms at apple-gunkies.ai.mit.edu) + + * tm-mips.h (CONST_OK_FOR_LETTER_P): Delete extra paren. + +Wed Nov 22 12:56:41 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * pyr.md (mode conversion peepholes): Set CC_NO_OVERFLOW. + * out-pyr.c (consecutive_operands): Don't expect wrap from reg15 to 16. + + * Makefile: Fix directions for pyramid. + + * tm-mips.h (CONST_OK_FOR_LETTER_P): Define `K'. + (SMALL_INT): Range is 16 bits, not 17. + (SMALL_INT_UNSIGNED): New macro. + * mips.md (andsi3, iorsi3, xorsi3): Use `K', not `I'. + + * mips.md (negsi2): Accept general_operand as input. + +Tue Nov 21 10:57:45 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * mips.md (one_cmpl*): Accept general_operand as input. + +Mon Nov 20 11:18:58 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * expr.c (expand_expr): For MINUS_EXPR, don't explicitly negate int + constant if it is in a mode too wide for host machine int. + + * cse.c (fold_rtx): Simulate negative shift counts. + +Sun Nov 19 14:36:18 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * out-pyr.c (notice_update_cc): Set CC_NO_OVERFLOW in many cases. + + * cse.c (fold_rtx, fold_cc0): Handle float trap. + +Sat Nov 18 00:17:47 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * varasm.c (output_constant): Handle float trap in fprintf. + * toplev.c (float_signal): Don't print message. + * fold-const.c (combine): Print it here. + + * sparc.md (extend patterns): Handle CONST_INT as operand. + + * out-i386.c (singlemove_string): Fix paren error. + +Fri Nov 17 12:19:56 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * expr.c (expand_increment): For pre-increment, copy the rtx to return. + + * c-parse.y (compstmt): There may be implicit decls, so check + and maybe keep the level. + + * tm-mips.h (FUNCTION_PROLOGUE, FUNCTION_EPILOGUE): + Use call_used_regs, not a private copy. + +Thu Nov 16 00:28:29 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * reload1.c: Keep track of paradoxical subregs of each pseudo, + and make extra stack space for their sake. + (reload): Record max size paradoxical subreg for each pseudo. + (scan_paradoxical_subreg): New subroutine for that. + (reload): Make stack slots big enough for that size. + + * tm-i860.h (ASM_DECLARE_FUNCTION_NAME): Define it, + so we can output a no-op before each function. + + * tm-pyr.h (INIT_CUMULATIVE_ARGS): Simplify. + Pass function type to aggregate_value_p. + + * fold-const.c (fold): + For foo++ > const, don't change if foo++ could overflow. + + * loop.c (eliminate_biv): + Fix typo; check both coeffs when comparing givs. + +Wed Nov 15 00:12:59 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * integrate.c (copy_for_inline): Correctly handle RTL type "u". + + * jump.c (delete_insn): Extra test for PREV != 0. + +Tue Nov 14 17:31:08 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * tm-sun3.h (LINK_SPEC): Specify -L to control choice of -lm. + + * tm-pyr.h (INIT_CUMULATIVE_ARGS): + If -fpcc-struct-return, always do the scalar thing. + + * function.c (expand_function_end): Use FUNCTION_OUTGOING_VALUE. + +Sat Nov 11 00:18:54 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * tm-sun386.h (ASM_OUTPUT_COMMON): Use ROUNDED, not SIZE. + (ASM_OUTPUT_LOCAL): Likewise. Also, generate .lcomm + rather than a .data area symbol. + * tm-att386.h: Likewise. + +Fri Nov 10 15:04:15 1989 Richard Stallman (rms at rice-chex) + + * caller-save.c (emit_mult_restore, emit_mult_save): + Improve arithmetic for address to save at. + +Thu Nov 9 00:14:19 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * tm-pyr.h (ASM_OUTPUT_REG_PUSH, ASM_OUTPUT_REG_POP): + Don't use obsolete pushw and popw insns. + (ASM_OUTPUT_ALIGN): Ensure arg in range 2 to 5. + * pyr.md (tstdi): Pattern deleted. + (SImode test recognizer): Output ucmpw if jump is unsigned. + + * out-sparc.c (operands_satisfy_eager_branch_peephole): + Check for moves between FP and non-FP regs; they take two insns. + * sparc.md (eager branch peepholes): Likewise. + (Ordinary delayed branch peepholes): Similar check. + * out-sparc.c (single_insn_extra_test): New subroutine. + +Wed Nov 8 18:19:51 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * combine.c (subst): In (sign_extend:M (subreg:N (and:M .. ) 0)) + insist that constant be positive in mode N. + +Tue Nov 7 23:25:20 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * rtl.h: Undefine FFS in case it was defined by the system. + +Mon Nov 6 14:43:55 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * tm-i860.h, tm-m88k.h, tm-pyr.h, tm-spur.h (INIT_CUMULATIVE_ARGS): + Test aggregate_value_p, not just BLKmode. + + * gnulib2.c (__builtin_saveregs): Moved from gnulib.c. + Code added for mips. + + * pyr.md (conditional branch recognizers): Don't simplify if not -O. + + * out-pyr.c (extend_and_branch): Handle two constant operands. + + * integrate.c (function_cannot_inline_p): Don't inline if alloca used. + +Sun Nov 5 02:59:23 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * Always make a LET_STMT and notes for the top level of a function + if it has any subblocks. + * c-decl.c (struct binding_level): New field keep_if_subblocks. + (poplevel): Obey the new field. + (keep_next_if_subblocks): New variable. + (pushlevel): Use that variable. + (store_parm_decls): Set that variable. + (compstmt): Pass nonzero to expand_end_bindings + for the new kept binding levels. + (kept_level_p): New function. + + * xm-mips.h: Define USE_C_ALLOCA if compiling with CC. + + * tm-alliant.h (CHECK_FLOAT_VALUE): Define this. + + * expr.c (expand_call): Make valreg 0 if passing structure address. + +Sat Nov 4 23:27:02 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * caller-save.c (emit_mult_save, emit_mult_restore): + Test regs for suitability as address before using as temps. + + * cccp.c (make_definition, do_define): Better error checks for name. + +Fri Nov 3 01:05:04 1989 Torbj|rn Granlund (tege at echnaton) + + * pyr.md (tstdi): New pattern. Use 64-bit shift with count zero. + + * pyr-tm.h: -mretd pops args with the retd insn. + + * pyr.md (peep-holes for loop optimizations): Use the R output + format in PRINT_OPERAND, don't use output_branch. + * out-pyr.c: No need for functions output_branch, output_inv_branch. + + * tm-pyr.h (ASM_OUTPUT_ALIGN): Don't truncate alignment to two. + +Wed Nov 1 00:38:27 1989 Torbj|rn Granlund (tege at echnaton.sics.se) + + * out-pyr.c (output_inv_branch): When reversing test operands, ne + remains ne, and eq eq eq. + + * pyr.md: Cleanup output code for compare patterns. + + * pyr.md (return): Adjust frame pointer if + current_function_pretend_args_size != 0. + + * pyr.md (extendsidi2): Use general_operand for the input operand. + + * pyr.md, out-pyr.c: Output shift insns with output_shift. + + * tm-pyr.h, out-pyr.c: Make NOTICE_UPDATE_CC understand how + condition codes are really set. Define flag CC_VALID_FOR_UNSIGNED + with to make it possible not to reset cc after each compare or + test. + * pyr.md: Don't use CC_STATUS_INIT for most patterns. + + * out-pyr.c (already_sign_extended): Cleanup, correct, optimize. + + * out-pyr.c: rename radr_diff to constant_diff. + + * out-pyr.c (movdi_possible): Don't combine moves from memory to + memory, because of possible address aliasing. Don't combine moves + with register destination if the source operands are depending on + the destination of the first move, as in + + movw (pr3),pr3 + movw 4(pr3),pr4. + + * out-pyr.c (consecutive_operands): Handle SUBREG in addition to REG. + + * out-pyr.c (output_move_double): movl of immediate *sign* extends. + +Tue Oct 31 22:51:39 1989 Torbj|rn Granlund (tege at echnaton.sics.se) + + * pyr.md (cmpsi): Don't expand this. It's just slower. + + * out-pyr.c (extend_and_branch): Handle only QImode and HImode. + Flush code specific for SImode. + + * out-pyr.c (extend_and_branch): To make zero extensions to HImode + of constants not crash: + * out-pyr.c (ensure_extended): Call extend_const if it's a + CONST_INT. Don't call extend_const from extend_and_branch. + * pyr.md, out-pyr.md: Use global variable test_mode to determine the + mode of tests and compares. Set in define_expands for tests and + compares. Used in extend_and_branch. + * out-pyr.c: Pass mode between extend_and_branch and ensure_extended. + + * out-pyr.c (extend_and_branch): Accept SUBREG whereever REG is + accepted. + * out-pyr.c (weird_memory_memory): Accept SUBREG whereever REG is + accepted. + +Thu Nov 2 13:02:15 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * gnulib2.c (lshrdi2, and other shifts): Take second arg as long long. + + * out-i386.c (fp_pop_int): Use %L0 in fistp insn. + +Wed Nov 1 00:05:59 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * stmt.c (init_function_start): Init max_parm_reg. + + * varasm.c (compare_constant_1): For ADDR_EXPR, compare symbol name. + (record_constant_1): Likewise. + + * out-sparc.c (output_mul_by_constant): Constant zero is legitimate. + + * caller-save.c (emit_mult_restore, emit_mult_save): + Handle stack addresses which are invalid. + + * cse.c (use_related_value): Don't abort if offset is 0. + +Tue Oct 31 15:08:58 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * config.gcc (pyramid): Set $machine to pyr. + + * Makefile: Change temp file names from tmp-insn-* to tmp-*. + + * expr.c (expand_call): OK_DEFER_POP for is_const was once too many. + +Sun Oct 29 00:53:46 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * c-parse.y (yylex): Prevent warning for numbers that underflow. + + * stmt.c (assign_parms): Convert stack addresses to valid addresses. + (validize_mem): New subroutine. + + * stmt.c (check_for_full_enumeration_handling): Accept enum type + as argument (since was finding it incorrectly). + Delete special case for constant index. + (expand_end_case): Pass enum type; check for constant index. + + * cexp.y (initialize_random_junk): Test DOLLARS_IN_IDENTIFIERS + for nonzeroness. + +Fri Oct 27 16:25:19 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * tm-next.h (__inline): define as macro for old 1.34 Next uses. + +Wed Oct 25 17:59:33 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + * stmt.c: Include recog.h. + +Tue Oct 24 19:23:11 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * combine.c (try_combine): Don't move a volatile asm. + +Mon Oct 23 01:45:34 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * combine.c (try_combine): Don't install a subreg relating two modes + that aren't tieable. + + * gnulib2.c (__fixdfdi): Declare __fixunsdfdi. + + * combine.c: Make uid_cuid an int *. + (combine_instructions): Allocate as such. + * loop.c: Make uid_luid an int *. + (loop_optimize): Allocate as such. + +Sun Oct 22 16:34:28 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * stmt.c (fixup_var_refs_1): New insn before a CALL goes before + the preceding USEs. + +Sat Oct 21 00:51:49 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * out-pyr.c (extend_and_branch): Allow SUBREG like REG. + * pyr.md (mem-reg and reg-mem HI, QI patterns): + Don't match unless one arg is MEM. + + * out-sparc.c (output_fp_move_double): Use ldd only when safe, + on same conditions used for std. + + * Makefile (gnulib): Fix comments for editing for hpux. + +Fri Oct 20 00:27:00 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * out-i386.c (singlemove_string): Handle ordinary constants as input. + + * reload1.c (choose_reload_regs): Arg of HARD_REGNO_MODE_OK + was the pseudo; should be the reload reg. + + * tm-decstatn.h (CPP_PREDEFINES): Add bsd4_2, ultrix, MIPSEL, + host_mips, R3000, LANGUAGE_C, SYSTYPE_BSD. + * tm-mips.h (CPP_PREDEFINES): Add host_mips, R3000, MIPSEB, LANGUAGE_C. + (CPP_SPEC): Remove those from here. + Define __SYSTYPE_*__ always. Define SYSTYPE_* only if not -ansi. + No CPP_SPEC needed for decstation. + Correct typos in option tests. + +Thu Oct 19 18:16:40 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * tm-m68k.h, tm-alliant.h (PRINT_OPERAND): + Don't print :l for address if :w was already printed. + +Wed Oct 18 13:03:52 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * tm-mips.h (FUNCTION_PROLOGUE): Get rid of __0__gcc macro. + Store that value in frame_stack_difference. + (FUNCTION_EPILOGUE): Get rid of __0__gcc macro. + (FIX_FRAME_POINTER_ADDRESS): Use frame_stack_difference. + * out-mips.c (frame_stack_difference): Define here. + + * gcc.c (compilers): Define __GNUG__ if g++. + +Tue Oct 17 01:17:07 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * tm-i860.h (HAVE_PRE_INCREMENT): Undefine this. + + * mips.md (movsf): New alternatives for r registers. + * tm-mips.h (FUNCTION_PROLOGUE): Handle big stack frames. + * out-mips.c (function_arg): Handle mode distinction for floating args. + + * pyr.md (mtstsw pattern): Accept general_operand. + + * i860.md (movsf): New alternatives: allow loading r from F. + Prefer f-reg as reload when moving m from F. + * tm-i860.h (PRINT_OPERAND): Handle CONST_DOUBLE if SFmode. + +Sun Oct 15 19:45:56 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * i860.md (movhi, movqi): Support moves to/from fp regs. + + * sparc.md (cse'd multiply): New pattern for mult. by -1. + + * out-i860.c (load_opcode, store_opcode): Handle DImode and fp reg. + + * expr.c (emit_library_call, expand_call): Make a SEQUENCE for + any needed USE insns and pass them to emit_call_1. + (emit_call_1): Place the passed SEQUENCE immediately before the + generated CALL_INSN even if gen_call made more than one insn. + +Fri Oct 13 00:12:46 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * recog.c (constrain_operands): Add case for `&'. + + * expmed.c (extract_bit_field): With structure reg fetched from mem, + don't put in subreg if mode already correct. + (store_bit_field): Typo: had extzv, wanted insv. + + * stmt.c (expand_function_start): Call init_recog. + +Thu Oct 12 01:48:30 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * cccp.c (macarg1): Count newlines even after backslash. + + * c-decl.c (pushdecl): Don't warn for explicit extern + followed by static. That case is useful for incomplete arrays. + + * tm-sparc.h (SELECT_RTX_SECTION): Test was backwards. + +Wed Oct 11 00:35:25 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * tm-seq386.h (DBX_DEBUGGING_INFO): Override this. + (HARD_REGNO_MODE_OK): Override this. + +Mon Oct 9 01:09:25 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * i860.md (movdi): accept F source in 2nd alternative. + Accept G source in 3rd. + (adddi3, subdi3): Typo in opcode of output. + +Sun Oct 8 01:38:27 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * tm-mips.h (ASM_SPEC): Pass -nocpp to as. + + * c-decl.c (grokdeclarator): Ignore variant differences + when preserving typedef types from being altered. + +Sat Oct 7 00:46:18 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * xm-mips.h: Use __builtin_alloca. + +Fri Oct 6 00:30:42 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * reload.c (find_equiv_reg): Do let xregno be a pseudo reg, + but don't call HARD_REGNO_NREGS in that case. + +Thu Oct 5 00:30:39 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * reload.c (find_equiv_reg): Don't let xregno be a non-hard reg. + Don't do OVERLAPPING_REGNO_P on a pseudo reg number. + + * i386.md (trunchiqi2, etc.): Output %1 with size of destination. + * out-i386.c (PRINT_REG): Support 'b' as CODE. + + * combine.c (try_distrib): Make sure we don't move a reg use + across a store into that reg. + + * reload1.c (order_regs_for_reload): Rate fixed regs at LARGE+2, + and explicitly used regs at LARGE+1. + + * stor-layout.c (build_int): When memoizing, make permanent nodes. + +Wed Oct 4 19:40:37 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * xm-i860.h: Missing file added. + +Mon Oct 2 16:26:33 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * reload1.c (emit_reload_insns): Reject any OLDEQUIV that is + in use in any other reload of this insn. + + * expr.c (expand_call): Don't put on notes for const functions + if there aren't real insns to hold them. + +Sun Oct 1 19:50:59 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * integrate.c (expand_inline_function): Handle PARALLEL in CALL_INSNs + when setting follows_call. + + * i860.md (pfeq, pfgt and pfle patterns): Add f0 as 3rd arg. + + * integrate.c (save_for_inline): Don't delete NOTE_INSN_FUNCTION_END. + +Fri Sep 29 08:56:30 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * tm-next.h (LINK_SPEC): Typo for -Z option. + +Thu Sep 28 12:57:11 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * reload.c (decompose): Handle case of pseudo with no hard reg. + +Wed Sep 27 01:20:36 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * explow.c (round_push): Fix typo: return fast if ALIGN is 1. + + * varasm.c (in_text_section): New function. + * tm-3b1.h (ASM_OUTPUT_SKIP): Use that. + +Tue Sep 26 02:40:23 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * c-typeck.c (commontype): If one arg is error_mark_node, return other. + +Sun Sep 24 00:21:24 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * c-decl.c (poplevel): When popping a local extern decl, + save the TREE_USED bit in the identifier. + * toplev.c (compile_file): Check that, printing "not used" warnings. + + * tree.c (make_node): Always put PARM_DECL in saveable_obstack. + + * Version 1.36 released. + + * genextract.c (main): Pass `insn' as arg to `fatal_insn_not_found'. + + * tahoe.md (casel patterns): Use %@ for operand of .align. + * tm-tahoe.h (PRINT_OPERAND): %@ prints `1'. + * tm-harris.h (PRINT_OPERAND): Redefine it; %@ prints `2'. + + * config.gcc (decstation): New entry. + + * tm-harris.h: New file, using tm-tahoe.h. + + * tm-decstatn.h, tm-mips-bsd.h, tm-mips-sysv.h: New files. + +Sat Sep 23 00:28:14 1989 Alain Lichnewsky (lich at glenlivet) + + * added -Zxxx flag in tm-mips.h. (-Z stands for systype) + + used as -ZSYSV or -ZBSD43 on RISC_OS. I suppose + that at somepoint -ZPOSIX might be required for Ultrix. + + * changed command issued to loader to set -systype and to get + crt1 crtn instead of crt0. + + * changed predefines for cpp to agree with RISC-OS + + * tm-mips.h checks for machine type ( defined(ultrix) == DECSTATION) + so that user does not have to go in and change tm-mips.h anymore + + * cpp defines mips host_mips unix and SYSTYPE_SYSV + or SYSTYPE_BSD43. + +Fri Sep 22 00:31:29 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * pyr.md (andsi3): Flush spurious paren. + + * Makefile (hard-params): Don't use LIBS or LIBDEPS. + + * rtl.c (init_rtl): + Use malloc to allocate the string for format of CONST_DOUBLE. + Don't fail to store in rtx_format. + +Thu Sep 21 00:33:13 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * print-tree.c (dump): Move decl of P in REAL_CST case. + + * fold-const.c (fold): For ABS_EXPR, handle REAL_IS_NOT_DOUBLE. + + * c-convert.c (convert_to_real): Use REAL_VALUE_ATOF to make 0. + + * mips.md (movdi): Handle constant with or without WORDS_BIG_ENDIAN. + For alternative 2, output just 2 store insns, not 3. + + * dbxout.c (dbxout_symbol): Optionally go to .data for + a static file-scope variable. + * tm-vax.h: Define DBX_STATIC_STAB_DATA_SECTION to request this. + + * varasm.c (output_constant, force_const_mem): + ASM_OUTPUT_DOUBLE_INT now takes rtx as argument. + + * gvarargs.h [__NeXT__]: Undefine macros defined by stdardg.h. + Define _VARARGS_H. + + * stddef.h (size_t): Don't define it if _SIZE_T macro is defined. + (NULL): Undef any previous defn. + + * cexp.y (NULL): Don't define if already defined. + + * emit-rtl.c (force_next_line_note): New function. + * stmt.c (expand_function_start): Call that just before returning. + +Wed Sep 20 01:22:16 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * c-parse.y (asm_clobbers): + Allow string concatenation: call combine_strings. + +Mon Sep 18 00:04:06 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * expr.c (expand_call): If calling const function, don't defer + pops for this call. + + * c-parse.y (yylex): When float constant ends in `f', + actually truncate to a single-float. + +Sun Sep 17 01:36:43 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * gcc.c (SWITCH_TAKES_ARG): -A takes an arg. + (link_spec): Inhibit start files when -A. + + * convex.md (call, call_value): Supply dummy arg to RETURN_POPS_ARGS. + + * gnulib2.c (__fixunsdfdi): After removing top half, A can be neg. + (__cmpdi2, __ucmpdi2): Was misusing macros HIGH and LOW-- + use .s.high and .s.low to extract words from long_long. + + * Makefile (gnulib2): Run `./gcc'. + + * Makefile (float.h): Use `make', not `$(MAKE)'. + (hard-params.o): Use `$(srcdir)' in deps as in commands. + + * out-tahoe.c (output_move_double): Handle constant operand 1. + +Sat Sep 16 01:15:24 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * reload1.c (emit_reload_insns): Put death note for input reload reg + even if reload was inherited. + + * out-i860.c (output_block_move): Typo loading size of block. + + * m68k.md (dbra patterns): Do CC_STATUS_INIT. + + * cse.c (fold_rtx): Check GET_MODE_CLASS before floating negate. + +Fri Sep 15 00:39:44 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * combine.c (subst): Don't combine (subreg (mem)) + if subreg's mode is wider than mem's mode. + +Thu Sep 14 04:33:51 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * Makefile (clean): Delete temp files used in making gnulib. + + * tm-next.h (LINK_SPEC): Pass -Z and -seglinkedit options. + +Tue Sep 12 01:06:39 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * stor-layout.c (layout_type): Ignore MAX_FIXED_MODE_SIZE for ints. + + * mips.md (cmpsi + bleu peephole): Should output unsigned insn. + + * expmed.c (store_bit_field, extract_bit_field): If loading mem + into reg for bit field insn, don't use a larger mode than insn wants. + + * Makefile (stamp-gnulib2): Depend on gcc, cc1, cpp to avoid + wrong order of making when parallel. + + * Makefile (float.h): Do use $(MAKE) to run recursive make. + +Mon Sep 11 00:49:11 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * cccp.c (main): Test for missing arg after -o, etc. + + * tm-next.h: Nearly completely new. + + * gcc.c (SWITCH_TAKES_ARG, WORD_SWITCH_TAKES_ARG): Move after config.h. + + * cccp.c: Cast some args to strcpy and strcat. + + * genoutput.c (error): Declare arg S. + + * tm-pyr.h, pyr.md, out-pyr.c, xm-pyr.h: New files. + * config.gcc: New item for pyr. + + * gvarargs.h: If __pyr__, use va-pyr.h. + +Sun Sep 10 00:48:43 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * reload1.c (inc_for_reload): Really return the first of the insns. + + * stor-layout.c (build_int): Memoize size nodes for sizes <= 32. + + * loop.c (check_dbra_loop): Don't reverse a biv that is used + in between its update and the loop endtest insn. + +Sat Sep 9 02:10:49 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * stor-layout.c (genop): Don't use `combine' for nonexplicit constants. + Handle some identity elements, etc., directly. + (layout_basetypes): Function deleted. + (layout_record): Ignore any TYPE_DECLs in the fieldlist. + Don't do PCC_BUTFIELD_TYPE_MATTERS hack on field with ERROR_MARK type. + (layout_union): Delete error check for base types. + Ignore any TYPE_DECLs in the fieldlist. + (layout_type): Copy layout info directly into all variants of type. + Delete unused local `x'. + + * mips.md (movdi): Handle constant source operand. + (movsi): Some output code moved to output_load_immediate. + * out-mips.c (output_load_immediate): New function. + + * config.gcc (iris): Use tm-iris.h and xm-iris.h. + + * integrate.c (copy_for_inline): Copy all nonconstant MEM addresses. + + * tm-3b1.h (ASM_OUTPUT_SPACE): New override defn, to output explicit + bytes of 0 if in text segment. + +Fri Sep 8 19:15:08 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * combine.c (try_combine): Don't do i3dest stuff if i3 isn't a SET. + +Thu Sep 7 00:16:32 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * integrate.c (function_cannot_inline_p): Fn is "not even close" + only if > 3 * max_insns. + + * toplev.c (fatal_insn_not_found): New fn. + * genextract.c (main): Make insn_extract call that fn. + + * integrate.c (expand_inline_function): Don't abort about bad offset + in a parm whose type is error_mark_node. + Make another syntax level to hold parm destructors. + + * tm-mips.h (FUNCTION_PROLOGUE, FUNCTION_EPILOGUE): + Increment push_loc after, not before, each reg save or restore. + When storing reg 9 or 29, use offset tsize-4. + Make tsize larger by 4 initially. + (STARTING_FRAME_OFFSET): -8, not -4. + + * gcc.c (choose_temp_base): Make use of TMPDIR and P_tmpdir + if they exist. + + * toplev.c, gcc.c, cccp.c, gen*.c (fancy_abort): + New function which can be used to replace `abort'. + + * toplev.c (main): Save argv, argc in save_argv, save_argc. + + * jump.c (delete_insn): Always advance NEXT across deleted insns, + in case not optimizing. Fixes setting current_function_returns_null. + + * symout.c: Include stddef.h with <...>. + +Wed Sep 6 00:39:35 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * gcc.c (find_exec_file): Was using `argbuf[0]' where wanted `prog'. + + * combine.c (combine_instructions): Dont call record_dead_and_set_regs + if insn has become a NOTE. + + * reload.c (combine_reloads): Update reload_when_needed. + + * jump.c (delete_insn): If delete label on ADDR_VEC, delete table too. + (jump_optimize): If ADDR_DIFF_VEC label has 1 ref, delete it and table. + + * gunlib2.c (__fixunsdfdi, __floatdfdi): Make the long long, + and/or its two halves, unsigned. + + * reload1.c (reload): When setting double_reg_address_ok, + require it to be offsettable. + * out-sparc.c (output_fp_move_double): Now safe to use std + for all reg+reg addresses. + + * vax.md: Add another simplified-casesi pattern for operand 0 constant. + + * cse.c (fold_rtx): Don't truncate VAL at end if WIDTH is 0. + Don't alter WIDTH for that purpose based on the operands. + + * stmt.c (warn_if_unused_value): && or || is ok if 2nd op has effect. + + * c-parse.y (ALIGNOF unary_expr): Find a larger value if possible. + + * reload.c (combine_reloads): Don't combine an output address reload. + (find_reloads): Call combine_reloads after setting reload_when_needed. + (find_reloads_address): Update OPERAND if copy the operand. + + * cccp.c (macroexpand): Missing arg no error in 1-arg macro if -trad. + +Tue Sep 5 14:12:23 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * reload.c (find_dummy_reload): Don't use the output reg if it is + a fixed reg which can overlap with other regs. + + * cse.c (exp_equiv_p): Two vectors must have same length. + + * tree.def (WITH_CLEANUP_EXPR): Print-name string was wrong. + + * optabs.c (expand_fix): Undo previous change (unsigned conversion). + It doesn't work. + + * gcc.c: Pass -i option to cpp. It takes an arg. + + * cccp.c (cplusplus_include_defaults) [VMS]: Typo in array indices. + + * Makefile (gnulib): Create it in tmpgnulib, then rename at the end. + + * i860.md (movdi from constant pattern): Fix `st' opcode typos. + + * Makefile (hard-params*): Use CCLIBFLAGS, not CFLAGS. + +Fri Sep 1 03:43:50 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * tm-i386gas.h (ASM_OUTPUT_ALIGN): .align arg isn't a log, in gas. + (ASM_OUTPUT_ALIGN_CODE): Align labels, etc. to 4-byte boundary. + + * integrate.c (save_for_inline): Delete NOTE_INSN_DELETED notes. + + * Makefile (clean): Delete dbr and jump2 dumps. + + * Makefile (gnulib, gnulib2): Compile in main dir, not libtemp subdir. + This avoids trouble with -I options, etc. + +Thu Aug 31 15:07:19 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * reload1.c (emit_reload_insns): + Be specific moving REG_DEAD notes to an output reload. + Sometimes move them to output-operand-address reloads. + + * out-sparc.c (output_fp_move_double): Very cautious about std. + Use it only for something visibly aligned, or for an array element. + + * cccp.c (main) [VMS]: Remove dirs and extension from PROGNAME. + (pfatal_with_name) [VMS]: Return VMS system call error code as status. + (cplusplus_include_defaults) [VMS]: Add GNU_GXX_INCLUDE. + + * xm-vms.h (FATAL_EXIT_CODE): Now (44 | 0x10000000). + + * expr.c (do_store_flag): Allow more values of STORE_FLAG_VALUE. + + * gnulib2.c (__fixunsdfdi): Explicitly cast doubles to `long int' + to avoid infinite recursion. + +Wed Aug 30 13:28:54 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * loop.c (skip_consec_insns): Skip NOTEs. + + * loop.c (general_induction_var): If G or V is a nonreplaceable giv, + give up. If G is allocated here, consider it replaceable. + + * stupid.c: Make uid_suid, reg_where_born and reg_where_dead + vectors of ints, not short. + +Tue Aug 29 00:21:13 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * tm-iris.h: Fix typo in formfeed char. + + * out-i860.c (singlemove_string): Add missing `.l' to `st', `ld'. + + * loop.c (general_induction_var): Don't set G from 2nd op. of MINUS, + since that would negate the result. + +Mon Aug 28 00:16:36 1989 Richard Stallman (rms at apple-gunkies.ai.mit.edu) + + * dbxout.c (dbxout_symbol): When we need a pointer type, don't + record it in TYPE_POINTER_TO, lest it not live as long as its target. + + * tm-hp9k320.h (CPP_PREDEFINES): Delete __hp9000s300 and _HPUX_SOURCE. + + * Makefile (gnulib): Deleted stamp-gnulib2 in wrong dir. + (hard-params.o): Copy it into current dir before compiling. + (STAGESTUFF): Include the stamp-*.[ch] files. + +Sun Aug 27 13:59:39 1989 Richard Stallman (rms at apple-gunkies.ai.mit.edu) + + * out-i860.c (output_size_for_block_move): Typo in CC_KNOW_HI_R31. + + * integrate.c (expand_inline_function): Ignore insns to set value reg + if we don't want the value. + + * varasm.c (make_function_rtl, make_decl_rtl): Use DECL_ASSEMBLER_NAME. + + * Makefile (stamp-gnulib2): Don't explicitly delete old members, + just replace them. + + * m68k.md, alliant.md (trunchiqi): Use movew if moving from memory + or from a const_int. + + * integrate.c (expand_inline_function): Set first_parm_offset + later on, after computing the args, in case those args + contain inline function calls. + + * alliant.md (movqi): Like recent change in m68k.md. + +Sat Aug 26 00:26:03 1989 Richard Stallman (rms at apple-gunkies.ai.mit.edu) + + * tm-hp9k320.h (CPP_PREDEFINES): Take out m68k and mc68000. + * tm-news.h (CPP_PREDEFINES): Add mc68000. + +Fri Aug 25 15:37:35 1989 Richard Stallman (rms at apple-gunkies.ai.mit.edu) + + * optabs.c (expand_fix): Can convert to unsigned int + by subtracting 2**(N-1), converting to signed, and adding 2**(N-1). + + * reload.c (find_reloads_address): For out-of-range stack slot, + reload the displacement into a reg. + (find_reloads_toplev): For subreg of a reg with a reg_equiv_address, + turn the whole thing into a memref. + +Thu Aug 24 14:07:03 1989 Richard Stallman (rms at apple-gunkies.ai.mit.edu) + + * c-decl.c (grokdeclarator): If function is declared `extern inline', + set current_extern_inline. + (start_function): In that case, set TREE_EXTERN in function decl. + * toplev.c (rest_of_compilation): In that case, don't really compile. + (compile_file): Don't output such functions at the end either. + + * c-typeck.c (build_function_call): Do set NAME if we have one. + + * Prevent any variability in results of qsort. + * stupid.c (stupid_reg_compare): Compare by regno as last resort. + * global-alloc.c (allocno_compare): Same idea. + * local-alloc.c (qty_compare_1): Same idea. + * reload1.c (hard_reg_use_compare, reload_reg_class_lower): Same idea. + + * cccp.c (macroexpand): If read one arg, but it's whitespace, + consider that 0 args for checking number of args. + Improve plurals in error messages. + + * expr.h (inhibit_defer_pop): New name for current_args_size, + now declared here. + (NO_DEFER_POP, OK_DEFER_POP): Moved here. + * expr.c: Names related to current_args_size renamed. + (clear_current_args_size): Deleted. + * stmt.c (expand_function_start): Init inhibit_defer_pop here. + + * stmt.c (expand_start_stmt_expr): Do NO_DEFER_POP. + (expand_end_stmt_expr): Do OK_DEFER_POP, and don't do deferred pops. + + * Makefile (c-parse.tab.c): Pass -o option to Bison. + +Wed Aug 23 23:14:06 1989 Richard Stallman (rms at apple-gunkies.ai.mit.edu) + + * expmed.c (store_bit_field, extract_bit_field): + Use GET_MODE_WIDER_MODE to scan possible modes for bestmode. + + * Makefile (stamp-gnulib2): Discard error messages from `ar d'. + +Tue Aug 22 00:31:51 1989 Richard Stallman (rms at apple-gunkies.ai.mit.edu) + + * final.c (output_source_line): In COFF, don't output `.ln 0'. + + * Makefile (stamp-gnulib2): Depend on gnulib. For parallel make. + + * stmt.c (uninitialized_vars_warning): Don't crash if DECL_RTL is 0. + + * i386.md (truncdfsf2): Pay attention whether stack top is dead. + +Mon Aug 21 22:02:40 1989 Richard Stallman (rms at apple-gunkies.ai.mit.edu) + + * reload1.c (choose_reload_regs): Don't use regno uninitialized, + in the code that does find_equiv_reg. + +Sun Aug 20 00:06:47 1989 Richard Stallman (rms at apple-gunkies.ai.mit.edu) + + * m68k.md (movqi): Was outputting bad code for areg->mem and mem->areg. + + * explow.c (memory_address): Handle a hard reg in wrong reg class. + + * stmt.c (expand_function_end): Set REG_FUNCTION_VALUE_P in return + reg when returning address of structure value block. + + * integrate.c (save_for_inline): Preserve integrated bit on insns. + +Sat Aug 19 14:20:07 1989 Richard Stallman (rms at apple-gunkies.ai.mit.edu) + + * combine.c (subst): Don't change (subreg:M (mem:N ...)) to + (mem:M ...) if address is mode-dependent. + + * config.gcc: Copy and alter Makefile for any srcdir except `.'. + In that case, make a .gdbinit as well. + + * sparc.md (andcbsi3, iorcbsi3, xorcbsi3): These are not commutative. + + * vax.md (cmpv and cmpzv patterns): Use COMPARE, not MINUS. + +Fri Aug 18 12:24:52 1989 Richard Stallman (rms at hobbes.ai.mit.edu) + + * alliant.md (movqi): Change move to mov in assembler code. + + * integrate.c (expand_inline_function): + Handle args passed in regs and copied to slots reached via arg ptr. + + * out-sparc.c (output_delayed_branch): + Do alter_subreg on operands of delay insn. + + * reload1.c (choose_reload_regs): Look for a reg to share + before one that we won't share. + + * expr.h: Define OPTAB_MUST_WIDEN. + * optabs.c (expand_binop): Handle that case. + * expmed.c (expand_shift): Use that when widening lshift to ashift. + + * optabs.c (emit_cmp_insn): Use CONST0_RTX, not individual vars. + + * gnulib2.c (lsh*di3, ash*di3): Return right away if count is zero. + Otherwise tried to shift by 32. + Also replace constant 32 by something symbolic. + + * final.c (output_source_line): Output line number in COFF + even if wrong file. + +Thu Aug 17 15:16:34 1989 Richard Stallman (rms at hobbes.ai.mit.edu) + + * Makefile (version.o): Make this a target; specify source file. + (obstack.o): Likewise. + + * config.gcc (i860): New alternative. + + * i860.md (movstrsi): Record the alignment as operand 3. + Renumber following (internal) operands. + * out-i860.c (output_block_move): Rewrite as in out-sparc.c. + (output_size_for_block_move): Likewise. And don't + subtract alignment from the size. + +Wed Aug 16 13:27:12 1989 Richard Stallman (rms at hobbes.ai.mit.edu) + + * loop.c (combine_movables): Don't combine zero-extend + registers that live outside the loop. + + * integrate.c (expand_inline_function): Use copy_to_mode_reg + to set up this_struct_value_rtx, to handle sums right. + + * Makefile: Use $(srcdir) in bison output files used as deps. + Supply some missing deps. + (*.info, doc): *.info files go in srcdir. + +Tue Aug 15 00:11:12 1989 Richard Stallman (rms at hobbes.ai.mit.edu) + + * i860.md, tm-i860.h, out-i860.c: New files. + + * c-decl.c (duplicate_decls): Fix bug determining whether NEWDECL + is a definition or just a decl. + Combine code to preserve various things from old definition + through a declaration. + + * config.gcc: Scan all args at beginning, setting variables. + Arg of form -srcdir=... sets srcdir explicitly. + srcdir now doesn't contain a slash, and is used with a slash. + + * Makefile (install): Copy header files and gcc.1 from srcdir. + But copy float.h from current dir. (Remove that from USER_H.) + (various): Use new variable INCLUDES to get the -I options. + Add -I. at the beginning of these. + (gnulib, gnulib2): Likewise, use SUBDIR_INCLUDES. + Also, get source file from srcdir. + Also, depend on $(CONFIG_H). + (alloca.o): Get alloca.c from srcdir. + + * reload1.c (emit_reload_insns): Bug in last change: + don't fail to set this_reload_insn. + + * Makefile (Bison rules): Specify $(srcdir) for target and source. + (Explicit C rules): Specify $(srcdir)/ for source in commands. + Use sed to eliminate `./' in normal case. + (insn-*.c): Use $(srcdir) to run move-if-change. + + * config.gcc: Check . and .. for the sources. + If in .., use that when making links. + Also, copy Makefile, alter srcdir in it, and add a VPATH. + + * stmt.c (expand_end_case): When converting CONST_INT index + to an INTEGER_CST, sign-extend if signed type. + +Mon Aug 14 13:51:08 1989 Richard Stallman (rms at hobbes.ai.mit.edu) + + * c-decl.c (duplicate_decls): Warn for qualifier mismatch + only if pedantic; don't consider it a type mismatch. + Merge the qualifiers of the two decls if the types match. + + * expmed.c (store_bit_field): For insv, memref displacement + always counts in bytes, regardless of unit fetched. + When checking predicate of op0, accept any mode. + + * optabs.c (expand_float): One call to can_float_p had args backwards. + + * loop.c (check_dbra_loop): Set the JUMP_LABEL of the new jump insn. + Increment label's use count rather than storing 2. + + * Makefile: Instead of $<, which fails in certain makes, + use $@ and then substitute in the name with sed. + + * out-sparc.c (output_scc_insn): Handle CC_REVERSED for ordered tests. + Use orcc insns to store the result and set cc's for it. + + * sparc.md (scc combination patterns): + Use operands[0] as basis for recorded cc value. + + * gnulib2.c (floatdidf, fixdfdi, fixunsdfdi): New functions. + + * gnulib.c (floatdidf, fixdfdi, fixunsdfdi): Deleted. + (union longlong, union double_di): Deleted. + (HIGH, LOW): Deleted. + These were deleted because most did not handle full range of DI + and they didn't use the right calling convention for DI. + +Sun Aug 13 13:06:45 1989 Richard Stallman (rms at hobbes.ai.mit.edu) + + * c-typeck.c (comptypes): Qualifiers must match. + (Was already true for scalars.) + Also, array elt qualifiers must match. + + * tm-apollo68.h (STRUCT_VALUE): Make it 0. + (This was done before and lost.) + * out-i386.c (function_epilogue): Use ret $4 to pop structure address. + (This was done before and lost.) + + * out-i386.c (call_top_dead_p): Don't fail to check + the rtx code of the insns themselves. + (This was done before and lost.) + + * out-sparc.c (output_block_move): If align is 8, make it 4. + + * typeclass.h: New file. + * expr.c: Include it. + (expand_builtin): Use those codes in __builtin_classify_type. + + * Makefile (all, lang-c): Reinstall gnulib2. + + * Makefile (gnulib2): Don't give up if `ar d' fails. + + * expr.c (emit_library_call): New 2nd arg NO_QUEUE. + All callers changed to pass it. + * optabs.c (expand_binop, expand_unop): Don't call emit_queue. + Instead, pass 1 for NO_QUEUE to emit_library_call. + +Sat Aug 12 12:05:22 1989 Richard Stallman (rms at hobbes.ai.mit.edu) + + * reload1.c (emit_reload_insns): Decision for where to put input + reload insn is now common to ordinary case and auto-increment. + Likewise, updating these positions afterward. + + * stmt.c (assign_parms): Treat last named arg as nameless. + * expr.c (expand_call): Likewise. + + * explow.c (copy_to_mode_reg): Use force_operand for PLUS or MULT. + (copy_addr_to_reg): Use copy_to_mode_reg. + + * expmed.c (store_bit_field): Handle case where insv rejects memrefs. + + * tm-convex.h (ASM_OUTPUT_ALIGN): Magic to handle the fact + that this is not called when LOG is 0. + +Fri Aug 11 16:39:51 1989 Richard Stallman (rms at hobbes.ai.mit.edu) + + * emit-rtl.c (get_lowpart): For multi-word, in error check, + test the unit size of the containing mode. + + * cccp.c (macroexpand, dump_all_macros): Return void. + (macroexpand): Cast sprintf arg to char*. + (error, warning, error_with_line): Declare first arg char*. + +Thu Aug 10 21:42:13 1989 Richard Stallman (rms at hobbes.ai.mit.edu) + + * expr.c (expand_call): + Use force_operand to copy arithmetic to register. + + * dbxout.c (dbxout_symbol): Go back to N_FUN for const variable. + + * integrate.c (expand_inline_function): Use proper machine mode + for a structure value in memory at address passed by caller. + +Wed Aug 9 15:21:36 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * config.gcc: Delete unnecessary variable assignments in case stmt. + (isi68-nfp): New alternative. + + * combine.c (try_combine): Don't substitute for a register + which is being explicitly clobbered. + + * This change was requested for C++. + * varasm.c (decode_reg_name, make_decl_rtl): Arg ASMSPEC now char *. + * toplev.c (rest_of_decl_compilation): Likewise. + * c-decl.c (finish_decl): Change call to rest_of_decl_compilation. + + * tree.h (struct tree_decl): Pack machine_mode into 8 bits. + + * explow.c (memory_address, copy_to_reg): + Use force_operand to copy arithmetic to register. + + * tm-isi68-nfp.h: New file. + * tm-isi68.h: Allow overriding TARGET_DEFAULT, and let that + change CPP_SPEC and LINK_SPEC. + (ASM_FILE_START): No `.globl fltused' if soft-float. + +Tue Aug 8 21:50:52 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * varasm.c (const_hash): For constructor, mask TREE_TYPE to HASHBITS + bits and take modulo, so we don't get negative numbers. + + * varasm.c (record_constant_1, compare_constant_1): + Record and compare the width of an integer. + + * varasm.c (assemble_function, assemble_variable, get_or_assign_label): + (force_const_mem): Don't call ASM_OUTPUT_ALIGN if boundary is 1. + + * c-decl.c (duplicate_decls): Consider const and volatile as part of + type when checking for match and when installing new type into OLDDECL. + + * expr.c (do_store_flag): Make sure target fits operand predicate. + Also, omit the AND insn when true-value is 1 + and the mode we get is wider than the one we want. + + * genrecog.c (main): Make insn-recog.c include real.h. + +Mon Aug 7 16:58:56 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * genemit.c (main): Define `operands' as `emit_operands', + not `recog_operands'. + + * reload1.c (emit_reload_insns): Don't copy back a dead output reg. + +Sun Aug 6 13:56:53 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * sdbout.c (plain_type_1, sdbout_one_type): Use the main variant. + (sdbout_type_fields): No need to check TREE_ASM_WRITTEN here, + since sdbout_one_type does that. + + * expr.c (do_store_flag): Ensure the CLOBBER doesn't clobber an input. + + * fold-const.c (fold_convert): Attempt to avoid overflow + when converting real to integer. Use unsigned conversion for + low part; always convert as positive and then change sign; + subtract high part before converting low part. + Also, check for real values out of range for chosen int type; + warn and do not convert. + + * tm-hp9k320.h (CPP_SPEC) [not HPUX_ASM]: Don't define mc68000 here. + (CPP_PREDEFINES): Remove mc68k, add m68k and mc68000. + [HPUX_ASM]: Define CPP_SPEC here as in the other case, + but add __HPUX_ASM__ to each alternative. + + * tm-m68k.h (FUNCTION_EPILOGUE): Call new hook FUNCTION_EXTRA_EPILOGUE. + * tm-altos3068.h (FUNCTION_EXTRA_EPILOGUE): Define it. + + * Makefile: Use $< wherever appropriate. + Also put definitions of customization vars before the comments + saying how to override them. + +Sat Aug 5 14:15:39 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * i386.md (sne): Typo in opcode name. + + * tree.h (struct tree_identifier): Delete redundant/unused error_locus. + +Fri Aug 4 00:04:10 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * varasm.c (const_hash, compare_constant_1, record_constant_1): + Compare types only for record constructors, not for array constructors. + + * dbxout.c (dbxout_parms): When outputing parm from home in local slot, + with address from the RTL, don't do big-endian correction on it. + + * c-typeck.c (build_unary_op): Do default conversion for unary +. + + * cccp.c (rescan): Accept comments between macro and its args. + + * c-decl.c (lang_decode_option): -traditional implies writable strings. + + * cccp.c (trigraph_pcp): Make warning msg more accurate. + + * c-typeck.c (c_expand_asm_operands): Delete the default promotion + which was inserted mysteriously since 1.35. + + * global-alloc.c (global_conflicts): Allocate regs_set only once. + Make it twice as big since clobbers are stored twice. + + * sparc.md (block move patterns): Record and use alignment operand. + * out-sparc.c (output_block_move): Get alignment from there. + (output_size_for_block_move): Greatly simplified. + + * tm-i386v.h (PCC_BITFIELD_TYPE_MATTERS): Define it. + + * stor-layout.c (layout_record): Anonymous bitfields don't affect + overall structure alignment, in PCC_BITFIELD_TYPE_MATTERS case. + + * loop.c (strength_reduce): Prevent hard reg from becoming biv or giv. + + * combine.c (subst): Simplify (eq (neg ...) (const_int 0)). + +Thu Aug 3 13:08:05 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * cse.c (fold_rtx): For (op var const) special cases, also check + for constant as first argument. + + * c-decl.c (pushtag): For global_binding_level, make permanent nodes. + + * expr.c (do_store_flag): Put the CLOBBER before the comparison. + + * expr.c (emit_push_insn): Conditionalize recent changes + on no FIRST_PARM_CALLER_OFFSET, so they don't happen on sparc. + + * out-sparc.c (gen_scc_insn): + Don't be confused by CLOBBER emitted by do_store_flag. + Skip past such insns looking for last_insn. + Don't alter last_insn; instead, patch it to a NOTE and emit new insn. + + * varasm.c (const_hash, compare_constant_1, record_constant_1): + For a CONSTRUCTOR, hash/compare/record type as well as elts. + + * cse.c (cse_insn): July 18 change was wrong. + Now, invalidate at the beginning any regs explicitly clobbered + so they will not be substituted for if they appear as inputs. + * sparc.md (movstrsi): Copy addresses to temp regs, then use them. + + * loop.c (record_giv): When comparing life spans for setting + ->forces, use luids consistently, not uids. + + * sparc.md (ashlsi3, ashrsi3, lshrsi3): Truncate constants mod 32. + +Wed Aug 2 17:50:30 1989 Richard Stallman (rms at sugar-bombs) + + * mips.md (patterns to move a subreg): Deleted. + +Sun Jul 30 19:23:13 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * gcc.c (process_command): Skip `-b' like `-B', in 2nd scan. + + * xm-sunos4.h: Deleted. + * tm-sparc.h, tm-sun3.h: Define LINK_SPEC here instead. + * tm-sun4os3.h: Undef it here. + * tm-sun3os3.h, tm-sun3os3nf.h: New files to undef LINK_SPEC. + * config.gcc: Use those new files where needed. + + * config.gcc: Delete sun3-fpa and sun3-os4-fpa. + * tm-sun3-fpa.h: Deleted. + + * cccp.c (do_include): Mention even non-ex files for -M. + + * out-mips.c (addr_compensate): Handle HImode. + * mips.md (Set HI from subreg of SI rule): + Allow operand in memory. + + * mips.md (cmpqi, cmphi): Patterns deleted. + (cmpsi, cmpsf, cmpdf): Change predicates to register_operand. + + * cexp.y (rule for ?:): Result is unsigned if either operand is. + + * expr.c (emit_push_insn): If PARTIAL > 0, load the partial regs + at the end, in case the rest of the push does a function call. + + * reload1.c (alter_frame_pointer_addresses): + After altering a PLUS, re-fetch CODE before scanning subexps. + + * stmt.c (assign_parms): Don't copy the arg pointer value + if it is also the frame pointer. If we do copy it, + inhibit REG_EQUIV notes for parms copied into pseudo regs + + * integrate.c (copy_for_inline, copy_rtx_and_substitute): + Set up filename and lineno fields of copy of ASM_OPERANDS. + +Sat Jul 29 18:58:49 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * integrate.c (expand_inline_function): Handle struct-value-addr + passed in memory just like that passed in reg: + in either case, translate the pseudo-reg made in + expand_function_start. + (function_cannot_inline_p): Permit inlining in that case. + But reject it if using pcc-style return convention. + + * stor-layout.c (layout_type): Consider STRICT_ALIGNMENT + for ARRAY_TYPE just as for RECORD_TYPE. + +Wed Jul 26 12:54:59 1989 Richard M. Stallman (rms at mipos3) + + * cse.c (fold_rtx): If WIDTH is zero for binary operator, + look at the modes of the original operands. + + * cse.c (cse_insn): Set prev_insn_explicit_cc0, for (set (cc0) INT). + (predecide_loop_entry): Likewise. + (fold_rtx): Look at it, for (if_then_else (cc0) ...). + + * expr.c (expand_builtin): Pass back return value from + __builtin_saveregs. + + * stmt.c (assign_parms): Allow arg pointer reg not to be fixed. + If it is not, copy it to a pseudo reg and use that later on. + +Tue Jul 25 15:42:04 1989 Richard M. Stallman (rms at mipos3) + + * expr.c (expand_builtin): New builtin __builtin_classify_type. + * tree.h, c-decl.c: Additional support. + + * flow.c (mark_used_regs): Treat arg pointer like stack pointer. + + * expr.c (emit_library_call): + Pass (tree)0 as TYPE arg to FUNCTION_ARG, etc. + +Mon Jul 24 11:18:10 1989 Richard M. Stallman (rms at mipos3) + + * loop.c (regs_match_p): Fix braino. + + * integrate.c (copy_for_inline, copy_rtx_and_substitute): + Make ASM_OPERANDS constraint vector be shared like operand vector. + + * xm-iris.h: New file. + + * Makefile (stage4): New target. + + * gnulib2.c (badd, bsub, bmul, bdiv): If want long value from + arithmetic, widen the operands first. + (__div_internal aka bdiv): Rename to __bdiv. + + * sparc.md (seq combination patterns): Fully initialize cc_status. + + * expr.c (emit_push_insn): Like July 19 change, for BLKmode. + + * stmt.c (expand_function_end): Stack-restore for alloca + is now done after the return_label. + + * loop.c (scan_loop): Set MAYBE_NEVER for conditional jump to loopbeg. + + * integrate.c (copy_rtx_and_substitute): Allow mapping of hard regs. + (expand_inline_function): Always create parm_map. + Handle structure value that way if nec. even if no parms. + Otherwise, find the pseudo used in the function to hold the + structure address, and map it to a new pseudo. + + * expr.c (expand_call): + Use mark_addressable to make FNDECL addressable. + * c-typeck.c (mark_addressable): No longer static. + + * cse.c (cse_insn): Modify last change: don't canon_reg + for hard regs inside clobbers. + + * expr.c (expand_assignment): ALIGN arg to store_field comes from + the structure, not from the value stored. + +Fri Jul 21 16:23:45 1989 Richard M. Stallman (rms at mipos3) + + * stmt.c (warn_if_unused_value): Don't warn for a cast + around a MODIFY_EXPR. + + * tm-hp9k320.h (PCC_STATIC_STRUCT_RETURN): Undefine it. + (CPP_PREDEFINES): Add some. + + * combine.c (simplify_and_const_int): + Simplify (and (ashiftrt (zero_extend FOO) N) M). + + * optabs.c (expand_binop): When widening, + for some operations we need not actually extend. + +Thu Jul 20 16:16:35 1989 Richard M. Stallman (rms at mipos3) + + * Makefile (insn-emit.o): Depend on insn-codes.h. + + * stmt.c (check_for_full_enumeration_handling): + Handle all cases for TYPE_NAME of enum type. + +Wed Jul 19 17:00:39 1989 Richard M. Stallman (rms at mipos3) + + * fold-const.c (fold_convert): Don't fail to force_fit_type. + + * expr.c (emit_push_insn): When pushing only part of scalar on stack, + adjust stack offset not to count the words not pushed. + + * stmt.c (expand_function_end): Always put return structure address + in return register. + + * c-typeck.c (process_init_constructor): Assume 0 for nameless field. + + * recog.c (general_operand, memory_operand): + Check validity of mem address using the mode of the MEM. + + * fixincludes: When calling egrep, use redirect, not -s. + +Tue Jul 18 11:18:55 1989 Richard M. Stallman (rms at mipos3) + + * Makefile (bootstrap*): Pass value of libdir down. + + * cse.c (cse_insn): Do canon_reg on any CLOBBERs and USEs. + + * cse.c (cse_insn): Don't use no_labels_between_p to check + for jump to following label; find following label and compare. + + * combine.c (try_combine): Don't substitute into subreg(x)=y + if modes of x and y are not tieable. + + * out-i386.c (call_top_dead_p): Don't fail to check + the rtx code of the insns themselves. + + * i386.md (tstsf, tstdf): Don't discard TOS if not dead. + + * stupid.c: Don't use regs with PRESERVE_DEATH_INFO_REGNO_P + for pseudos which live across jumps or labels. + (stupid_life_analysis): Update last_jump_suid, last_label_suid. + (stupid_mark_refs): Use those to set reg_crosses_blocks. + (stupid_find_reg): Check that data, passed from stupid_life_analysis. + + * toplev.c (main): Avoid using caddr_t. + + * mips.md (inverted bgeu peephole): Typo in opcode. + +Mon Jul 17 12:29:45 1989 Richard M. Stallman (rms at mipos3) + + * i386.md (mulb patterns): Turned off due to assembler bug. + + * rtl.c (read_name): Use 0, not NULL, for character. + + * alliant.md (movqi): Typos in mov opcodes. + + * tm-sparc.h, tm-spur.h (CONST_DOUBLE_OK_FOR_LETTER_P): + Use CONST_DOUBLE_LOW, etc. + + * stmt.c (expand_function_end): Check value of EXIT_IGNORE_STACK, + not just whether defined. + + * i386.md (seq, etc.): New patterns. + * expr.c (do_store_flags): If result is wrong mode, + ensure rest of bits are cleared. + Before storing low part of TARGET, emit a CLOBBER for it. + + * i386.md (load address): Use an immediate add if possible. + + * i386.md (ashlsi3): Don't generate leal; shift is faster. + + * Now struct_value_rtx is 0 to treat it as a parm. + * expr.c (expand_call): Implement that. + * integrate.c (expand_inline_function): Don't freak out. + * tm-apollo68.h (STRUCT_VALUE): Make it 0. + + * On 386, called function must pop the structure value address. + * tm-i386.h (STRUCT_VALUE): Don't change this. + Address is now pushed but not counted as a parm. + * out-i386.c (function_epilogue): Use ret $4 to pop that address. + * output.h: Declare the current_function_... variables. + * final.c: Include output.h. + + * varasm.c (make_decl_rtl): Insert missing `else', validating reg decl. + +Fri Jul 14 14:12:17 1989 Richard M. Stallman (rms at mipos3) + + * out-sparc.c, out-spur.c (output_move_double): + Fixed typo, addreg0 => addreg1. + + * c-decl.c (lang_decode_option): Handle -fshort-enums. + (finish_enum): In that case, give enum minimum number of bytes. + * toplev.c (main): Default flag_short_enums. + * toplev.c, flags.h (flag_short_enums, flag_signed_char): + Define those flags here, not in c-decl.c and c-tree.h. + + * i386.md (mulqi3, umulqi3): New patterns. + + * c-convert.c (convert_to_integer): Tighter restrictions on + distributing truncation through max, min, and multiplication. + If operands were extended from unsigned, make the operation + unsigned. + + * cccp.c (main): Fix bug where #include <...>, when -I- was used, + failed to search standard dirs and/or searched some dirs + intended only for #include "...". + + * tm-mips.h (FUNCTION_PROLOGUE,FUNCTION_EPILOGUE): + Increment push_loc after store or load, not before. + +Thu Jul 13 11:24:30 1989 Richard M. Stallman (rms at mipos3) + + * emit-rtl.c (add_insn_after): Don't update last_insn + if insn is in a sequence. Instead, update end of sequence. + + * stmt.c (fixup_var_refs): Update end of stacked sequence. + + * stmt.c (expand_function_start): Set result rtl before assign_parms. + + * optabs.c (emit_unop_insn): Set PREV_INSN after preliminaries. + + * stmt.c (warn_if_unused_value): Do CONVERT_EXPR like NOP_EXPR. + + * stmt.c (expand_function_start): Make sure parm_birth_insn + is a NOTE. + + * Makefile (clean): Delete tmp-insn-*. + +Wed Jul 12 14:24:12 1989 Richard M. Stallman (rms at mipos3) + + * i386.md (mulqi3): Restrict operand 2 to `q' reg. + + * reload1.c (choose_reload_regs): Check HARD_REGNO_MODE_OK + for regs to be inherited. + Also check HARD_REGNO_MODE_OK at end for modes of both + reload_in and reload_out as well as reload_mode. + + * Makefile (maketest): Update for config subdir. + +Tue Jul 11 16:29:57 1989 Richard M. Stallman (rms at mipos3) + + * integrate.c (copy_decl_tree): Copy TREE_USED of each LET_STMT. + + * make-cc1.com: Changes by Angel Li. + Define variables CC, CFLAGS, LDFLAGS, LIBS. + Use LIBR library, not LIB. Specify a /INC in CFLAGS. + Use MCR to run the gen* files. Add some comments. + * make-cccp.com: Similar. + * config-gcc.com: New file. + + * stmt.c (assign_parms): Compute parm alignment from passed type. + + * c-typeck.c (actualparameterlist): Instead of truncating + and then promoting for PROMOTE_PROTOTYPES, go straight to int. + + * c-parse.y (setspecs): Save old current_declspecs on a stack. + (decl, component_decl): Restore from that stack. + +Wed Jul 5 15:01:00 1989 Richard Stallman (tiemann at yahi) + + * tm-aix386.h, xm-aix386.h: New files. + + * loop.c (check_dbra_loop): Handle either test or compare + for insn two before loop end; detect and reject anything else. + + * expr.c (expand_call, expand_builtin): If alloca is done, + set current_function_calls_alloca. + * stmt.c (expand_function_end): If so, generate code to save and + restore the stack pointer, if not EXIT_IGNORE_STACK. + + * ns32k.md (movsi): Fixes for moving from fp or sp. + + * tm-mips.h (ASM_OUTPUT_ASCII): Start new .ascii every 256 chars. + +Tue Jul 4 11:01:00 1989 Richard Stallman (tiemann at yahi) + + * reload1.c (choose_reload_targets): Don't depend on + reload_spill_index when cancelling invalid inheritance. + Also, abort if trying to preserve death info + on a spill reg used in operand addressing. + + * fold-const.c (fold): Don't fold "foo"[n] here. + * expr.c (expand_expr): Do it here. + Handle wide strings correctly. + + * i386.md (movsf,movdf): Disallow mem-mem moves. + Enable mem-to-reg moves. + + * c-decl.c (finish_{struct,enum}): Warn if inside parm decls. + (in_parm_level_p, declare_parm_level): Record when inside. + * c-parse.y (parmlist, parmlist_or_identifiers): Call + declare_parm_level. + + * c-decl.c (parmlist_tags_warning): Revise warning message text. + + * tm-hp9k320.h (ASM_SPEC): Pass -V switch to assembler. + + * tm-sun386.h (ASM_START_FILE): Truncate filename to 14 chars. + + * c-typeck.c (decl_constant_value): Use only literal values. + +Sat Jul 1 17:29:54 1989 Richard Stallman (tiemann at yahi) + + * integrate.c (copy_rtx_and_substitute): Don't make nested SUBREGs. + + * stmt.c (expand_function_start): Set new global + current_function_returns_pointer. + + * stmt.c (get_frame_size): Return the size, not the offset. + * integrate.c (expand_inline_function): When setting FP_DELTA, + compensate for this change. + * tm-alliant.h,tm-mips.h,tm-sparc.h,tm-tahoe.h + (FUNCTION_PROLOGUE,FUNCTION_EPILOGUE): Compensate. + + * out-mips.c (function_arg): Return 0 for BLKmode. + + * tm-mips.h (FUNCTION_INCOMING_ARG): Delete; no register windows. + * out-mips.c (function_inarg): Delete; no longer used. + + * mips.md (addsi3): Use register_operand for operands 0,1. + (load address): New pattern, following movsi. + (fix_trunc*): Use trunc insn, not cvt. + (cmpfs + bgt peephole): Operands were backwards in template. + + * gcc.c (main): Record in explicit_link_files which input files go + straight to linker. If linker is not run, complain about them. + (execute): Increment execution_count, to show we were called. + + * gcc.c (validate_all_switches): Check ASM_SPEC, CC1_SPEC, etc., + so we find all switches that could be valid. + + * varasm.c (output_constructor): Position fields according to + DECL_OFFSET; don't try to compute alignment here. + + * tm-sparc.h (PCC_BITFIELD_TYPE_MATTERS): Define this. + + * reload1.c (emit_reload_insns): Fix stupid error in last change. + + * c-decl.c (duplicate_decls): If redeclaring builtin, give error is + type mismatched; otherwise warn only if -W. + + * jump.c (jump_back_p): Verify that PREV is not null. + +Mon Jun 26 13:50:28 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * reload1.c (choose_reload_regs): If number of reloads needing + spill regs exceeds n_spills, don't inherit any reloads. + + * sdbout.c (sdbout_record_type_name): Dumb error in last change. + + * reload1.c (emit_reload_insns): Extend last change: don't use + equiv reg if reg is in use at same stage of insn, either. + +Sun Jun 25 00:00:56 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * reload1.c (emit_reload_insns): Don't use an equivalent register + to reload from, if that register was used for reloading + earlier in this insn. + + * sdbout.c (sdbout_record_type_name): Handle a TYPE_DECL as the + type name. Get rid of TYPE_TAG_NAME as separate macro. + + * optabs.c (emit_cmp_insn): Args to memcmp are addresses, not blocks. + + * reload1.c (choose_reload_regs): Typo, clearing reload_override_in. + + * tm-i386.h: Add register classes SIREG and DIREG. + (enum reg_class, REG_CLASS_NAMES): Define class names. + (REGNO_REG_CLASS, REG_CLASS_CONTENTS): Define their contents. + (REG_CLASS_FROM_LETTER): Define letters `S' and `D'. + +Sat Jun 24 00:17:16 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * c-decl.c (keep_next_level): New function. + (struct binding): New slot `keep' says make a LET_STMT for this level. + (pushlevel, poplevel): Implement that. + * c-parse.y (stmt exprs): Call keep_next_level. + + * sdbout.c (plain_type_1): Handle REFERENCE_TYPE, METHOD_TYPE. + Correct for size less than 0. + (plain_type): Correct for size less than 0. + + * global-alloc.c (mark_reg_set): For CLOBBERs, call mark_reg_clobber. + + * reload1.c (order_regs_for_reload): Among regs explicitly used, + prefer those used less often. + + * reload1.c (choose_reload_regs): If we find alternate place + to reload from, verify it after all reloads assigned. + New variable reload_override_in used for this. + + * combine.c (record_dead_and_set_regs): Look inside SIGN_EXTEND and + STRICT_LOW_PART for place being set. + (subst): When using reg_last_set to find what a register contains, + verify the entire register was set. + + * toplev.c (rest_of_decl_compilation): Report invalid register name. + +Fri Jun 23 13:19:41 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * tm-hp9k3bsd.h: New file. + * config.gcc: New target hp9k320-bsd. + + * gcc.c (record_temp_file): Don't add a name twice to one queue. + + * stmt.c (expand_expr_stmt): Call warn_if_unused_value. + (warn_if_unused_value): Code extracted from expand_expr_stmt. + Recurse to handle COMPOUND_EXPR. Don't warn about COND_EXPR. + + * tm-encore.h (DBX_REGISTER_NUMBER): Override tm-ns32k.h; + return operand unchanged. + + * reload1.c (emit_reload_insns): Don't use recog_memoized + on an asm. + + * jump.c (delete_insn): Update last_insn. + * emit-rtl.c (set_last_insn): New function. + + * reload1.c (reload): Put a note at end of insn chain. + + * gcc.c: Put cpp output of .S file into a .s file. + +Thu Jun 22 22:14:35 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * optabs.c (expand_binop, expand_unop): Emit queue before library call. + It is done within emit_library_call, and cse screws up if there is a + queued insn in the middle of a cse-able sequence. + +Wed Jun 21 11:57:22 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * tm-mips.h (CPP_PREDEFINES): Define -Dunix. + + * reload.c (combine_reloads): Combined reload needed for entire insn. + + * c-parse.y (yylex): Braino checking for out-of-range escape seq. + + * stor-layout.c (layout_union): Handle PCC_BITFIELD_TYPE_MATTERS. + (layout_struct): Don't let a bitfield cross the storage unit + of its type, if PCC_BITFIELD_TYPE_MATTERS. + +Tue Jun 20 00:03:48 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * varasm.c (get_or_assign_label): Let CONSTANT_ALIGNMENT specify + alignment of the constant. + CONSTANT_ALIGNMENT is a new optional macro. + + * varasm.c (force_const_mem, get_or_assign_label): + Make buffer bigger. + + * toplev.c (print_target_switch_defaults): New fn called for -version. + + * toplev.c (compile_file): Detect error closing output file. + + * stor-layout.c (fixup_unsigned_type): Don't shift by 32. + + * stmt.c (emit_case_nodes): Pass UNSIGNEDP along to emit_cmp_insn. + + * stmt.c (expand_end_case): If index is narrow and cannot be + directly compared, widen it just once. + + * c-parse.y (yylex): Support multi-character constants. + Thorough rewrite of char constant parsing. + + * c-decl.c (pushdecl): Replace local extern function decl with + previous global decl if latter is inline, or builtin, or has + more arg type info. + + * hard-params.c (xmalloc): Define it, for alloca.c. + + * tm-hp9k320.h (STANDARD_STARTFILE_PREFIX): Override -D in Makefile. + + * expmed.c (store_fixed_bit_field): Avoid shift by 32. + + * stmt.c (expand_function_start): Emit a NOTE_INSN_FUNCTION_BEG. + * final.c (final_scan_insn): For SDB output, do the + sdbout_begin_function at that note. + + * reload1.c (choose_reload_regs): If a reload reg inherits + from a previous reload, verify safety after all reloads are assigned. + + * c-decl.c (build_enumerator): Remove no-op casts. + + * reload.c (find_reloads): If an earlyclobber operand matches + an input operand it is constrained to match, that's not a problem. + If an earlyclobber operand loses due to earlyclobber, its matching + input operand also loses. + + * reload1.c (choose_reload_regs): Don't use result of find_equiv_reg + if that reg is used for reloading in an earlier part of the insn. + + * cse.c (fold_rtx): If WIDTH is 0, don't try sign-extending ARG0, ARG1. + + * Makefile (hard-params*): Use $(OLDCC). + + * c-typeck.c (c_alignof): No warning for -pedantic. + + * c-parse.y (readescape): Don't have both error and warning + on one hex escape. + + * c-parse.y (yylex): Treat vertical tab as white space. + (skip_white_space): Likewise. + + * c-parse.y (datadef): If pedantic, warn for stray semicolon. + + * expr.c (expand_increment): Pass accurate unsignedp arg + to expand_binary_op. + +Mon Jun 19 13:36:20 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * config.gcc (news, news-gas): Use xm-m68k.h. + + * final.c (output_asm_label, output_addr_const): Make buf bigger. + + * cexp.y (main): Handle EOF on input. + (lookup, warning): Provide as a dummy. + (is_idchar, is_idstart): Declare as unsigned char. + + * cexp.y (parse_escape): Use TARGET_NEWLINE, etc., as values. + Support hex escapes. Warn if octal or hex escape doesn't fit in char. + + * cexp.y (yylex): Sign-extend char constants if appropriate. + + * genemit.c: Make insn-emit.c include insn-flags.h. + + * gcc.c: Move record_temp_file past page which declares vflag. + + * integrate.c (expand_inline_function): If copying an insn with + a REG_EQUIV note, make a similar note. + + * Allow reload regs to be reused for parts of an insn. + * reload.c (find_reloads): Classify each reload for which part + of the insn it is needed in. + (find_reloads_address, etc.): Pass down the overall operand + that this is part of, to record it on address reloads. + (push_reload): Record that for each reload. + * reload1.c (reload): Compute maximum needs of any part of the insn. + (choose_reload_regs): Part of old choose_reload_targets. + Hairier criteria for inheriting reloads and for which ones are + available for the next insn to inherit. + (emit_reload_insns): The rest of old choose_reload_targets. + Emit reload insns in proper order according to where they are needed. + * Record `reload_reg_in_use' separately for each part of the insn. + (mark_reload_reg_in_use): New function. + (reload_reg_free_p, reload_reg_free_before_p): New functions. + (reload_reg_reaches_end_p): New function. + + * expr.c (expand_expr): Emit queue in X+=(Y?Z:A) optimization. + + * rtlanal.c (rtx_equal_p): Check vectors have same length. + +Sun Jun 18 12:16:14 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * stmt.c (expand_expr_stmt): Maybe warn if top-level operator + makes an unused result. + + * gcc.c (delete_temp_files, delete_failure_queue): + If -v, report failures in unlink. + + * Makefile (includes): New target to run fixincludes. + (install): Swap arms of if-statement. + +Sat Jun 17 12:41:53 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * stor-layout.c (layout_union): Arg to error_with_decl was missing. + + * ns32k.md (movsf): Use CONST_DOUBLE_LOW to extract from CONST_DOUBLE. + + * loop.c (consec_sets_giv): Change type of force, force2. + + * combine.c (dump*): Declare arg as FILE*. + + * Makefile (clean): Delete hard-params. + + * flow.c (life_analysis): Use a special obstack for the temporary + regsets. + + * m68k.md (clr pattern): On 68000, use moveq to clear data reg. + + * gvarargs.h: File varargs.h renamed. + The old name conflicted with , now that -I. is used. + * tree.c, expr.c, emit-rtl.c: Change #include commands. + * Makefile (install): Install gvarargs.h under name varargs.h. + * gcc.c: Include gvarargs.h, not system's varargs.h. + + * Makefile: Use -I$(srcdir) before -I$(srcdir)/config. + * config/tm.h: Deleted; didn't work if config was a symlink. + + * cse.c (cse_insn): Record location of inner_dest + so it can be replaced properly if a new MEM rtx is made. + +Fri Jun 16 14:17:20 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * make-cc1.com: Compile and link rtlanal.c. + + * c-typeck.c (build_array_ref): Call fold on the array ref. + * fold-const.c (fold): Simplify array ref of string constant. + + * stmt.c (expand_asm_operands): Fix error message. + + * Makefile (gnulib2): Remove old members before compiling new. + Fix stupid errors. + * gnulib2.c (__cmpdi2, __ucmpdi2): Typos in names of interface unions. + + * genconfig.c (main): Don't write MAX_CLOBBERS_PER_INSN; obsolete. + Add 3 to MAX_RECOG_OPERANDS. + + * cse.c (fold_cc0): Extra arg specifies machine mode. + Callers changed. + (cse_insn): Record original mode of each src for this purpose. + +Thu Jun 15 12:35:18 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * gnulib2.c (_cmpdi2, _ucmpdi2): Moved here from gnulib.c. + Use long long for argument type. + + * rtlanal.c (may_trap_p): Moved here from loop.c. + Return 1 for division by explicit zero. + + * reload1.c (eliminate_frame_pointer, alter_frame_pointer_addresses): + Rerecognize insns which are changed by this. + + * i386.md (call_value): Don't return prematurely. + + * alliant.md (movqi): Handle moving Aregs to mem and vice versa. + (bftst -> btst): Restrict to bitpos less than 8 + so operand may be non-offsettable. + (nop): New pattern. + (return): Was disabled; now deleted. + * tm-alliant.h (PRINT_OPERAND_PUNCT_VALID_P): Define it. + * out-alliant.c (output_btst): Same change as in out-m68k.c + + * alliant.md, out-alliant.c: Offsetable -> offsettable. + + * c-parse.y (rule for stmt_exprs): Make the LET_STMT volatile. + + * c-decl.c (duplicate_decls): Don't save inline function data + from previous definition if a new *definition* is seen. + + * integrate.c (access_parm_map): Handle subregs and constants. + + * stmt.c (expand_return): Don't crash if DECL_RTL (DECL_RESULT()) is 0. + + * tm-tahoe.h (LONGJMP_RESTORE_FROM_STACK): Define it. + + * tm-mips.h (CONSTANT_P): Deleted; duplicates rtl.h. + +Fri Jun 9 01:39:30 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * Makefile (float.h): Avoid using $(MAKE). + + * Don't cram two things into STMT_BODY of a LET_STMT. + * tree.h (struct bind_stmt): New field, subblocks. + (STMT_SUBBLOCKS): New macro to access it. + * print-tree.c (walk): Print new field. + * tree.c (build_let_stmt): Store the old BODY arg into subblocks field. + * c-parse.y (stmt expr rule): Put rtl expr alone into body field. + * dbxout.c (dbxout_block): Recurse on subblocks, not body. + * sdbout.c, symout.c: Likewise. + * integrate.c (copy_decl_tree): Likewise. + * stmt.c (setjmp_protect, uninitialized_vars_warning): Likewise. + * expr.c (expand_expr): For LET_STMT, simply use its body. + + * machmode.def: Add sixth arg to each entry. + * tree.h, rtl.h, rtl.c: Add arg to DEF_MACHMODE. + * rtl.h (GET_WIDER_MODE): New macro; table in rtl.c. + * expr.c (expand_expr): Use that for widening multiply. + + * stmt.c (fixup_var_refs_1): When converting MEM to QImode for + bit field, adjust the address if possible to make bitpos + less than 8. + * m68k.md (bftst -> btst): Restrict to bitpos less than 8 + so operand may be non-offsettable. + + * cccp.c (do_line): Accept and pass on 3rd arg for enter or leave file. + + * out-m68k.c (output_btst): Handle COUNT bigger than size of unit. + + * cccp.c (CHECK_DEPTH): Macro to detect instack overflow. + (finclude, macroexpand, expand_to_temp_buffer): Use that. + + * cccp.c (rescan): Don't check for disabled macro if traditional. + (macroexpand): Don't disable macro if traditional. + + * sdbout.c (sdbout_one_type): Take out last change; assembler barfs. + + * c-parse.y (maybe_attribute): Eliminate #-syntaxes. + Make ATTRIBUTE the name for __attribute. + + * c-parse.gperf: Add __attribute{,__} and __signed{,__}. + * c-parse.y: Install results of that change. + + * Fix bug in sizeof ({...}). + * c-decl.c (poplevel): Set TREE_USED. Return the LET_STMT. + * c-parse.y (stmt-expr rule): Put the RTL_EXPR in the LET_STMT, + clear its TREE_USED, and use it as the result. + * expr.c (expand_expr): Allow LET_STMT as an expr. + Set its TREE_USED and expand the TREE_VALUE of its body. + * dbxout.c (dbxout_block): Ignore LET_STMT if TREE_USED not set. + * sdbout.c, symout.c: Likewise. + +Thu Jun 8 00:06:36 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * c-parse.y (yylex): Extend ERANGE-inhibitor for 0.0 + to 0.0e0 as well. + + * flow.c (life_analysis): Prevent allocation of regs live at setjmp + on certain machines. Controlled by LONGJMP_RESTORE_FROM_STACK. + Sets reg_live_length to -1. + * local-alloc.c (block_alloc): Be prepared for that. + * tm-vax.h (LONGJMP_RESTORE_FROM_STACK): Define it. + + * gnulib2.c (all interfaces): Declare args and values as long long, + and split them using unions. + + * loop.c (check_dbra_loop): Don't reverse loop if there are two + refs to varying addresses. Consider foo[i] = foo[i-1]. + (count_nonfixed_refs): Subroutine to count them. + + * cexp.y: Distinguish signed and unsigned. + An integer value is now represented by a struct. + All rules for arithmetic changed. + (yylex): Adapt to change in yylval data type. + + * limits.h (LONG_MIN): Make sure it's a signed long. + + * sdbout.c (sdbout_one_type): Output types of fields first, + if they are structs. Don't go through pointers. + (sdbout_field_types): Subroutine for that + +Wed Jun 7 13:00:44 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * fixincludes: Switch to /usr/include before doing vuid_event.h. + Use $2 as output directory for sed. + + * tm-i386.h (FUNCTION_PROFILER): Put counter address in %edx. + * tm-i386v.h (LIB_SPEC): Use -L/usr/lib/libp if profiling. + + * expr.c (expand_increment): Typo testing for BImode component. + + * convex changes from csmith: + * tm-convex.h: use EXTRA_SECTIONS to do .bss. + out-convex.c: set_section, align_section are now unused. + * convex.md: add pattern to pick an A-reg destination for sums + whose source involves a dedicated A reg (frame or arg pointer) + * convex.md: immediate and, or, xor instructions store a 32-bit + result. Fix instructions that assumed it was 64. + + * mips.md (probe): New pattern to create stack space. + + * Makefile (float.h): Ignore errors from hard-params. + Specify ./ to run it. + +Tue Jun 6 15:45:27 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * out-tahoe.c: Rename `offsetable' to `offsettable'. + + * tahoe.md (nop): New pattern. + + * i386.md (umul...): Constrain operand 1 as `0', not `a'. + `a' sometimes wanted two a-regs for operands 0 and 1. + + * cccp.c: Forward-declare some structs. + + * c-decl.c: Rearrange fcn fwd decls and struct decls. + + * expr.c: Move some fcn fwd decls after structs their args use. + * genpeep.c, genextract.c: Likewise. + + * loop.c: Forward-declare some structs. + + * stmt.c: Move decls of structs before those of static functions. + + * loop.c (strength_reduce): Delete extra arg to check_eliminate_biv. + + * integrate.c (expand_inline_function): Supply missing arg + to convert_to_mode. + + * gcc.c (handle_braces): Supply missing arg to do_spec_1. + + * explow.c (lookup_static_chain): Accept a context arg. + + * expmed.c (store_split_bit_field): Pass ALIGN arg + to extract_fixed_bit_field. + + * expr.c (expand_assignment): Convert TYPE_ALIGN to bytes. + (store_constructor, expand_expr): Likewise. + + * m68k.h: NO_ADDSUB_Q conditionals turn off all addq, subq insns. + (Fully supported only with MOTOROLA and HPUX_ASM flags.) + + * jump.c (do_cross_jump): Don't die if LABEL is 0. + + * tm-mips.h (PRINT_OPERAND_PUNCT_VALID_P): New macro. + * tm-iris.h: New file. Unsplit lines accidentally split. + +Mon Jun 5 15:39:30 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * integrate.c (output_inline_function): Call init_function_start, + not expand_function_start. + * emit-rtl.c (restore_reg_data): No need to init reg_rtx_no. + + * stmt.c (init_function_start): Set current_function_returns_struct. + + * rtlanal.c (reg_set_between_p): New fn analogous to reg_used_between_p + * loop.c (strength_reduce): Reject biv initial value which is altered + subsequently before actual loop start. + + * rtlanal.c: New file split out from rtl.c. + Has things not used in the gen files. + + * loop.c (strength_reduce): Reject biv initial value in a hard reg + clobbered by an intervening function call. + + * tree.c (get_identifier): New flag needed to enable id-clash warnings. + (start_identifier_warnings): Set that flag. + * c-decl.c (init_decl_processing): Call that, after making built-ins. + +Sat Jun 3 14:41:34 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * final.c (final_scan_insn): No basic block profiling at jump tables. + + * stmt.c (expand_decl): Probe the stack to make pages exist. + * expr.c (expand_builtin): Likewise, for alloca. + + * move-if-change: Specify /bin/sh. + + * tm-ns32k.h (INDIRECTABLE_2_ADDRESS_P): Don't accept PLUS + with constant operands but not inside CONST. + + * integrate.c (output_inline_function, save_for_inline): + Save stack_slot_list, and restore it for actual output. + * emit-rtl.c (gen_inline_header_rtx): New arg for this. + + * emit-rtl.c (restore_reg_data): Initialize reg_rtx_no. + (restore_reg_data_1): Handle reg_rtx_no jumping past + reg_pointer_flag_length. + + * reload1.c (alter_reg): Do nothing if regno_reg_rtx has 0. + + * integrate.c (copy_rtx_and_substitute): Typos for stack parm + addresses in PLUS case. + + * genoutput.c (gen_insn, gen_peephole): Make output_n fns static. + (output_prologue): Use new macro DEFAULT_MACHINE_INFO if defined. + + * tree.h (enum machine_mode): Define MAX_MACHINE_MODE as in rtl.h. + +Fri Jun 2 15:40:47 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * cccp.c (do_include): A file included via a system header file + counts as a system header file for -M. + + * gnulib2.c: Support boolean ops and shifts. + + * loop.c (emit_iv_inc): Use emit_iv_init_code. + + * rtl.h (CONST0_RTX): Don't try to cast abort. + + * tm-news.h (PRINT_OPERAND_ADDRESS): Fix typo `reg_name'. + Delete two garbage lines. + + * loop.c (eliminate_biv): Use emit_iv_init_code to compute comparison + value. If value is constant, recognize the insn, and if that fails, + put the value in a register. + +Thu Jun 1 16:56:39 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * print-tree.c (dump): Don't die if rtx components are null. + + * expmed.c (expand_mult_add): New fn to do A * X + B. + (make_tree): New subroutine. + * loop.c (emit_iv_init_code): Use that. Much simpler now. + +Tue May 30 17:20:40 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * fold-const.c (fold): Use TREE_SET_CODE to store in tree codes. + + * tree.h (struct tree_common): Make `code' an unsigned int. + (TREE_CODE, TREE_SET_CODE): Put in casts. + + * optabs.c (emit_cmp_insn): Supply all the args in recursive calls. + + * toplev.c (report_error_function): Fix typo; METHOD_TYPE missing. + + * fixincludes: Add code to make internal non-directory links. + +Mon May 29 21:36:28 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * gcc.c (find_exec_file): Try both with and without machine_suffix. + (find_file): Use machine_suffix here too. + +Sat May 27 00:02:26 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * reload.c (decompose): OFFSET wasn't initialized. + + * cse.c (cse_main): Assign monotonic cuids. + (make_regs_eqv, CHEAPER): Use cuids, not uids. + (cse_end_of_basic_block): Return a cuid, not a uid. + + * expr.c (expand_builtin): For BUILTIN_SAVEREGS, range of regs + moved included one extra previous insn. + + * emit-rtl.c (emit_line_note): Don't check -g here. + (emit_note): For line number when no -g, increment cur_insn_uid anyway. + * stmt.c (expand_start_case): Always output a NOTE_INSN_DELETED. + + * loop.c (loop_optimize): Don't count line-number NOTEs for luids. + Prevents -g from affecting optimization decisions. + +Fri May 26 17:31:15 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * local-alloc.c (block_alloc): Don't count notes in insn_number. + Prevents -g from affecting order of allocation. + +Thu May 25 14:12:19 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * local-alloc.c (block_alloc): Clear full length of regs_live_at. + + * ns32k.md (cmpsi): Make this the first cmp pattern. + + * jump.c (do_cross_jump): Skip NOTEs while checking for existing label. + + * cse.c (cse_insn): When no-oping a jump, decrement use count of label. + (cse_basic_block): If label use count is 0, go past it. + + * integrate.c (access_parm_map): New fn, broken out of + copy_rtx_and_substitute, handles case of mem ref to stack arg. + (copy_rtx_and_substitute): Call it. + Also use it for address of a stack arg. + + * gen*.c (fatal): Declare 1st arg as string. + +Wed May 24 00:13:36 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * optabs.c (init_optabs): Handle movdi and movdf insns. + + * final.c (end_final): Realign locn ctr after outputting string. + + * tm-sparc.h (LINK_SPEC): Link bb_link.o before standard lib. + + * tm-sun386i.h (LINK_SPEC): Accept and ignore -sun386. + + * gcc.c (find_exec_file): Use machine_suffix. + (process_command): Set that for -b option. + + * integrate.c (function_cannot_inline_p): No size limit + for functions declared inline. + + * loop.c (skip_consec_insns): New fn, skip several insns or libcalls. + (force_movables): New fn, part of scan_loop broken out. + (ignore_some_movables): New fn, ignore a movable whose insn + is within another movable's libcall. + (scan_loop): Call those three. + Don't handle m->consec for zero-extend movables, since always 0. + +Tue May 23 12:58:24 1989 Joe Weening (weening at gang-of-four.stanford.edu) + + * config/alliant.md: + Removed operand classes 'x', 'y', 'G', 'H'. + Added "%." to many opcodes to simplify comparison with m68k.md. + Changed TARGET_68881 to TARGET_CE. + Changed floating-point insns to better describe the Alliant CE. + Most args to floating-point insns are now nonimmediate_operand. + Removed special insns for pushing doublewords onto stack. + Added non-CE versions of movsf and movdf to avoid using FP + registers in this case. + (float*i*f2): Don't allow immediate ops. + (sne): Fix typo, fsne => fsneq. + (call, call_value): Changed to always pop args from stack + upon return; this gives better code than before and conforms + to Alliant calling standard. + Incorporated some recent changes to m68k.md. + + * config/out-alliant.c: + (regno_reg_class): Removed FPA reg classes. + (output_move_const_double): Function not needed, removed. + + * config/tm-alliant.h: + Removed FPA registers and reg classes. + Target flags: changed TARGET_68881 to TARGET_CE, removed + TARGET_RTD, TARGET_REGPARM, TARGET_FPA. + Removed TARGET_CE test in several places since we need to + use FP regs even for non-CE programs. + (TARGET_VERSION, CPP_SPEC): Define for Alliant. + (CONDITIONAL_REGISTER_USAGE): Removed, not needed. + (FRAME_POINTER_REQUIRED): Defined. + (RETURN_POPS_ARGS): Defined. + (FUNCTION_VALUE, LIBCALL_VALUE, FUNCTION_VALUE_REGNO_P): + Use fp0 to return floating-point values. + (FUNCTION_ARG): Remove TARGET_REGPARM code. + (FUNCTION_ARG_PARTIAL_NREGS): Always 0. + (FUNCTION_PROFILER): Define for Alliant. + (FUNCTION_EPILOGUE): Remove use of rtd instruction. + Renamed CC_IN_68881 to CC_IN_FP. + (NOTICE_UPDATE_CC): Incorporate changes that were made + in tm-m68k.h. + + * config/xm-alliant.h (LINK_SPEC): Pass -X to linker. + +Tue May 23 12:58:24 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * sdbout.c: Don't include c-tree.h. + + * tree.c (build_index_type): Use sizetype for min and max values. + Convert maxval rather than clobbering it. + + * tm-hp9k320.h: Finish unterminated comment. + + * sdbout.c (sdbout_parms): Use gen_fake_label for anonymous parm. + +Sun May 21 12:58:06 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * stmt.c (aggregate_value_p): New fn says whether expression is a type + that functions cannot return as a scalar. + (assign_parms, expand_function_start): Use that. + * expr.c (expand_call): Likewise. + + * gcc.c (delete_failure_queue): New subroutine. + (delete_temp_files): No longer delete the failure queue. + (main): Delete failure queue after each failing compilation. + +Sat May 20 13:16:23 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * varasm.c (force_const_mem): New optional macro SELECT_RTX_SECTION. + + * mips.md: Change %u0 to %:. + (movsi): Add constraint alternative accepting address arg. + + * fold-const.c (mul_double): Special case for 2nd arg 2, 4, 8. + (combine): Special case shortcuts for plus, minus, mult, div. + + * stmt.c (expand_function_start): Simplify hairy statement for 3B1. + * expr.c (expand_call): Likewise. + + * math-68881.h: New file. + + * m68k.md (movqi): Handle moving aregs to mem and vice versa. + + * dbxout.c (dbxout_type): Don't test use_gdb_dbx_extensions + in cases that occur in C. + + * stmt.c (expand_function_{start,end}): Make DECL_RESULT's rtl 0 + when function returns no value. + + * tree.c (build_decl): Initialize DECL_PRINT_NAME, DECL_ASSEMBLER_NAME. + + * c-decl.c (store_parm_decls): Call init_function_start. + +Thu May 18 00:41:37 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * stmt.c (expand_null_return_1): New arg USE_GOTO says jump to + return_label even if could otherwise use a return insn. + Make a return_label if we need one and don't have one already. + If have parm cleanups, always jump to cleanup_label. + (expand_null_return): Pass 1 for USE_GOTO if cleanups pending. + (expand_return): Set LAST_INSN if have local cleanups or parm cleanups. + Use that if jumping to tail-recursion label. + Optimization for returning a comparison is safe for local cleanups + but don't do it if there are parm cleanups. + Calling expand_null_return_1, pass 1 for USE_GOTO if local cleanups. + (this_contour_has_cleanups_p): New function. + + * stmt.c (init_function_start): New function, beginning of + expand_function_start broken out. + Use DECL_PRINT_NAME to get function's name. + (expand_function_start): Now two args, function and PARMS_HAVE_CLEANUPS + Compute RETURN_LABEL sooner; make one if parm cleanups. + If parms have cleanups, put scalar return value in pseudo-reg. + Don't mark that pseudo with REG_FUNCTION_VALUE_P. + (expand_function_end): Simplify decisions about output of return_label + and return insn. + If DECL_RESULT is pseudo-reg, copy it to real return reg. + + * stmt.c (expand_function_end): Handle ordinary struct values + like pcc, but only if unoptimized. + (expand_function_start): Make a return_label for ordinary struct value. + + * stor-layout.c (layout_type): Handle METHOD_TYPE like FUNCTION_TYPE. + (layout_decl): Allow TYPE_DECL. + + * stor-layout.c (layout_basetypes): Code for basetypes broken + out of layout_record. Sets the type size tentatively. + (layout_record): Start with that tentative size. + Also, don't do anything with CONST_DECL members. + + * stor-layout.c (layout_union): Simpler error report for static memb. + + * reload1.c (eliminate_frame_pointer): Reduce PUSH_ROUNDING + conditional to apply only to push instructions. + + * expr.c (expand_call): Fix stupid errors handling MAX_PARM_BOUNDARY. + * stmt.c (assign_parms): Likewise. + + * toplev.c (announce_function, report_error_function): + (error_with_decl, warning_with_decl): Use DECL_PRINT_NAME. + + * toplev.c (compile_file): Subtract integration_time from parse_time. + + * toplev.c (compile_file): Don't output read-only static variables + at end of compilation if address was not used. + + * toplev.c (rest_of_compilation): Handle flag_syntax_only. + + * toplev.c (main): Handle -g0 and -G0 options. + For -g and -G, set use_gdb_dbx_extensions. + + * toplev.c (main): Set `progname'. + (pfatal_with_name, fatal_io_error, {error,warning}_with_file_and_line): + (sorry): Print value of `progname', not "cc1". + + * tree.def: Delete FRIEND_DECL. Add PUSH_EXPR and POP_EXPR. + + * tree.c (simple_cst_equal): Handle INDIRECT_REF. + + * tree.c (lvalue_p): Handle METHOD_TYPE. Handle NEW_EXPR. + + * tree.c (copy_list): New function. + + * tree.h (struct tree_decl): New fields print_name and assembler_name. + (DECL_PRINT_NAME, DECL_ASSEMBLER_NAME): New accessors. + + * c-decl.c (LONG_DOUBLE_TYPE_SIZE): New compilation parameter. + +Wed May 17 22:07:17 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * dbranch.c (emit_delay_sequence): Reset insn code to -1 when + turning insn into a sequence so that it won't think that it matches + something in the md file. + + * dbranch.c (insn_eligible_p): Call refers_to_regno_p with a + non-zero range. + + * dbranch.c (pnote): Modified to make sure instruction clobbered + register is a set, rather than, say, a clobber. + +Wed May 17 14:01:20 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * sdbout.c (sdbout_parms): Handle parm with no name. + + * loop.c (combine_movables): Test for overlap of zero-extend regs + was screwed up. + + * c-typeck.c (c_sizeof{,_nowarn}): Convert from bytes to chars, + since c defines sizeof (char) as 1. + (pointer_int_sum, pointer_diff): Use c_sizeof{,_nowarn}. + +Tue May 16 16:27:32 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * reload1.c (choose_reload_targets): Don't reuse regs + mentioned in reload_reg_rtx. + + * tm-tahoe.h, tahoe.md, out-tahoe.c, xm-tahoe.h: New files. + +Mon May 15 16:25:12 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * fixincludes: Exit with explicit status 0 at end. + cd to /usr/include before cd to subtree root in case of relative link. + Create dir $LIB earlier. + When checking for a link, treat .. like an absolute target. + + * symout.c (symout_block_symbols): Give every local decl a typespec. + * cexp.y (parse_number): + * flow.c (life_analysis, dump_flow_info): + + * loop.c (consec_sets_invariant_p): Logic error accepted consec sets + of which only one was invariant. + + * expr.c (expand_expr): Use no subtargets inside loops. + * stmt.c (inside_loop): New function. + +Sun May 14 00:11:07 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * tree.h: Declare long long types. + + * c-parse.y (combine_strings): Make string contents saveable. + + * tree.c (savealloc): New function. + + * m68k.md (movdi): % missing in fmove%.d. + + * c-parse.y (yylex): Detect overflow past 64-bits. + Detect specially numbers not fitting in signed long long. + +Sat May 13 13:16:05 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * reload1.c (alter_frame_pointer_addresses): Preserve volatility. + + * varasm.c (output_constructor): Die if BITS_PER_UNIT is too big + for this function to work. + + * genpeep.c (match_rtx): For match_operator, match the operands, too. + + * varasm.c (output_constant): Use ASM_OUTPUT_DOUBLE_INT for DImode. + + * stor-layout.c (make_signed_type, make_unsigned_type): + (fixup_unsigned_type): Use HOST_BITS_PER_INT. + + * stor-layout.c (layout_type): Use TFmode if appro. + + * optabs.c (emit_cmp_insn): Use mode sizes to check cmpstrqi, cmpstrhi. + + * c-typeck.c (get_floating_type): Compare MODE against modes of types. + (signed_type, unsigned_type, signed_or_unsigned_type, type_for_size): + Handle long long types. + (digest_init): Don't assume width of `char' is BITS_PER_UNIT. + + * c-parse.y (yylex): For truncating chars, use width of `char' type. + Allow `ll' in int constants and make long long. + Also make long long if constant won't fit in an int. + + * c-decl.c (SHORT_TYPE_SIZE): Round up when dividing. + +Fri May 12 22:36:21 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * real.h: Allow multiple inclusion. + + * tm-sun386i.h (DBX_REGISTER_NUMBER): Bizarre renumbering. + +Thu May 11 00:36:21 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * fixincludes: Fix non-ansi declaration of sprintf in X11/Xmu.h + + * c-parse.y (stmt from expr): Do default conversion if useful + for sake of ({...}). + + * sparc.md (andcc recognizer): Operand missing in subreg. + +Wed May 10 17:20:38 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * rtl.c (read_name): Error if name is missing. + (dump_and_abort): Don't print char args if -1. + + * i386.md (umulqihi3): Operand numbers were missing. + + * reload1.c (choose_reload_targets): Allow spill reg in find_equiv_reg + if it's free and correct class. + + * cse.c (canon_hash): Handle empty strings. + + * cccp.c (macroexpand): Newline newline treated like real white space + when stringifying. + + * Rename *offsetable* to *offsettable*. + +Tue May 9 22:54:58 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * c-decl.c (finish_type): Layout any variants of the type. + +Tue May 9 12:30:28 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * final.c (final_scan_insn, final): Added an argument to + final_scan_insn to disallow peephole processing (to turn it off + during delayed branch scheduling). + + * final.c (final_scan_insn): Made insn not matching any MD rtl a + criteria for delayed branch case. Moved delayed branch case to just + before real insn recognition to reduce the number of insns on which + recog_memoized is called. + +Mon May 8 15:02:42 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * fixincludes (LIB): Allow overriding. + + * cccp.c: Don't search /usr/include/CC by default. + +Mon May 8 13:09:21 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * print-tree.c (dump): Fixed typo; IDENTIFIER ==> IDENTIFIER_NODE. + +Sun May 7 12:44:53 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * print-tree.c (dump): TYPE_NAME may be IDENTIFIER or TYPE_DECL. + +Sat May 6 00:13:47 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * tree.def: Define EXACT_DIV_EXPR, for when remainder known as 0. + * fold-const.c (combine, fold, div_and_round_double): Handle new code. + * expr.c (expand_expr): Likewise. + * c-typeck.c (pointer_diff): Use EXACT_DIV_EXPR. + + * integrate.c (expand_inline_function): Use size of passed type + for allocating stack slot with that type. + + * c-parse.y (maybe_attribute, attribute*): New syntax for Apollos. + These tokens currently not generated. + +Fri May 5 18:43:01 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * toplev.c [USG]: Undefine FLOAT for sake of sys/param.h on hpux. + + * optabs.c (expand_binop): If backtracking, don't delete insns made + for -fforce-mem. + +Thu May 4 01:57:23 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * reload.c (find_reloads): Don't compare an earlyclobber operand + with itself. + + * reload.c (immune_p): Constants and stack slots don't overlap. + + * Put no-ops in front of loops and labels, + to prevent confusion in the debugger. + * c-parse.y (loops and labels): Call emit_nop. + * stmt.c (emit_nop): New function--sometimes emit a no-op. + * *.md (nop): New insn. + + * expr.c (expand_call): Typo in arg to FIRST_PARM_CALLER_OFFSET. + +Wed May 3 01:34:58 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * loop.c (scan_loop): Scanning around end of loop + should not set maybe_never. + + * Rename SELECT_VARIABLE_SECTION to SELECT_SECTION. + * varasm.c (get_or_assign_label): Use SELECT_SECTION if defined. + * varasm.c: Use EXTRA_SECTION_FUNCTIONS if defined (new macro). + + * mips.md: Change %u to %u0 to avoid error check. + + * tm-mips.h (TARGET_VERSNUM): Inc. to 1 08. + (TARGET_VERSION): Change strings. + (AL_DEBUG): Don't define it. + (HARD_REGNO_MODE_OK): Add some casts to int. + (STACK_ARGS_ADJUST): Name was misspelled. + (PRINT_OPERAND_ADDRESS): Just abort for MEM, POST_INC, etc. + (EXTRA_SECTIONS, SELECT_VARIABLE_SECTION, SELECTORS_EXTRA_SECTIONS, + SELECT_VARIABLE_CONST_SECTION): New macros. + (ASM_FILE_END): Change function name. + * out-mips.c (function_arg_advance): Delete debugging printfs. + (function_inarg, function_arg): Likewise. + (compare_collect, compare_restore): Add some. + + * reload1.c (reload): Fix handling of caller_save_needed. + + * stmt.c (expand_function_start): Clear caller_save_needed. + + * stmt.c (emit_case_nodes): Some compiler has trouble with calling + a function pointer. + * gnulib.c: likewise. + +Tue May 2 15:32:25 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * loop.c (combine_movables): For zero extend, + do each from-mode separately. + +Mon May 1 00:18:47 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * tm-apollo68.h: New file. + + * c-parse.y (is_reserved_word, hash): Add keywords `__asm__', etc. + * c-parse.gperf: Corresponding changes. + + * c-parse.y (check_newline): Set main_input_filename before + considering optional arguments. + + * final.c (final_scan_function): Return next insn to process. + Usually that's the following insn; occasionally, previous compare. + + * c-decl.c (DOUBLE_TYPE_SIZE): Wrong value. + + * reload.c (decompose): Failed to return value. + + * Support local specified-register variables. + * varasm.c (decode_reg_name): New function, cvt asmspec to regnum. + (make_decl_rtl): Call that. + * toplev.c (rest_of_decl_compilation): Handle local specified-register + declarations. + + * i386.md (tstqi, trunc*qi): Constrain to `q' regs. + + * loop.c (scan_loop, move_movables): ->global for zero-extend register + now means register is used outside range from where it is set + to the following label. Non-global zero-extend regs + may be entirely cleared. + + * loop.c (combine_movables): Loop that combines matching movables + broken out from scan_loop. + Now also combine non-global zero-extend registers with each other + if their lifespans don't overlap. + + * c-typeck.c (build_unary_op, ADDR_EXPR of a COMPONENT_REF): + Always convert to desired result type. + +Sun Apr 30 12:58:58 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * c-decl.c (init_decl_processing): New macros parameterize int types. + CHAR_TYPE_SIZE, SHORT_TYPE_SIZE, LONG_TYPE_SIZE, LONG_LONG_TYPE_SIZE, + FLOAT_TYPE_SIZE, DOUBLE_TYPE_SIZE. + + * fixincludes: Use sed instead of ex. No problem with split lines. + + * print-tree.c (dump): Print type's name, if any. + + * c-parse.y: Use __inline, not plain inline. + + * toplev.c: New option -fdelayed-branch. + (compile_file): Open and close dbranch dump file. + Collect and print dbranch time. + (rest_of_compilation): Optionally do dbranch scheduling, + only if HAVE_DELAYED_BRANCH. + (main): Handle -dd. + + * rtl.c (copy_rtx): Handle null pointers as code `e'. + + * final.c (dbr_sequence_length): New function. + (final_scan_insn): Most of `final' broken out. + Add support for SEQUENCE insns. + last_ignored_compare and new_block now top-level static. + + * c-parse.y (MAX_WORD_LENGTH): Long enough for __volatile. + +Sat Apr 29 13:03:20 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * c-parse.y (asm statements): Output line numbers. + + * loop.c (emit_iv_init_code, emit_iv_inc, eliminate_biv): Copy + additive term rtx's to prevent sharing between insns. + + * c-parse.y (check_newline): Increment input_file_stack_tick. + * toplev.c (report_error_function): Describe input stack only if + changed. + + * c-decl.c (finish_struct): Reject zero width for named field. + + * tm-sun3.h (CC1_SPEC): Prevent error on `-sun3'. + * tm-sparc.h (CC1_SPEC): Prevent error on `-sun4'. + + * Makefile (cleanconfig): cleanlinks renamed; also delete gnulib. + (gnulib): Delete stamp-gnulib2 since gnulib2 should be redone after. + +Fri Apr 28 00:38:32 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * config.gcc (genix): Correct xm file name. + + * tm-genix.h: Undefine ASM_SPEC inherited from tm-encore.h. + + * Makefile: Make float.h using hard-params. + (clean): Delete float.h. + + * hard-params.c: New program. + + * varasm.c (assemble_variable): Use SELECT_VARIABLE_SECTION if defined. + (in_section): Use EXTRA_SECTIONS if defined. + + * toplev.c (compile_file): Call ASM_FILE_END if defined. + + * gcc.c (SWITCH_TAKES_ARG, WORD_SWITCH_TAKES_ARG): Let config override. + + * loop.c (emit_iv_init_code): Force A to a reg if it isn't. + +Thu Apr 27 12:51:14 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * tm-mips.h (ASM_START_FILES): Don't call print_options. + Don't call the funny abort-functions. + * out-mips.c: Delete funny debugging functions and aborts. + (print_options): #if 0. + (compare_restore): Test for COMPARE, not MINUS. + (mips_section_get, mips_output_external, mips_asm_final): New fns. + + * input.h: New file with *input_filename, lineno and input_file_stack. + Included in toplev.c and c-parse.y. + * c-decl.c (finish_function): LINENO is now arg. + * c-parse.y: Calls changed. + + * c-parse.y (check_newline): Handle `1' or `2' from cpp + by pushing or popping input_file_stack. + * toplev.c (compile_file): Push main input file on input_file_stack. + (report_error_function): If in include file, print the chain + of include-locations. + + * cccp.c (output_line_command): New arg says whether entering or + leaving a file. Output `1' or `2' on #-line if so. Callers changed. + + * gnulib2.c: Little-endian fixes from csmith@convex.com. + + * fixincludes: Wrong quoting in `echo' command. + + * tm-mips.h (REG_P): Duplicate defn deleted. + (PRINT_OPERAND): `\' was missing. + +Wed Apr 26 02:44:59 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * cccp.c (handle_directive): Preprocess even #pragma, but copy + to output file afterward. + (do_pragma): Use standard calling convention. + (install_builtins, special_symbol): Define __INCLUDE_LEVEL__. + + * cccp.c (do_include): Don't forget to close file. + + * final.c (output_asm_insn): Use PRINT_OPERAND_PUNCT_VALID_P + to validate punctuation after percent. + * tm-m68k.h, tm-alliant.h, tm-ns32k.h, tm-vax.h, tm-i386.h: + Define PRINT_OPERAND_PUNCT_VALID_P. + + * Version 1.35 released. + + * c-decl.c (grokdeclarator): Use INT_CST_LT only on int constants. + +Tue Apr 25 15:47:11 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * reload.c (find_reloads_address_1): Always return a value. + + * flow.c (mark_set_1): Look inside zero_extract, sign_extract. + + * expr.c (emit_library_call) [STACK_ARGS_ADJUST]: + Fix typo for `struct args_size'. + +Mon Apr 24 00:12:18 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * flow.c (mark_set_1): Look inside strict_low_part. + + * c-typeck.c (decl_constant_value): Don't use var's init if volatile. + + * print-tree.c (dump): Don't call walk on rtx's. + + * integrate.c (expand_inline_function): Convert expanded arg from + passed mode to nominal mode. + +Sun Apr 23 13:14:47 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * fixincludes: fix _IO macros if split across two lines. + Fix typo: EOF was indented. + + * gnulib2.c: New file with DImode library routines. + * Makefile (gnulib2): Put them into gnulib. + Must be explicitly requested. + +Fri Apr 21 13:45:45 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * cccp.c (main): Don't turn on trigraphs for -Wtrigraphs or -Wall; + use -trigraphs for that. + + * cccp.c (main): Use -trigraphs to enable trigraphs. + * gcc.c: Pass -trigraphs to cpp; don't pass -T. + + * Makefile: Variable srcdir relates location of sources + to current directory. Default is `.'. + + * integrate.c (expand_inline_function): When copying expanded arg, + use mode it's passed in, not arg's nominal mode. + + * dbxout.c (dbxout_block): Print generated name with assemble_name. + +Thu Apr 20 12:36:09 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * stdarg.h: check __sparc__ instead of sparc. + +Tue Apr 18 18:58:03 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * tm-next.h (STARTFILE_SPEC): Define it. + +Mon Apr 17 19:56:05 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * dbxout.c (dbxout_block): Use ASM_GENERATE_INTERNAL_LABEL to format + the labels LBB... and LBE... + +Sun Apr 16 23:57:47 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * mips.md: Change MINUS to COMPARE where appropriate. + +Sat Apr 15 16:11:49 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * c-decl.c (finish_struct, redeclaration_error_message): + Rename variables named OLD and NEW. + + * sparc.md (cse'd mult pattern): Handle memory operands. + Optimize small integer operands. + + * stmt.c (expand_decl): On sparc, ensure dynamic arrays of doubles + are properly aligned, despite unaligned STACK_POINTER_OFFSET. + +Fri Apr 14 10:59:56 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * expr.c (expand_call): Bugs treating struct value address as param: + do so only if it's supposed to be pushed; + decode value of FUNCTION_ARG properly. + + * tm-altos3068.h (CPP_SPEC): Some braces were dropped. + + * gcc.c (pexecute): Print message when exec fails. + (perror_exec): New fn. + (perror_with_name,pfatal_with_name): Change message syntax. + + * tm-hp9k320.h (ASM_IDENTIFY_GCC): Define as no-op. + +Wed Apr 12 00:20:31 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * cse.c (cse_insn): Can record constant value being stored in + a bit field, if we can tell that truncation won't change it. + + * m68k.md (bfset, bfclr, bfchg insns): Do CC_STATUS_INIT + since the cc's are set from the old contents. + + * gcc.c (compilers): Running `as', put -o option before input file. + + * gcc.c: Delete output file only if that file's compilation fails. + * gcc.c (record_temp_file): Changed args: always_delete, fail_delete. + (store_arg): Likewise. Callers changed. + (clear_failure_queue): Called after each compilation. + +Tue Apr 11 01:18:53 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * combine.c (subst): (SET (ZERO_EXTRACT) (OR (ZERO_EXTRACT) const)) + optimization was sometimes invalid. + + * tm-m68k.h (NOTICE_UPDATE_CC): A doubleword move that requires 2 insns + does not set the cc's usefully. + + * Makefile (cleanlinks): Just do `clean', not `realclean'. + (realclean): Delete config links also. + + * expr.c (expand_call): Handle case where return value is in memory + but TARGET is a register. + + * c-typeck.c (build_binary_op_nodefault): New arg ERROR_CODE + is passed to binary_op_error instead of CODE. + All callers changed. + (binary_op_error): CODE = NOP_EXPR is new special case. + (truthvalue_conversion): Call build_binary_op_nodefault directly + and specify NOP_EXPR for the error code. + + * c-decl.c (xref_tag): If pedantic, warn on fwd ref to enum. + +Mon Apr 10 19:44:48 1989 Chris Smith (csmith at mozart) + + * tm-convex.h (PCC_BITFIELD_TYPE_MATTERS): It doesn't, + but set it anyway. It makes for better code on this + word machine. + + * convex.md (one_compl*): add not:QI and not:HI, which + do get used after all. + + * tm-convex.h (A_REG_P, S_REG_P): define new macros + convex.md: use them + + * convex.md (addsi3): tidy up constraints. + + * tm-convex.h (REG_OK_FOR_INDEX_P): stack pointer is not ok. + + * convex.md: add a pattern to push REG+CONST so we can + prefer an A reg. + + * tm-convex.h (tstqi): should sign extend, not zero extend. + + * expr.c (convert_move): Extending narrow to DI via SI, + operand of extendsidi2 was wrong. + + * emit-rtl.c (gen_lowpart): Handle CONST_DOUBLE. + +Mon Apr 10 05:19:39 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * recog.c (nonmemory_operand): Test constant operands + as general_operand does. + + * tm-m68k.h (PRINT_OPERAND): Limit effect of code `d' + to constant addresses. + + * loop.c (can_eliminate_biv_p, eliminate_biv): Don't rely on givs with + nonconstant coefficients, since the coeffs could be zero. + + * loop.c (can_eliminate_biv_p): Check each giv for ! ignore + before assuming it can be used. + (check_eliminate_biv): New fn, a piece of strength_reduce broken out. + + * cccp.c (error_from_errno): New fn, like error and perror_with_name. + (do_include): Call that if open fails. + (finclude): Print I/O error msg before closing desc. + + * c-decl.c (shadow_tag): If more than one tag or structure, + or anything other than a tag, warning. + + * c-parse.y (components): Just warn if memb decl has no member, + and only if pedantic. + + * loop.c (strength_reduce): Print uids, not luids, for dump. + (record_giv): giv_count field counts only DEST_REG givs. + (check_dbra_loop): src_two_before_end was set wrong. + + * loop.c (record_giv): New arg LOOP_END; all callers changed. + Don't mark giv replaceable if used past LOOP_END. + (find_mem_givs): New arg LOOP_END; all callers changed. + + * out-i386.c (FP_CALL): Make this a `return' stmt. + +Fri Apr 7 11:56:58 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * expr.c (expand_expr, case ..._DECL): Preserve mode thru + calling change_address. + + * expr.c (emit_library_call): Typo: ARGNUM => COUNT. + + * expr.c (preexpand_calls, expand_call): Take note of RETURN_IN_MEMORY. + * stmt.c (assign_parms): Likewise. + * integrate.c (function_cannot_inline_p): Likewise. + + * STACK_ARGS_ADJUST: Arg is now a `struct arg_data' and it should + be updated in place. + * tm-mips.h: Define it. + * expr.c (expand_call): Adapt to this. Assume padding comes after args + so turn off the feature of changing the args' offsets. + (emit_library_call): Adapt to this. + + * tm-mips.h (PRINT_OPERAND): Use CONST_DOUBLE_{LOW,HIGH}. + Truncate SFmode constants to single precision. + + * c-typeck.c (mark_addressable): Fix test for local vs global reg var. + + * config.gcc: Change `:-' to `-' in var refs. + Shell on convex doesn't handle `:-'. + +Thu Apr 6 00:09:01 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * integrate.c (expand_inline_function): Compare actual's mode + against formal's DECL_ARG_TYPE's mode, not TREE_TYPE's mode. + + * c-decl.c (implicitly_declare): Make the decl permanent if + in global binding level. (Can happen for certain invalid input.) + + * c-typeck.c (build_modify_expr): Block path that made a MODIFY_EXPR + containing an ERROR_MARK. + + * config/tm.h: New file. + + * loop.c (only_reg_use_p): Fix bugs in recursion, add some fast + special cases. Comment on return value was backwards. + (strength_reduce): Negate the value of only_reg_use_p. + + * genoutput.c (output_prologue): Output `#include hard-reg-set.h'. + * Makefile: insn-output.o depends on that. + + * toplev.c (main): Typo recognizing -Wswitch. + + * config.gcc (mips): New alternative. + * tm-mips.h, out-mips.c, mips.md, va-mips.h: New files. + * varargs.h: Include va-mips.h if on mips. + +Wed Apr 5 16:58:04 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * c-decl.c (duplicate_decls): Rename OLD, NEW to OLDDECL, NEWDECL. + + * stmt.c (expand_function_start): Ref subr instead of + current_function_decl; should make no difference. + + * stmt.c (assign_parms): Do extra padding for some parms, + controlled by MAX_PARM_BOUNDARY. + * expr.c (expand_call): Same thing for caller side. + Note this is implemented only for machines that lack push insns. + Also, in both cases, it doesn't handle variable-size args. + +Tue Apr 4 12:22:06 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * gcc.c (find_file): Try STANDARD_EXEC_PREFIX for startfiles too. + + * varasm.c (make_decl_rtl): Delete never-executed clause. + + * spur.md (movqi, loadhi, extend*, zero_extendhisi): + Make subregs with C code, not RTL patterns, so we can + avoid generating subreg of subreg. + + * optabs.c (emit_cmp_insn): Not all clauses always succeed, + so stop using `else' structure. + + * stmt.c (expand_return): Avoid moving void to void, in cleanups case. + +Mon Apr 3 18:04:33 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * m68k.md (cmphi): Don't allow a-reg vs a-reg, since that sign-extends. + If there is one a-reg, make sure it is not last. + +Sun Apr 2 13:02:26 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * stor-layout.c (agg_mode): Use highest mode that has desired size. + Allow all integer modes, but reject sizes > MAX_FIXED_MODE_SIZE. + (That defaults to the size of DImode.) + + * machmode.def: Add PSI, PDI and XF, CXF modes. + +Sat Apr 1 00:50:11 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * ns32k.md (ashd, lshd): Delete patterns that logand the count with 31. + The shift count is not truncated on this machine. + + * combine.c (subst): Simplify nested or's, nested xor's. + (try_distrib): XOR doesn't distribute through anything. + + * rtl.c (rtx_equal_p): Don't die on null pointers. + + * loop.c (eliminate_biv): Use COMPARE, not MINUS, in generated compare. + + * loop.c (invariant_p): Mem refs in constant pool are invariant. + + * c-decl.c (redeclaration_error_message): If -traditional, allow + redeclarations of typedef provided they agree. + + * c-decl.c (start_decl): Do expand_decl on the decl that pushdecl + returns. If there was a prev. decl with a different type, + we have changed its type and cleared its old rtl, so it need new rtl. + +Sat Apr 1 00:50:11 1989 Matthew Self (rms at sugar-bombs.ai.mit.edu) + + * expr.c (convert_move): Modified to use mode classes + instead of refering to specific machine modes. + + * expr.c (do_jump): Converted to use CONST0_RTX macro. + do_jmp no longer refers to any machine modes directly except + for VOIDmode! + + * expr.c (compare, compare1): Modified to use CONST0_RTX + macro. No longer refers to any machine modes directly + except VOIDmode and BLKmode! + + * machmode.def: Documented assumptions made about the order + of machine modes during mode widening. + + * optabs.c (expand_binop, expand_twoval_binop, expand_unop, + emit_cmp_insn): Added mode widening which is independent of + specific machine modes. It assumes that we may widen to any + higher numbered mode of the same mode class. + NOTE: the checks for VOIDmode ops which were present in + QI and HI to SI widening are now present in all widening. + I assume this is correct. Also, widening is now possible + from QI to HI. This may or may not be a good thing.... + + * rtl.h (CONST0_RTX): Added definition of new macro + CONST0_RTX (mode). + + * rtl.h (GET_NOTE_INSN_NAME, GET_REG_NOTE_NAME): New macros. + * rtl.c (note_insn_name, reg_note_name): New tables. + * rtl.def (NOTE): Change last field from `i' to `n'. + * rtl.c (print_rtx): Print mode of INSN_LIST or EXPR_LIST as reg-note. + Print operand code `n' as name of kind of note. + (read_rtx): treat `n' like `i'. + + * loop.c (struct induction): Add `mode' field. + (strength_reduce, record_giv): Set the `mode' field in V. + (can_eliminate_biv_p, eliminate_biv): Use that field. + + * loop.c (struct iv_class): `init_insn' records what inits the biv. + Replaces `init_val_set' flag. + (strength_reduce): Update and test `init_insn' instead. + Use of a biv between its init and the start of the loop + does not preclude its elimination from the loop. + Setting a giv is ok for eliminating a biv, even if giv is "ignore", + since that just means giv will be combined with another. + Handle some DEST_ADDR givs for that purpose. + Test for giv-setting before check can_eliminate_biv_p. + New error check for replaceable giv whose value needed after loop. + (only_reg_use_p): New fn. + + * expr.c (expand_expr): PLUS, MINUS with EXPAND_SUM: + Associate even harder. + + * loop.c (strength_reduce): Treat all constant biv init vals like ints. + + * loop.c (strength_reduce): Clear all_reduced when v->ignore is set; + the code to check this later didn't always do the job. + + * loop.c (verify_loop): Set loop_continue. + (scan_loop): mention its value. + * rtl.h: Define NOTE_INSN_LOOP_CONT. + * stmt.c (expand_loop_continue_here): Output one. + +Fri Mar 31 10:08:29 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * c-typeck.c (pointer_int_sum, pointer_diff): Treat const void * like + void *. + + * rtl.c (rtx_addr_varies_p): Don't die on null exp. + * cse.c (refers_to_mem_p, refers_to_p): Likewise. + + * gcc.c (validate_switches, validate_all_switches): New fns. + Mark a switch as valid if any compiler spec or the linker spec + matches it, even for languages not being used. + +Thu Mar 30 00:22:14 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * loop.c (loop_optimize, move_movables): when moving a `clr' insn used + in zero-extension, sometimes change it to an `and' so that the + significant low bits are not clobbered. + + * cccp.c: Implement __BASE_FILE__ and #once. + (savestring): New fn. + (struct file_name_list): new name for struct directory_stack. + (enum node_type): Add T_ONCE, T_BASE_FILE. + (directive_table): Add #pragma once. + (initialize_builtins): Add __BASE_FILE__. + (special_symbol): Handle __BASE_FILE__, together with __FILE__. + (do_include): Ignore the file if it's on the #pragma once list. + (do_once): New fn; add current file to #pragma once list. + + * cccp.c (do_include): Don't add non-ex files to list of deps. + + * config.gcc: Use {...:-...}, not {...=...}. + + * c-parse.y: Add precedence for IF/ELSE, and for parens; + avoids some conflicts. + + * tm-newsgas.h: Include tm-news.h and define USE_GAS. + + * tm-news.h: New name for tm-news800.h. + If not USE_GAS, define SONY_ASM. + Don't define USE_GAS by default. + (CPP_PREDEFINES): Various alternatives depending on processor type. + (ASM_FORMAT_PRIVATE_NAME): Override this. + (ASM_IDENTIFY_GCC): Override; output nothing. + (FUNCTION_PROLOGUE, FUNCTION_EPILOGUE): Round fsize up to % 4. + Max for halfword link insn is 32k, not 64k. + (FUNCTION_EPILOGUE): Don't output move.l if no regs to restore. + (PRINT_OPERAND_ADDRESS): Change handling of tableref pc-rel addresses. + * m68k.md (movhi): Add SONY_ASM conditional. + + * cse.c (cse_insn): If replacing a dest address, preserve MEM_IN_STRUCT + + * gcc.c (error, fatal): alternate varargs defns if HAVE_VPRINTF. + +Wed Mar 29 09:54:13 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * gcc.c (process_command): Check WORD_SWITCH_TAKES_ARG, so that + -Tdata can be handled right. + + * stmt.c (check_for_full_enumeration_handling): new fn, for warn_switch + (expand_end_case): Call it, if orig index was enum. + * toplev.c (main): Handle -Wswitch. + * c-parse.y (SWITCH stmt): Pass orig switch expr to expand_end_case. + + * tm-*.h, out-*.c: Uniformly use reg_names, not reg_name, and don't + define any duplicates. + * final.c: Delete reg_name. + + * c-parse.y (is_reserved_word): Add keywords __asm and __inline; + also __const and __volatile. + (yylex): Keywords that start with `__' are recognized regardless of + -traditional or -ansi. + + * c-parse.y (check_newline): Always recognize #ident. + Macro IDENT_DIRECTIVE is no more. + If ASM_OUTPUT_IDENT is undefined, don't output anything for #ident. + * tm-3b1.h: Don't define IDENT_DIRECTIVE or ASM_OUTPUT_IDENT. + * tm-encore.h, tm-i386gas.h, tm-i368v.h, tm-sun386i.h, tm-vaxv.h: + Don't define IDENT_DIRECTIVE; define ASM_OUTPUT_IDENT to output in + default way. + + * expr.h (RETURN_IN_MEMORY): New macro, default defn here. + * expr.c (expand_call): Use it to control where to return value. + * stmt.c (expand_function_start): Likewise. + + * out-sparc.c (find_addr_reg): Abort if none found. + Eliminate confusion; do only one change between tests for PLUSness. + (output_move_double): Arg to find_addr_reg is address, not mem ref. + * out-m68k.c, out-spur.c, out-i386.c, out-alliant.c: Likewise. + + * jump.c (find_cross_jump): Don't let either E1 or E2 be included + in the range of matching insns preceding the other (E2 or E1). + + * c-parse.y (check_newline): No error for `#pragma\n'. + + * Makefile (gcc.o): Control STANDARD_STARTFILE_PREFIX here. + + * stmt.c (walk_fixup_memory_subreg): handle null. + + * tm-sparc.h (FUNCTION_BLOCK_PROFILER): Change LPBnn to LPYnn, + to avoid conflict with final.c. + +Tue Mar 28 15:23:17 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * cccp.c (do_include): If fail, print system error message. + (perror_with_name): Use more standard error format. Inc. `errors'. + + * dbxout.c (dbxout_function): Output any temporary types + that were made by dbxout itself. + + * stmt.c: always use an epilogue if pcc-struct-return. + (expand_function_start): Compute return_label after testing that. + (expand_function_end): Output a return insn after pcc-struct-return + processing, if there is a return insn. + (expand_null_return): Don't output a return insn, in that case. + Simplify the conditions--depends entirely on HAVE_return. + + * tm-m68k.h (FUNCTION_BLOCK_PROFILER): Use jsr, not call. + + * reload.c (find_reloads): Certain mem addresses will be offsetable + after reloading; in particular, those where reg_equiv_address applies. + + * loop.c (check_dbra_loop): Change MINUS to COMPARE. + + * c-typeck.c (convert_for_assignment): Return THE standard error_mark. + +Thu Mar 23 09:39:02 1989 Richard M. Stallman (rms at watson) + + * c-parse.y (components): Error if empty. + + * dbxout.c (dbxout_symbol): Output const variables as N_STSYM. + + * varasm.c (force_const_mem): Use ASM_OUTPUT_DOUBLE_INT if defnd. + + * c-decl.c (grokdeclarator): Warn about `long long long'. + + * reload1.c (reload): When changing REG to MEM, clear REG_USERVAR_P. + * final.c (alter_subreg): Preserve volatile bit of MEM. + + * m68k.md (cmpsi, cmphi): Permit cmpm. + + * gcc.c (find_file): Use standard_startfile_prefix_2. + Now search /usr/local/lib/, /lib/ and /usr/lib/. + + * tm-m68k.h (PRINT_OPERAND): Support code `d'. + * m68k.md (cmpsi, cmphi, cmpqi): Use it for all mem addresses. + + * final.c (output_asm_insn): Don't allow %LETTER without an + operand number. + * tm-m68k.h, m68k.md, tm-hp9k320.h, tm-news*.h: Use %@ instead of %s. + * tm-alliant.h, alliant.md: Likewise. + * i386.md, out-i386.h: Put `0' after each %L, %W, %B, %S, %Q, %R. + + * stmt.c (expand_end_stmt_expr): Pop pending stack args. + + * varasm.c (assemble_variable): For 0-size common variable, + allocate at least 1 byte. + + * tm-encore.h (ASM_OUTPUT_DOUBLE, PRINT_OPERAND): Use 0f, not 0l, + for doubles. + +Mon Mar 13 10:24:56 1989 Richard M. Stallman (rms at ccvi) + + * out-i386.h (function_prologue, function_epilogue): + Use call_used_regs, not a copy, so -f options work. + Save regs in the opposite order. + Save regs even starting from 0 if they happen to be call-saved. + + * Bug fixes from Rob McMahon. + + * loop.c (strength_reduce): When inserting insn to set + nonreplaceable giv, put it after all the consecutive insns + that compute it. + + * reload.c (find_reloads): When forcing const to mem, + use the insn's operand mode, not the const's mode. + + * reload1.c (choose_reload_targets): Use wider of inmode and outmode + when determining have_groups. + + * reload1.c (choose_reload_targets): typo checked wrong insn with + constraint_accepts_reg_p. + + * reload1.c (choose_reload_targets): Enable #if-0'd code for + forgetting old reloads in case of output reload from a non-spill-reg. + +Sun Mar 12 00:04:49 1989 Richard M. Stallman (rms at ccvi) + + * c-parse.y (yyerror): Add forward-decl here. + * c-tree.h: Delete decl here. + + * New macro USE_C_ALLOCA. + * cse.c (cse_main): Do alloca (0) to clear out C alloca. + * flow.c (life_analysis): + * local-alloc.c (local_alloc): + * reload1.c (reload_as_needed): likewise. + + * loop.c (emit_iv_init_code, eliminate_biv): + Always put constant in a PLUS last. + + * gcc.c (make_switch): Unused function deleted. + + *gcc.c (switches): Each switch has a `used' field. + (process_command): Init it to 0 when making `switches'. + (do_spec_1, handle_braces, give_switch): Set to 1 when switch is used. + (main): If it remains 0 at the end, print error message. + + * expr.c (convert_move, convert_to_mode): Don't truncate a MEM in + place if it is volatile. + + * loop.c (strength_reduce): When reducing a giv, if the biv is + incremented between the giv's creation and its use, increment + the reduced giv var *after* its use. + + * c-decl.c (duplicate_decls): Warn about proto vs nonproto + only if no other errors apply. + + * jump.c (invert_exp): Don't crash if arg is null. + + * alliant.md (float*i*f2): Don't allow immediate ops. + (sne): Fix typo, fsne => fsneq. + + * expr.c (store_one_arg, expand_call): When size doesn't matter, + pass const0_rtx, not (rtx) 0. + + * expr.c (do_jump): Args to invert_exp were missing. + + * gcc.c (store_arg): Now 2 separate args for delete-on-success + and delete-on-failure. All calls changed. + (do_spec_1): DELETE_THIS_FILE is meaningful for output files. + + * config/xm-alliant.h (LINK_SPEC): Pass -X to linker. + +Sat Mar 11 10:30:41 1989 Richard M. Stallman (rms at ccvi) + + * tm-*.h, xm-*.h, *.md: Moved to subdir `config'. + * output-*.c: Moved to `config/out-*.c'. + * Makefile (.c.o): Define rule to use -Iconfig when compiling. + (various): Delete the commands from some compilation rules. + Put -Iconfig in other compilation commands. + Also some reordering of variable defs and comments for cleanliness. + (realclean): Change a shell comment to a Make comment. + + * fold-const.c (fold): Simplify and extend TRUTH_... operators + knowing that args must be ints and values will be 0 or 1. + + * gcc.hlp: New file (for VMS). + + * reload1.c (reload): Don't let two 2-groups overlap. + + * reload.c (push_reloads): When a plain reg matches a reload + for an increment, don't change the reload_in to a plain reg. + Leave the increment there. + + * integrate.c (expand_inline_function): Don't try to inline + unless the parm machine modes really match what's expected. + + * stmt.c (emit_case_nodes): default_label is an rtx, not tree. + + * tm-next.h (DOLLARS_IN_IDENTIFIERS): Define it as 1. + + * output-sparc.c (output_move_double): Don't trust random structs + to be double-word aligned. + + * gcc.c: Pass -Wcomments to cpp. + + * rtl.def (ASM_OPERANDS): New operands, source file and line. + * rtl.h (ASM_OPERANDS_*): New macros for components of ASM_OPERANDS. + * stmt.c (expand_asm_operands): Use new fields, not REG_ASM_* notes. + * toplev.c (error_for_asm): likewise. + * rtl.h (enum reg_note): Delete REG_ASM_FILE, REG_ASM_LINE. + + * combine.c (try_combine): Check explicitly for volatility in I2, I1. + +Fri Mar 10 19:30:10 1989 Richard M. Stallman (rms at ccvi) + + * c-parse.y (GOTO stmt): Set TREE_USED for the label. + * c-decl.c (poplevel): Warn about unused label. + + * c-decl.c (warn_pointer_arith, warn_strict_prototypes): New vars. + (lang_decode_options): Options to set them. + * c-typeck.c (pointer_int_sum, c_sizeof): Maybe warn if bad target. + * c-decl.c (grokparms): Maybe warn if nonprototype fn decl. + + * flags.h, toplev.c (warn_shadow): New flag. + * toplev.c (main): Decode it. + * c-decl.c (pushdecl): Maybe warn about any shadowing. + Existing parm-shadowing warning now disabled if shadowing decl + is also a parm. + + * flags.h, toplev.c (warn_id_clash, id_clash_len): New flags. + * toplev.c (main): Decode -Wid-clash-LEN. + * tree.c (get_identifier): Implement warning if two idents match. + + * toplev.c (compile_file): Warn about statics defined and unused. + + * rtl.h (CONST0_RTX): New macro. + + * recog.c (offsetable_address_p): New 1st arg says whether to demand + a strictly valid address. + (offsetable_memref_p): Pass nonzero. + * stmt.c (optimize_bit_field): Pass zero. + + * cccp.c (main): Allow -Wcomment like -Wcomments. + * c-decl.c (lang_decode_options): Likewise. + +Sun Mar 5 15:02:59 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * m68k.md [tstdf, cmp[sd]f, truncdfsf2, floatsi[sd]f2, add[sd]f3, + sub[sd]f3, mul[sd]f3, div[sd]f3, neg[sd]f2, abs[sd]f2]: Made sure + that the test function's in the match_operands of the define_expand + and define_insn's matched, and made that test function + "register_operand" when both define_insn's really needed registers + in that spot. + +Sat Mar 4 00:25:37 1989 Richard M. Stallman (rms at c2v) + + * expr.c (emit_push_insn): Don't ever bypass the big-endian + padding at the end. + + * cccp.c (deps_output): Break line if would otherwise exceed 75 chars. + Make a name for that value 75. + + * combine.c (subst): Handle general case of (subreg (sign_extend X)). + + * tm-sun386i.h (CPP_PREDEFINES): Define `sun'. + + * fixincludes: change `find' calls to find dirs thru symlinks. + + * flow.c (mark_set_1): (set (subreg (reg N))...) + does make reg N significant for this basic block. + +Fri Mar 3 13:55:25 1989 Richard M. Stallman (rms at c2v) + + * c-decl.c (parmlist_tags_warning): Print an explanation + for the first such warning. + + * i386.md (extendsfdf): Let op 1 match op0 if that is an fp reg. + + * expr.c (expand_call): Fix stupid errors copying pcc struct value. + + * varasm.c (output_constructor): Discard NOP_EXPRs from build_c_cast. + +Thu Feb 23 05:55:57 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * Version 1.34 released. + + * c-typeck.c (build_c_cast): If EXPR is an error mark, return that. + + * fold-const.c (div_and_round_double): Abort if divisor is 0. + (combine): Likewise, for real constants. + (real_zerop): New subroutine. + (fold): Don't try to fold division if divisor is 0. + Don't try to fold reals if can't do arithmetic on them. + Don't try to compare reals for TRUTH_..._EXPR if can't do arith. + Use real_zerop to test reals for zeroness. + For TRUTH_ANDIF_EXPR and TRUTH_ORIF_EXPR, can simplify based on + first operand alone. + + * c-typeck.c (store_init_value): Fix error msg text. + + * tm-sparc.h (FUNCTION_PROFILER): Use `mcount'. + * tm-sun4os3.h (FUNCTION_PROFILER): Override it; use `.mcount'. + +Wed Feb 22 04:33:22 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * tm-hp9k320.h (CPP_SPEC, CPP_PREDEFINES): Make handling of + -Dmc68000 depend on TARGET_DEFAULT. + + * tm-sparc.h (FUNCTION_PROFILER): Missing newline in fprintf. + + * integrate.c (expand_inline_function): Don't map struct-value-address + in memory if fn does not use it. + + * c-parse.y (check_newline): At skipline, detect eof. + + * stmt.c (uninitialized_vars_warning): Change text of warning. + +Tue Feb 21 03:58:50 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * output-sparc.c (output_mul_insn): Handle case of both args + in reg 8, or both in reg 9. + + * tm-sparc.h (ASM_SPEC): Define, to handle -pipe. + + * tm-sparc.h (FUNCTION_PROFILER): Add omitted fprintf args. + (BLOCK_PROFILER): Likewise. Use tempvar. + + * m68k.md (QImode btst): Allow nonoffsetable mem refs. + +Mon Feb 20 00:32:42 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * flow.c (mark_used_regs): Don't record about global reg vars. + + * config.gcc (convex-*): tm file names are tm-convex1.h, tm-convex2.h. + + * tm-vax.h, tm-ns32k.h, tm-alliant.h: Define PCC_STATIC_STRUCT_RETURN. + + * gcc.c (compilers): Pass `-a' to cc1. + * tm-sun3.h, tm-sparc.h (LIB_SPEC): Define, to handle `-a'. + + * expr.c (emit_push_insn): Copy stack addresses to be passed to bcopy; + old method of preadjustment is broken by changes in emit_library_call. + + * c-decl.c (finish_decl): New temp `temporary'; don't get confused + about whether allocation was temporary. + +Sun Feb 19 17:03:35 1989 Chris Smith (csmith at mozart) + + * tm-convex.h: define PCC_STATIC_STRUCT_RETURN + + * convex.md: + remove pshea patterns, movsi does it better. + add ashift:DI abs:DF abs:SF + (tstdi): use a clobbered register instead of a bogus DImode zero. + (trunchiqi2): delete noninstruction cvth.b + (udivsi3, udivhi3, udivqi3): deleted, expand_divmod does it now. + (call, call_value): delete stupid call/ret -> jump optimization. + (call, call_value): flush call_ap_check, use reg_mentioned_p instead. + + * convex.md: (movxx): swap constraint alternatives so that the + leftmost alternative is (set =g r). This makes (set mem const) + get combinable input reloads of const instead of uncombinable + output reloads to mem. They still do not combine, but wtf, + I'll inch up on it. + + * output-convex.c: (const_double_{high,low}_int): new routines + to pick apart const_doubles for assembler. + +Sun Feb 19 01:40:17 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * sparc.md (shift memory right 24 bits): Another `a1' typo. + + * config.gcc (convex-*): Delete troublesome whitespace. + + * c-decl.c (grokparms): Delete redundant `parm != 0' tests. + + * stmt.c (fixup_memory_subreg): Slight simplification. + + * tm-sparc.h (FUNCTION_PROFILER): Fill delay slot. + (FUNCTION_BLOCK_PROFILER): Use sethi. + (BLOCK_PROFILER): Use %g2, not %g0. Use sethi. + +Sat Feb 18 02:11:25 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * expr.c (expand_expr): Ignore const array's initial value + if it's an error_mark. + * c-decl.c (finish_decl): Set DECL_INITIAL to an error_mark + if the decl is a permanent node. + + * cccp.c (rescan): If traditional, if macro ends inside string, + keep scanning for the end of the string. + (handle_directive): A line of just `#' becomes blank. + (collect_expansion): \ in strings traditionally doesn't hide macro arg. + + * m68k.md, alliant.md (addsi3): New alternative a=r+a, in addition + to old a=a+r, needed since reload-insns are not commuted. + +Fri Feb 17 03:15:23 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * tm-m68k.h (PCC_STATIC_STRUCT_RETURN): Define it. + * toplev.c, flags.h: New var flag_pcc_struct_return. + * stmt.c (expand_function_start): Obey new flag and new variable. + * expr.c (expand_call): Obey new flag and new variable. + * varasm.c (assemble_static_space): New function. + + * stmt.c (expand_return): If we need cleanups, compute retval first + into pseudo reg, then do the cleanups, then copy it to return reg. + +Thu Feb 16 02:59:52 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * regclass.c (init_reg_sets_1): Win if STATIC_CHAIN_REGNUM undefined. + + * expr.c (expand_call): Handle conflict between two precomputed + args that are both function calls returning structures. + + * loop.c (move_movables): Bkwds test of m->partial, for a matching reg. + + * expr.c (emit_library_call, expand_call): Handle STACK_ARGS_ADJUST. + +Wed Feb 15 01:59:15 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * toplev.c (flag_caller_saves): New var, for -fcaller-saves. + DEFAULT_CALLER_SAVES controls initial value. + * global-alloc.c (find_reg): Do caller saves only if flag set. + * local-alloc.c (find_free_reg): Do caller saves only if flag set. + * tm-alliant.h, tm-convex.h: Define DEFAULT_CALLER_SAVES. + +Wed Feb 15 01:59:15 1989 Chris Smith (rms at sugar-bombs.ai.mit.edu) + + * caller-save.c: New file. + * regs.h (CALLER_SAVE_PROFITABLE): New macro. + (reg_n_calls_crossed): new int-vector replaces reg_crosses_calls. + * flow.c (allocate_for_life_analysis, propagate_block, dump_flow_info): + Use reg_n_calls_crossed. + * stupid.c (stupid_mark_refs, stupid_life_analysis): Likewise. + * global-alloc.c (find_reg): Sometimes allocate call-clobbered regs + for call-crossing pseudos. + New arg ACCEPT_CALL_CLOBBERED; callers changed. + * local-alloc.c (find_free_reg): Similar changes. + (qty_n_calls_crossed): New int-vector replaces qty_crosses_calls. + (alloc_qty, local_alloc, combine_regs, find_free_reg): change that var. + * regclass.c (call_fixed_regs, call_fixed_reg_set): new vars. + (init_reg_sets_1): Initialize them. + * reload1.c (reload): Call caller-saves processing if needed. + +Wed Feb 15 01:59:15 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * expr.c (expand_expr): INTEGER_CST for DImode: don't handle + endianness here. So CONST_DOUBLE_LOW is always the low word. + * varasm.c (force_const_mem): Handle it here. + + * expr.c (convert_move): widening followed by extendsidi2 had braino. + + * integrate.c: Don't include ctype.h; not needed and kills Sun cpp. + + * m68k.md (cmpsf, cmpdf and their recognizers): + Replace MINUS with COMPARE. + Also, use VOIDmode for COMPAREs, not SF or DF. + + * optabs.c (sign_expand_binop): Handle ops such as division where + an unsigned char could be widened and handled with signed int insns. + * expmed.c (expand_divmod): Use that. + + * c-typeck.c (digest_init): Allow for type variants in validating + initialization from a string constant. + + * c-typeck.c (decl_constant_value): Disable opt. if pedantic or + outside functions, so that validity of program is never affected. + + * fold-const.c (fold): Signedness-test for ABS_EXPR was backwards. + +Tue Feb 14 01:30:47 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * cccp.c (main): Don't omit normal output, if we want deps on + a separate stream. + + * c-decl.c (grokdeclarator): Don't record any arg types for functions + if -traditional. + + * print-tree.c (prtypeinfo): Mention permanent attribute. + + * tm-next.h: New file. + + * c-typeck.c (decl_constant_value): The DECL_INITIAL may be ERROR_MARK. + + * c-decl.c (duplicate_decls): For fns, new static decl overrides + old non-static one. + + * emit-rtl.c (gen_lowpar, gen_highpart): Use change_address, so we + preserve volatility, etc. + + * stmt.c (expand_expr_stmt): Use emit_filename, emit_lineno + as file and line for any warning. + * emit-rtl.c (emit_line_note): Set those vars. + + * c-decl.c (store_parm_decls): If -Wimplicit, warn of arg with no decl. + + * recog.c (offsetable_address_p): Use strict_memory_address_p, + since called from reload.c. + +Mon Feb 13 03:11:50 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * sparc.md (compare-to-reg patterns): Some still had MINUS. + + * toplev.c (main): Warn if `-a' on system that can't handle it. + + * stmt.c (expand_asm_operands): Delete unused local `val'. + (pushcase_range): Likewise for `value'. + (fixup_var_refs): Likewise for `insn'. + * emit-rtl.c (start_sequence): Likewise for `save'. + * loop.c (scan_loop): Likewise for `before_start'. + * expr.c (expand_expr): Delete label `binop1'. + + * reload1.c (constraint_accepts_reg_p): Handle SUBREGs of REGs. + +Sun Feb 12 05:37:46 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * gnulib.c (__bb_init_func): New function + + * tm-m68k.h (BLOCK_PROFILER, FUNCTION_BLOCK_PROFILER): Defined. + +Sat Feb 11 00:05:55 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * tm-sparc.h (FUNCTION_PROFILER): Make it really work. + (BLOCK_PROFILER, FUNCTION_BLOCK_PROFILER): New macros. + + * final.c (final): Use BLOCK_PROFILER at start of each basic block. + (final_start_function): Use FUNCTION_BLOCK_PROFILER if -a. + (end_final): New fn to output the block-profiling tables. + * toplev.c (profile_block_flag): Set if -a. + (compile_file): Call end_final. + + * combine.c (try_combine): Avoid combining in most cases if I3 + has an inc or dec and I1 or I2 uses the same register. + + * tree.c (size_in_bytes, int_size_in_bytes): Use type's main variant. + + * c-typeck.c (actualparameterlist): Error if parm type is incomplete. + + * expr.c (expand_call): Ignore args that have incomplete type. + +Fri Feb 10 02:26:02 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * c-parse.y (case stmts): strip dummy NOP_EXPRs. + + * reload1.c (reload_as_needed): Clear reg_{has,is}_output_reload here, + (choose_reload_targets): not here. + +Thu Feb 9 01:35:55 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * output-sparc.c (output_mul_by_constant): Forget cc status. + + * stmt.c (assign_parms): Don't put volatile parms in regs. + + * vax.md (jlbs/jlbc recognizers): Move them before jbc/jbs recognizers. + + * cse.c (fold_rtx): Handle (EQ (COMPARE ...) (CONST_INT 0)). + + * c-typeck.c (default_conversion, digest_init): For static const + nonvolatile scalar variable, use its initial value if known. + + * expr.c (expand_expr: case COMPONENT_REF): If containing structure + comes out volatile, leave the component MEM volatile too. + + * hard-reg-set.h: Fix multi-word case macros to swallow semicolon. + + * c-typeck.c (default_conversion): In array=>ptr, volatility + of target type comes from TREE_THIS_VOLATILE, not TREE_VOLATILE. + + * reload1.c (forget_old_reload_1, choose_reload_targets): + New array reg_is_output_reload is converse of reg_has_output_reload. + forget_old_reload_1 needs both. + +Wed Feb 8 01:26:24 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * reload1.c (forget_old_reloads_1): New fn, guts of forget_old_reloads. + Do process a spill reg if it isn't used for reloading in this insn. + (forget_old_reloads): Deleted, replaced with note_stores. + (reload_as_needed): Undo Feb 1 change. + Call forget_old_reloads_1 on pseudos autoincremented and not reloaded. + + * c-typeck.c (convert_for_assignment): Handle variant types. + + * c-decl.c (lang_decode_option): -Wall implies -Wunused. + +Tue Feb 7 01:32:28 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * combine.c (try_combine): Don't try adding outputs to an asm_operands. + + * cse.c (CHEAPER): Don't ever let a hard reg get ahead of a pseudo. + + * stmt.c (fixup_gotos): Don't crash on undef label if THISBLOCK is 0. + + * c-decl.c (parmlist_tags_warning): New fn. + * c-parse.y (parmlist, parmlist_or_identifiers): Call it, + to warn about any tags defined inside the parmlist. + * c-decl.c (grokparms): Don't warn about ptr to incomplete type. + The new warning is better. + +Mon Feb 6 01:11:36 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * expr.c (store_constructor): Incorrect ALIGN arg in store_field calls. + + * c-parse.y (%union): Delete unused alternative. + + * c-decl.c (grokparms): Use main variant to test for ptr to incomplete. + + * c-decl.c (finish_enum): Delete superfluous init for `pair'. + + * cse.c (fold_rtx): Optimize X+0, X-0 in floating point. + Fix typo in PLUS case; omitted value to compare GET_MODE_CLASS against. + (equiv_constant): Allow CONST_DOUBLE. + + * cse.c: Optimize past if-statements that are known to fail. + (cse_insn): If condjump becomes uncond to end of this block, + set cse_skip_to_next_block. + (cse_basic_block): If that happens, ignore rest of block, and maybe + treat next block as part of this one (if tables have room). + Resume insn that starts next basic block to be scanned. + (cse_main): Make room for at least 500 qtys. + (cse_end_of_basic_block): Subroutine broken out of cse_main. + + * c-parse.y (hash, is_reserved_word): Rewrite: new hash technique. + + * c-decl.c (duplicate_decls): Be smart about proto vs nonproto mismatch + involving a function definition. + +Sun Feb 5 17:31:12 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * alliant.md (movdi): Typo in `fmoved'. + (ftruncsf2): Handle moving into fp reg. + + * jump.c (jump_optimize): Typo in testing PRESERVE_DEATH_INFO_REGNO_P. + + * reload1.c (choose_reload_targets): Move all death notes to the + output reload insn. + + * m68k.md (fix_truncsfsi2,fix_truncdfsi2): Use accurate rtl pattern. + + * loop.c (delete_insn_forces): Use presence of REG_RETVAL to check + for value-of-library-call insn. + +Sat Feb 4 18:17:56 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * integrate.c (expand_inline_function): Make addresses of stack + slots valid somehow. + + * tm-3b1.h (DIVSI3_LIBCALL, etc.): Define these macros; avoid gnulib. + + * expmed.c (store_bit_field): Avoid (subreg (mem)) when converting + VALUE1 to SImode. + + * jump.c (jump_optimize): Do delete USE and CLOBBER insns. + This is needed for proper jump optimization. + + * rtl.def (COMPARE): New code. + * *.md (compare and related patterns): Use COMPARE, not MINUS:VOID. + * loop.c (eliminate_biv, can_eliminate_biv_p): Likewise. + * cse.c (fold_rtx, fold_cc0, cse_insn): + * output-m88k.c (output_{f,}compare, output_store): + * output-sparc.c (strict_single_insn_op_p, single_insn_src_p, safe_insn_src_p): + * combine.c (subst): + * jump.c (jump_back_p): + +Fri Feb 3 18:34:27 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * output-i386.c (notice_update_cc): If arith insn sets the cc's, + discard all remnants of previous cc value and flags. + + * sparc.md (ashiftrt mem by 24): Fix typo `a1'. + +Thu Feb 2 14:55:44 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * output-sparc.c (output_mul_insn): Clear the CC status. + +Wed Feb 1 20:01:54 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * Version 1.33 released. + + * reload1.c (reload_as_needed): On entering new basic block, + if it didn't need reload regs, forget all inherited contents of those. + + * tm-alliant.h (NOTICE_UPDATE_CC): Floating moves don't set the cc's. + Also delete the clauses and tests for FPA regs. + +Tue Jan 31 21:51:05 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * config.gcc: Handle convex-c1, convex-c2. + * tm-convex1.h, tm-convex2.h: New files that include tm-convex.h. + * tm-convex.h: Define switches -mnoc1, -mnoc2. + + * config.gcc: rename `nofp' to `nfp', to match the file names. + +Mon Jan 30 22:12:15 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * output-sparc.c (output_delay_insn): Extract the operands, + call alter_subreg, constrain_operands and NOTICE_UPDATE_CC. + So callers other than output_eager_then_insn don't lose. + (output_eager_then_insn): No need to do that stuff. + + * symout.c (symout_block_symbols): Handle (MEM (REG)) for + variable-sized arrays. + + * tm-encore.h (ASM_SPEC): Always pass -j; avoid jump-range lossage. + +Sun Jan 29 17:06:26 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * alliant.md: Fix refs to CONST_DOUBLEs to use CONST_DOUBLE_{HIGH,LOW}. + + * combine.c (subst): (minus (zero_extend ...) (const_int ...)) opt. + now limited to within the context of (set (cc0) ...). + +Sat Jan 28 14:26:08 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * cse.c (fold_cc0): Missing `&' extracting CONST_DOUBLEs. + (fold_rtx): Don't put CONST_DOUBLEs together into a (CONST (PLUS...)). + + * output-convex.c (gen_cmp): Recognize CONST_DOUBLE as a constant. + + * tree.c (build_real_from_int_cst): Typo in REAL_ARITHMETIC case. + + * Makefile (bootstrap2): Don't use bootstrap3 as subroutine. + + * varasm.c (force_const_mem): Put the CONST_DOUBLE on the chain + if its MEM is stored in it; so it can be cleared at end of function. + + * stmt.c (emit_case_nodes): Put a compare before each cond-jump. + Two cond-jumps after one cond is invalid and makes cse produce garbage. + +Fri Jan 27 01:05:01 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * tm-sun2.h (CPP_SPEC): Define __HAVE_68881__ only if -m68881. + + * c-decl.c (start_decl): Don't expand_decl if DECL already has rtl. + (grokparms): If just declaring fcn, incomplete parm type is just + a warning, and don't discard the specified type. + + * expmed.c (expand_divmod): Be smarter about not clobbering args + with intermediate results; one mem can clobber another, and a reg + can clobber a mem. + + * tm-i386.h (FUNCTION_PROFILER): Use LPREFIX. May actually work now. + * tm-i386gas.h: Include tm-bsd386.h, not tm-att386.h. + This means changing asm syntax. + #undef DBX_NO_XREFS and DBX_CONTIN_LENGTH. + + * sparc.md (eager branch peepholes): Don't forget 2nd arg to + safe_insn_src_p. + Don't print warnings. + * output-sparc.c: (strict_single_insn_op_p): Return 0 for floating + REG or MEM, since copying that may take 2 insns. + (operands_satisfy_eager_branch_peephole): require delay insn to + be strict_single_insn_op_p as well as safe_insn_src_p. + (operand_clobbered_before_used_after): Don't print warnings. + + * varasm.c (decode_rtx_const): Clear entire structure incl. gaps. + Avoids spurious hash mismatches. + (force_const_mem): If CONST_DOUBLE, store its CONST_DOUBLE_MEM field. + Also look in that field rather than hashing, to save time. + + * c-typeck.c (build_c_cast): If value is literal, mark NOP_EXPR as so. + (store_init_value): Change error msg. + + * c-decl.c (duplicate_decls): Classify prototype vs nonprototype + mismatches better. + + * tm-3b1.h: Fix comment. + +Wed Jan 25 12:46:50 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * Makefile (cleanlinks): Use -f. + +Tue Jan 24 17:54:16 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * cse.c (canon_hash): Fix paren error in last change. + + * varasm.c (immed_real_const_1): Missing arg to bcmp. + +Mon Jan 23 02:43:45 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * stor-layout.c (layout_type): BLKmode elts force array to be BLKmode. + + * genpeep.c, genoutput.c, genemit.c: Put `#include "real.h"' in output. + + * stmt.c (expand_expr_stmt): No "no effect" warning for error-mark. + + * varargs.h: Rename implicit arg name to __builtin_va_alist + which triggers code in assign_parms. Does this really matter? + + * sparc.md (sne): New define_expand. + (seq recognizers): Handle sne as well. + * output-sparc.c ({strict_,}single_insn_src_p): + Some NEG and MINUS insns are actually 2 asm insns. + (safe_insn_src_p): No floating arith is safe; they can trap. + (eq_or_neq): New fn, for seq/sne recognizers. + + * c-decl.c (grokdeclarator, size of array type): + Strip from SIZE any NOP_EXPRs that don't change anything. + + * reload.c, recog.c: Include real.h so constraint macros can examine + CONST_DOUBLEs. + +Sun Jan 22 04:12:54 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * c-decl.c (init_decl_processing): Define __builtin_saveregs. + * tree.h: likewise. + * expr.c (expand_builtin): Handle it. + + * tm-sparc.h: Define TARGET_EAGER and -meager. + * sparc.md (eager branch peepholes): Reenable, but test TARGET_EAGER. + Change fb insns to use %F. Delete `,a' from some of them. + * jump.c (jump_optimize): Don't delete USE and CLOBBER insns. + + * xm-vms.h (const): Define it as empty. + + * make-cccp.com: Move the rename of cexp_tab.c. + Compile cccp.c with no macro definitions. + + * cccp.c (main): VMS conditional for setting max_include_len. + +Sat Jan 21 12:53:00 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * varargs.h (va_start): On sparc, call __builtin_saveregs. + Delete the old conditional that used va-sparc.h. + Rename macros and locals to start with two underscores. + * va-sparc.h: File deleted. + + * c-decl.c (store_parm_decls): Initialize OTHERS. + + * stmt.c (assign_parms): Obey layout_decl. + +Fri Jan 20 02:19:32 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * cse.c (fold_rtx): For SYMBOL_REF and LABEL_REF, mask address + to 16 bits. + + * tree.h (NUM_TREE_CODES): NUM_TREE_CODE renamed. + +Thu Jan 19 13:53:24 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * c-typeck.c (mark_addressable): For global reg var, report error. + Now returns an int; value of 0 means caller should fail. + All calls (in this file) changed. + + * stor-layout.c (layout_decl): Don't let an more than 1 word + of any aggregate go in any 1 register. (Needed for machines whose + integer regs are 64 bits). + + * tm-convex.h, xm-convex.h, convex.md, output-convex.c: new files. + + * expr.c (convert_move): Use extendqidi2, etc. for converting + small ints to double ints. Use zero_extendsidi2 rather than + clearing the high half. + +Wed Jan 18 01:20:52 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * varasm.c (make_decl_rtl): If global `register' decl is invalid, + make ordinary non-register rtl. + + * output-sparc.c (operand_clobbered_before_used_after): new fn. + (reg_clobbered_p, safe_insn_src_p): New fns. + (single_insn_src_p): Treat constants all as ok, even though not + always literally so. Also accept some SIGN_EXTENDs and ZERO_EXTENDs. + (strict_single_insn_src_p): New fn, like above but is strict + about constants and constant memory addresses. + (relop): New fn. + (output_move_double): Don't make a MEM, and don't use %m. + (output_delayed_branch): New name for output_delay_insn. + Now handle non-small constant operands. + Avoid duplicate loads of g1 for constant addresses. + Use recog_operand directly for output of the delay insn. + (output_delay_insn): Now a completely new fn. + (output_eager_then_insn, next_real_insn_no_labels): New fns. + (operands_satisfy_eager_branch_peephole): New fn. + + * sparc.md: New peepholes for testing a recently used operand. + New peepholes for delayed branches, incl. conditional ones. + ** Some of them commented out because they seem not to work. + (andcc recognizer): Fix typo, missing %. + (bgt): Change bgt to bg in output. + (reversed jumps): Replace with one pattern using match_operand. + It uses %F to output the condition. + (movsi): For round-valued immed const, use just a sethi. + For other immed, use explicit sethi and or. + (movhi, movqi): use `move' for reg source or small int source. + For other immed, use explicit sethi and or. + (movsi, etc.): Handle all constant addresses like SYMBOL_REFs. + (movsf): Delete never-used duplicate code for constant addresses. + (addsi3, subsi3, cse'd multiply): Use sethi and or, rather than set. + (andsi3, iorsi3, xorsi3): Likewise. + (jump): Make an annulled branch. + + * tm-sparc.h (PROMOTE_PROTOTYPES): Define this. + (GO_IF_LEGITIMATE_ADDRESS): Now accept all constant addresses; + also cleaned up. + (NOTICE_UPDATE_CC): Don't change the G1 status when storing in memory. + Assume all PARALLEL insns are peepholes. + (PRINT_OPERAND): New codes C and N for outputting conditions, + either forward or reversed. Also F for reversed floating. + + * jump.c (delete_for_peephole): New function to delete range of insns. + * genpeep.c (gen_peephole): Output code to use this. + + * Makefile (install): Fix typo, had $${name} for $${file}. + +Tue Jan 17 00:00:12 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * i386.md (ashlsi3): Use addl or leal for special cases. + + * c-decl.c (grokdeclarator): Make a non-global VAR_DECL public + if it is external. + + * masm386.c: Clean up formatting. + + * cse.c (fold_rtx): Typo simplifying x|0 or x^0 + when the 0 comes second. + + * expmed.c (store_fixed_bit_field): For halfwords, verify that + the field fits in an *aligned* halfword. + (extract_fixed_bit_field): likewise. + + * expmed.c (store_split_bit_field): New arg align, passed in from + store_fixed_bit_field and passed back to it. + (extract_split_bit_field): likewise. + + * expr.c: Reinsert changes from Jan 2, mysteriously deleted Jan 3. + Also changes from Dec 23, Dec 28 and Dec 29. + + * tm-i386.h: Likewise for changes from Dec 30. + + * c-typeck.c (build_component_ref): If field's type is error-mark, + return an error-mark. + +Mon Jan 16 14:16:54 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * genpeep.c (main): Output code to exit early if insn is followed + by a barrier. + (gen_peephole): Reject barriers just like labels. + + * stmt.c (do_jump_if_equal): New arg UNSIGNEDP, for emit_cmp_insn. + Caller changed. Now static. + + * final.c (final): Set INSN_DELETED_P in insns when output. + + * final.c (final): Re-set BODY if peephole does anything. + + * c-decl.c (grokparms): Ignore anything but PARM_DECLs in the list. + (store_parm_decls): If we had a prototype, separate out anything other + than a PARM_DECL declared in it, and pushdecl those at the end, + after DECL_ARGUMENTS is set. + + * stmt.c (expand_end_case): Do stack adjusts after computing index. + + * expr.c (store_one_arg): Handle padding for case of BLKmode + for which space was preallocated. + + * integrate.c (copy_rtx_and_substitute): When copying asm insn, + preserve sharing of the input-operand vectors. + (expand_inline_function): Clear {orig,copy}_asm_operands_vector + to make that mechanism work. + (save_for_inline, copy_for_inline): Likewise. + + * stmt.c (expand_asm_operands): Reject `+' in constraints. + Every output constraint requires `='; inputs reject it. + + * stmt.c (expand_function_end): Arg to fixup_gotos was missing. + +Sun Jan 15 00:28:23 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * cccp.c, gcc.c (main): Handle SIGPIPE. + (pipe_closed): New fn; report suitable fatal error. + + * loop.c (loop_optimize): Initialize moved_once. + + * gcc.c (do_spec): Don't call `execute' if value != 0. + Delete redundant second call to do_spec_1. + + * toplev.c (compile_file): Make declared-but-not-defined warnings + only if -Wunused. + + * stmt.c (emit_case_nodes): Fix typo setting gen_ble_pat. + + * tm-sparc.h ({U,}MODSI3_LIBCALL): Name was wrong. + + * gcc.c (env_exec_prefix refs): Don't try to open via it if it's null. + + * output-sparc.c (output_store, output_load_{fixed,floating}): + Fixed confusions between the mem ref and its address. + + * cse.c (canon_hash): global_regs has entries only for hard regs. + * flow.c (insn_dead_p, mark_set_p, mark_used_regs): Likewise. + + * cse.c (fold_rtx): More simplifications for MULT, IOR, AND, XOR + DIV and shifts with one arg 0 or 1. + +Sat Jan 14 11:41:11 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * c-typeck.c (build_array_ref): If pedantic, check for regdecl arrays. + + * fixincludes: Make all subdirs in advance, so no need for `dirname'. + + * genpeep.c (gen_peephole): Delete code to increment LABEL_NUSES; + instead, clear JUMP_LABEL for any jumps being deleted. + No need to test INSN1 for being a label, since not called then. + [If any of the matched insns is a JUMP_INSN, set want_jump, + and in that case make the matched peephole a JUMP_INSN itself.] + That's in an #if 0 now; it's good in jump, but not in final. + + * jump.c (jump_optimize): Don't do peepholes here. + * final.c (final): Do them here. + + * jump.c (jump_optimize): In optimizing `if (foo) bar; else break;', + don't try to invert anything but a standard-looking conditional jump. + + * jump.c (jump_optimize): Do peepholes on ALL BUT the first pass. + + * gcc.c (env_exec_prefix): New var used like user_exec_prefix + but set from envvar GCC_EXEC_PREFIX. + +Fri Jan 13 13:21:59 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * genpeep.c (gen_peephole): Test INSN1 for a label at the very start, + then test following insns at the end of the loop. + + * sparc.md (call recognizers): do CC_STATUS_INIT, for %g1. + +Thu Jan 12 02:13:49 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * varasm.c (make_decl_rtl): Recognize more error cases for reg vars: + BLKmode, or initializer given. + Distinguisn missing asm from invalid name. + + * expr.c (expand_call): Never return 0; return const0_rtx instead. + This makes expand_expr more uniform. + + * c-decl.c (grokparms): For ptr to incomplete type, just warn; + don't change the parm's type. + + * stmt.c (expand_return): Set RETVAL_RHS so as to recognize + tail-recursive fcn returning void. + Unconditionally test value of expand_expr for being a REG. + + * reload.c (find_reloads): Don't process insns that have + no constraint alternatives. No more need for have_constraints. + + * recog.c (constrain_operands): New local var nalternatives. + Don't bother checking the insn if nalternatives is 0. + +Wed Jan 11 01:27:48 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * Implement global register decls. + + * varasm.c (make_decl_rtl): Handle global register vars. + (make_function_rtl): Set function_defined: after 1st function dfn. + (assemble_variable): Ignore global register vars. + + * c-decl.c (grokdeclarator): Don't reject global register decls. + (builtin_function): Use make_decl_rtl, not make_function_rtl, + to avoid setting function_defined. + + * regclass.c (init_reg_class{,_1}): Init and process global_regs. + They are fixed, and call-clobbered. + + * flow.c (insn_dead_p): Storing one of global_regs is never dead. + (mark_used_regs, mark_set_1): A global reg is never dead. + + * cse.c (canon_hash): Consider global regs volatile. + + + * expr.c (do_jump): Know how to invert jumps which are sequences. + + * dbxout.c, symout.c, final.c: On USG, use our own stab.h. + + * tm-i386gas.h: New file for GAS on sysV (with DBX debugging info). + + * m68k.md (bfchg and bfins patterns): Make # alternatives uniform. + * alliant.md: Likewise; also in movdf patterns. + + * genoutput.c (output_epilogue): Spurious `break' disabled + error check for mismatched # of alternatives. + (output_epilogue, scan_operands): Errors in input are not fatal. + + * flow.c (regno_uninitialized): Avoid crash if no basic blocks. + + * sparc.md (move insns): Delete special patterns that handled + symbolic constant addresses. The main move patterns now do this. + * output-sparc.c (output_store, output_load_{fixed,floating}): + Subroutines to do the work for this; has the code from those + special patterns. Also fixed bugs in testing against cc_status.mdep. + + * output-sparc.c (output_delay_insn): Clear the CC status. + This is necessary for %g1 in the case of a call insn. + + * tm-i386.h (REG_CLASS_CONTENTS): INDEX_REGS is now all but ESP. + (REGNO_REG_CLASS): Corresponding change. + (REG_CLASS_FROM_LETTER): Eliminate `x' letter since not used. + + * optabs.c (emit_cmp_insn): New arg ALIGN, used for BLKmode. + All callers changed. + Pass alignment (as rtx) as 4th arg to cmpstr gen functions. + Use cmpstrhi if available. + * expr.c (compare): Only this call passes a nonzero ALIGN. + + * expr.c (emit_push_insn, emit_block_move): Pass alignment (as rtx) + as 4th arg to movstr gen functions. + +Tue Jan 10 23:43:05 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * stor-layout.c (layout_type): Use BLKmode, if a struct isn't + aligned well enough for a scalar mode. + + * expr.c (expand_expr): For static CONSTRUCTOR, ensure memory + address is made valid. + + * genpeep.c (match_rtx): For MATCH_OPERATOR, set max_opno, n_operands. + +Mon Jan 9 17:07:56 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * varasm.c (output_constant): Split strings every 2000 chars. + + * stmt.c (expand_end_case): Test bkwds, handling constant switch arg. + +Fri Jan 6 09:11:20 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * output-sparc.c (output_delay_insn): Add parens to first if test. + (output_move_double): Turn addr for `sethi' into MEM for %m. + + * c-typeck.c (convert_for_assignment): move test for ERROR_MARK. + + * c-parse.y (unary_expr): Allow cast_expr as arg of unary op. + + * stmt.c (expand_decl): Don't abort if FUNCTION_DECL lacks rtl; + assemble_variable is called after this. + + * c-parse.y (primary -> identifier): Separate case for undeclared + identifier outside of functions; avoids confusing error msgs. + +Thu Jan 5 01:24:47 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * Makefile (install): Ignore errors in all `if' commands. + Create $(libdir) if nec. + + * Makefile (insn-*.[ch]): Put in empty commands. May help Ultrix Make. + + * stmt.c (emit_case_nodes): New arg UNSIGNEDP says do unsigned jumps. + Arg INDEX is an rtx, not a tree. + (expand_end_case): Pass that arg. + (node_has_{low,high}_bound): check for overflow, avoid confusion. + +Wed Jan 4 02:24:21 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * sparc.md (movdi, movdf): Use `&' constraint when loading reg from; + otherwise can lose on (set (reg X) (mem (plus (reg X) (reg X+1)))). + + * expr.c (emit_push_insn): For memory scalar partially going in regs, + copy each word to reg before pushing. Avoids memory-to-memory move. + Make the displaced address valid. + Also delete unfinished STACK_OFFSET variable. + + * c-parse.y (check_newline): Read just one #-directive and return. + This prevents lossage when toplev.c calls it to get the main input file + name, and it gets a following #ident as well. + + * c-decl.c (lang_decode_option): Set warn_cast_qual for -Wcast-qual. + * c-typeck.c (build_c_cast): Issue some warnings if set. + + * tm-3b1.h (ASM_OUTPUT_CASE_LABEL): Missing `;'. + +Tue Jan 3 18:07:31 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * expr.c (emit_library_call): Do force_operand on each operand + if it isn't a REG, MEM or constant. + Do this, or mode conversions, earlier, before loading any hard regs. + + * m68k.md (addsi3) [SGS]: Put a zero displacement in the `lea'. + + * c-typeck.c (default_conversion): Don't lose `const' or `volatile' + when converting array type to pointer. + +Mon Jan 2 01:18:01 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * expmed.c (store_bit_field, store_fixed_bit_field): New arg, + alignment in bytes the structure is known to have. + (store_fixed_bit_field): Handle working in halfwords, + in case the pointer isn't known to have fullword alignment. + * expmed.c (extract_bit_field, extract_fixed_bit_field): likewise. + (extract_bit_field): fix unsignedp arg to extract_fixed_bit_field. + * expr.c (store_field): New arg, passed to {store,extract}_bit_field + (expand_assignment, store_constructor): Pass that arg. + (expand_expr): Pass new arg to extract_bit_field. + + * m68k.md (casesi_2 recognizer): Offset always 6 for 3b1. + + * c-typeck.c (convert_for_assignment): Strip from rhs no-op NOP_EXPRs + put on by build_c_cast (to make the result not an lvalue). + (build_modify_expr, build_compound_expr): likewise. + (build_conditional_expr): likewise. + (actualparameterlist, build_function_call): likewise. + (default_conversion, truthvalue_conversion): likewise. + + * loop.c (move_movables): If reg has moved out of one loop, + divide `savings' by 2. + +Sun Jan 1 03:00:07 1989 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * c-typeck.c (truthvalue_conversion): Distribute the conversion + into the arms of a COND_EXPR. + + * cse.c (fold_rtx): Don't fold a MINUS with VOIDmode + into a symbolic constant--it's incorrect. + + * cse.c (cse_insn): If SRC is a subreg with known value, simplify it. + + * integrate.c (copy_rtx_and_substitute): Allow a ref to a part of + MEM parm whose actual parm is a reg, provided it refs + the low part of the MEM. + (function_cannot_inline_p): Don't inline functions which have + aggregate parameters and take their addresses. This could produce + refs to non-low-parts, which copy_rtx_and_substitute can't handle. + + * c-typeck.c (build_modify_expr): If lhs is COND_EXPR, + make a COMPOUND_EXPR to ensure the rhs is computed before the branch. + + * Implement -pipe. + * gcc.c (do_spec_1): `|' is now a special delimiter + which goes in the argbuf. + When a newline is preceded by a `|', delete it if no -pipe. + Otherwise, don't execute yet, and keep scanning. + (do_spec): At end, if we have stuff with no newline, execute it. + (handle_braces): Implement %{|foo:...}. + (execute): If argbuf contains some `|'s, run several processes + and pipe them together. + (pexecute): new subroutine to make one of the processes. + (find_exec_file): new fn to search for program to execute. + (record_temp_file): new arg FAIL_ONLY. + (store_arg): 2nd arg == 3 means delete file on failure. + This is used for output files. + (delete_temp_files): delete certain files only if fail. + + * cccp.c (include_defaults): /usr/include before /usr/local/include. + + * recog.c (asm_noperands): 1-off in loop checking CLOBBERS + when no output operands and PARALLEL. + + * expmed.c (negate_rtx): Sign-extend the high bits rather than clear. + + * cse.c (fold_rtx): fold negation of real values. + (fold_cc0): fold comparisons on real values. + + * Makefile (install): Use $(INSTALL) for gcc.1 and files in USER_H. + + * Handle floating-point problems for cross-compilation. + + * real.h (CONST_DOUBLE_LOW, etc.): new macros to access CONST_DOUBLE. + * varasm.c (immed_double_const, decode_rtx_const): Use these. + ({force,clear}_const_double_mem): Likewise. + * output-*.c (output_move_double): Use these. + * output-m68k.c (standard_{68881,sun_fpa}_constant_p): Likewise. + * tm-*.h (PRINT_OPERAND): Use these. + * output-i386.c (print_operand): Use these. + * final.c (output_addr_const): Likewise. + * emit-rtl.c (gen_rtx): Delete special code for CONST_DOUBLE. + + * real.h (union real_extract): Portable type for storing real as ints. + * varasm.c (immed_double_const, decode_rtx_const): Use these. + + * varasm.c (immed_real_const_1, decode_rtx_const): + Don't assume REAL_VALUE_TYPE is 2 ints long. + * emit-rtl.c (init_emit_once): Likewise. + + * real.h (REAL_VALUE_TYPE): Define as `double' if not defined. + (REAL_IS_NOT_DOUBLE): Define this if default REAL_VALUE_TYPE not used. + (REAL_VALUES_EQUAL, REAL_VALUES_LESS): Define, if not already defined. + (REAL_VALUE_LDEXP, REAL_VALUE_ATOF): Likewise. + * tree.h (struct tree_real_cst): Use REAL_VALUE_TYPE for the value. + + * rtl.c (init_rtl): Increase length of CONST_DOUBLE if REAL_VALUE_TYPE + needs more space. Change the rtx_format element to match. + * varasm.c (immed_real_const_1): 1st arg now has REAL_VALUE_TYPE. + (force_const_mem): Assume a CONST_DOUBLE contains REAL_VALUE_TYPE. + * emit-rtl.c (init_emit_once): Likewise. + And use REAL_VALUE_ATOF to get a floating zero. + * optabs.c (expand_float): Use REAL_VALUE_TYPE, REAL_VALUE_LDEXP. + * c-parse.y (yylex): Likewise, and use REAL_VALUE_ATOF. + * fold-const.c (split_tree): Don't accept REAL_CSTs. + (combine, fold_convert, fold): Use REAL_ARITHMETIC if defined; + else don't fold reals if they are not doubles. + * tree.c (build_real_from_int_cst): Likewise. + * print-tree.c (dump) [REAL_IS_NOT_DOUBLE]: output float value + in hex, since we don't know how to do it right. + +Sat Dec 31 14:15:13 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * optabs.c (init_optabs): Handle new macros {U,}MULSI3_LIBCALL, + DIVSI3_LIBCALL, MODSI3_LIBCALL. + * tm-sparc.h: Define {,U}{MUL,DIV,MOD}SI3 to call Sun's library direct. + + * tm-sun3-nfp.h, tm-sun3-fpa.h: New files. + +Fri Dec 30 00:14:36 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * cccp.c (main): Certain envvars specify a file to write deps info to. + + * toplev.c (compile_file): Warn about undefined fns declared static. + + * m68k.md (casesi_2 recognizer) [SGS] RTX_INTEGRATED_P test backwards. + * tm-3b1.h (ASM_OUTPUT_CASE_LABEL): Likewise. Also missing `\'. + + * reload1.c (count_occurrences): New function. + (choose_reload_targets): Don't delete a reload if the same reg + is used elsewhere in the current insn. + (delete_output_reload): code split out from choose_reload_targets. + + * c-typeck.c (build_c_cast): Always put on some operator, + so the cast is never an lvalue for strict ANSI. + + * c-typeck.c (initializer_constant_valid_p): Don't depend on + distinction between NOP_EXPR and CONVERT_EXPR. + + * c-convert.c: Fns reordered; new comments. + + * fold-const.c (fold): If simplifying a NOP_EXPR within a BIT_AND_EXPR, + return a NOP_EXPR. + New var TYPE holds type of expr. + + * c-parse.y (expr_no_commas): Split off cast_expr and unary_expr, + to reject `sizeof (int) foo'. + + * toplev.c (main): Treat plain `-' as input filename. + + * final.c (final): If an insn's output routine returns 0, + it means to output the deleted compare insn immediately preceding. + + * m68k.md (branch insns): Use 0 as 3rd arg for OUTPUT_JUMP + rather than explicitly clearing the overflow flag. + + * tm-i386.h (OUTPUT_JUMP): Really use NO_OV; don't abort. + * i386.md (branch insns): Put real data (sometimes 0) in 3rd arg + of OUTPUT_JUMP. 0 means preceding test may not be deleted. + (lea pattern): Clear the cc's. + * output-i386.c (notice_update_cc): various arith insns set the cc's. + +Thu Dec 29 13:22:01 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * stmt.c (expand_decl_init): Do nothing for static decls. + + * reload.c (find_reloads_address{,_1}): Return 1 iff entire arg + was reloaded as a whole, else 0. + (find_reload): If find_reloads_address returns 1, don't let that MEM + satisfy a `>' or `<' constraint. + + * m68k.md (cmpmb): Delete special pattern, make cmpqi handle it. + The special pattern couldn't handle reloading the incremented register. + + * integrate.c (copy_rtx_and_substitute): Test BYTES_BIG_ENDIAN, + not BITS... + + * combine.c (subst): Consider big-endian correction + when simplifying (subreg (mem ...) ...). + + * reload.c (find_reloads): Don't crash if matching operands in `asm' + are both read or both write. + + * expr.c (emit_push_insn): Address for movstr must be XINNER, not X. + + * toplev.c (main): Typo parsing `-fno...'. + +Wed Dec 28 13:07:21 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * toplev.c (rest_of_compilation): `volatile' fns need jump_optimize + for warnings, as if -Wreturn-type. + * c-typeck.c (c_expand_return): Warn about `return' in a `volatile' fn. + * c-decl.c (finish_function): Warn if `volatile' fn can drop thru end. + + * cse.c (canon_reg): Handle nulls as subexpressions. + (fold_rtx, canon_hash, mention_regs, exp_equiv_p): Likewise. + * loop.c (invariant_p, replace_regs, replace_call_address, may_trap_p, + {basic,general}_induction_var): Likewise. + + * expr.c (expand_call): Handle `const' functions: + Local IS_CONST is 1 if function is const. + Attach REG_RETVAL and REG_LIBCALL notes around the call. + Copy fn address to register outside of those notes. + Likewise precompute all parms outside them. + + * expr.c (expand_call): If fn is volatile, emit barrier after the call. + + * c-decl.c (grokdeclarator): Allow function declared const or volatile. + +Sat Dec 24 18:40:12 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * integrate.c (function_cannot_inline_p): If STRUCT_VALUE_INCOMING + or STRUCT_VALUE is defined, can't inline functions returning BLKmode. + +Fri Dec 23 13:26:26 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * expr.c (store_constructor): Compute array's size + with int_size_in_bytes. + + * varasm.c (assemble_variable): If shared data, go to data section + before outputting an uninitialized symbol. + + * tm-sequent.h (ASM_OUTPUT_ALIGN_CODE): Missing backslash. + (SHARED_SECTION_ASM_OP): Macro defined. + * tm-seq386.h (SHARED_SECTION_ASM_OP): Macro defined. + + * c-typeck.c (c_expand_asm_operands): Warn if output op is `const'. + + * Fix problem where a stmt expr in an initialization + refers to the variable it is initializing. + * stmt.c (expand_decl_init): New fn split out from `expand_decl'. + * c-decl.c (finish_decl): Call that. + Don't call expand_decl if already done. + (start_decl): Call expand_decl if type is complete already. + + * Makefile (install): Typo in ranlib command. + +Thu Dec 22 15:57:12 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * tree.h (tree_identifier): New field. + (IDENTIFIER_ERROR_LOCUS): Accessor for it. + * c-parse.y (primary => IDENTIFIER): + Undeclared variable gets one err msg per function it appears in. + + * ns32k.md (andsi3): Delete extra brace. + + * alliant.md, xm-alliant.h, tm-alliant.h, output-alliant.c: New files. + + * combine.c (SUBST, SUBST_INT): Store new field `is_int'. + (copy_substitutions): Don't copy an int as an rtx. + + * Makefile (INSTALL): Install gcc.1 properly. + + * tm-ns32k.h (FUNCTION_PROLOGUE, ASM_OUTPUT_ALIGN_CODE): + Add missing backslashes. + +See file OChangeLog. + +Local Variables: +mode: indented-text +left-margin: 8 +fill-column: 76 +version-control: never +End: diff --git a/gcc-1.40/INSTALL b/gcc-1.40/INSTALL new file mode 100644 index 0000000..f6c2fd4 --- /dev/null +++ b/gcc-1.40/INSTALL @@ -0,0 +1,860 @@ +This is a copy of one node from the Info file gcc.info-3. +For full information on installing and porting GCC, refer to the +GCC manual: + + Info file gcc.info + TeX output gcc.dvi + TeX source gcc.texinfo + +Installing GNU CC +***************** + + Here is the procedure for installing GNU CC on a Unix system. + +* Menu: + +* Other Dir:: Compiling in a separate directory (not where the source is). +* Sun Install:: See below for installation on the Sun. +* 3B1 Install:: See below for installation on the 3B1. +* SCO Install:: See below for installation on SCO System V 3.2. (Or ESIX.) +* VMS Install:: See below for installation on VMS. +* HPUX Install:: See below for installation on HPUX. +* Tower Install:: See below for installation on an NCR Tower. + + 1. Edit `Makefile'. If you are using HPUX, or any form of system + V, you must make a few changes described in comments at the + beginning of the file. Genix requires changes also, and so does + the Pyramid. + + 2. On a Sequent system, go to the Berkeley universe. + + 3. Choose configuration files. The easy way to do this is to run + the command file `config.gcc' with a single argument, which + specifies the type of machine (and in some cases which operating + system). + + Here is a list of the possible arguments: + + `vax' + Vaxes running BSD. + + `vms' + Vaxes running VMS. + + `vax-sysv' + Vaxes running system V. + + `i386-sysv' + Intel 386 PCs running system V. + + `i386-sysv-gas' + Intel 386 PCs running system V, using the GNU assembler and + GNU linker. + + `sequent-i386' + Sequent with Intel 386 processors. + + `i386-aix' + Intel 386 PCs or PS/2s running AIX. + + `sun2' + Sun 2 running system version 2 or 3. + + `sun3' + Sun 3 running system version 4, with 68881. Note there we + do not provide a configuration file to use an FPA by + default, because programs that establish signal handlers + for floating point traps inherently cannot work with the FPA. + + `sun3-nfp' + Sun 3 running system version 4, without 68881. + + `sun4' + Sun 4 running system version 4. *Note Incompatibilities::, + for calling convention incompatibilities on the Sun 4 + (sparc). + + `sun2-os4' + Sun 2 running system version 4. + + `sun3-os3' + Sun 3 running system version 2 or 3, with 68881. + + `sun3-nfp-os3' + Sun 3 running system version 2 or 3, without 68881. + + `sun4-os3' + Sun 4 running system version 2 or 3. *Note + Incompatibilities::, for calling convention + incompatibilities on the Sun 4 (sparc). + + `sun386' + Sun 386 ("roadrunner"). + + `alliant' + Alliant FX/8 computer. Note that the standard installed C + compiler in Concentrix 5.0 has a bug which prevent it from + compiling GNU CC correctly. You can patch the compiler bug + as follows: + + cp /bin/pcc ./pcc + adb -w ./pcc - << EOF + 15f6?w 6610 + EOF + + Then you must use the `-ip12' option when compiling GNU CC + with the patched compiler, as shown here: + + make CC="./pcc -ip12" CFLAGS=-w + + Note also that Alliant's version of DBX does not manage to + work with the output from GNU CC. + + `tahoe' + The tahoe computer (running BSD, and using DBX). + + `decstation' + The DEC 3100 Mips machine ("pmax"). Note that GNU CC + cannot generate debugging information in the unusual format + used on the Mips. + + `mips-sysv' + The Mips computer, RS series, with the System V environment + as default. Note that GNU CC cannot generate debugging + information in the unusual format used on the Mips. + + `mips-bsd43' + The Mips computer, RS series, with the BSD 4.3 environment + as default. Note that GNU CC cannot generate debugging + information in the unusual format used on the Mips. + + `mips' + The Mips computer, M series. Note that GNU CC cannot + generate debugging information in the unusual format used + on the Mips. + + `iris' + Another variant of the Mips computer, the Silicon Graphics + Iris 4D. Note that GNU CC cannot generate debugging + information in the unusual format used on the Mips. + + `convex-c1' + Convex C1 computer. With operating system version 9, use + `cc -pcc' as the compilation command when building stage 1 + of GNU CC. + + `convex-c2' + Convex C2 computer. With operating system version 9, use + `cc -pcc' as the compilation command when building stage 1 + of GNU CC. + + `pyramid' + Pyramid computer. + + `hp9k320' + HP 9000 series 300 using HPUX assembler. Note there is no + support in GNU CC for HP's debugger; thus, `-g' is not + available in this configuration. + + `hp9k320-gas' + HP 9000 series 300 using GNU assembler, linker and debugger. + This requires the HP-adapt package, which is available + along with the GNU linker as part of the "binutils" + distribution. This is on the GNU CC distribution tape. + + `hp9k320-old' + HP 9000 series 300 using HPUX assembler, in operating + system versions older than 6.5. Note there is no support + in GNU CC for HP's debugger; thus, `-g' is not available in + this configuration. + + `hp9k320-bsd' + HP 9000 series 300 running BSD. + + `hp9k200-bsd' + HP 9000 series 200 running BSD. Note that the C compiler + that comes with this system cannot compile GNU CC; contact + `law@super.org' to get binaries of GNU CC for + bootstrapping. Additionally, a minor patch is necessary if + you wish to build kernels with GNU CC; contact + `law@super.org' to get a copy of the patch. + + `isi68' + ISI 68000 or 68020 system with a 68881. + + `isi68-nfp' + ISI 68000 or 68020 system without a 68881. + + `news800' + Sony NEWS 68020 system. + + `next' + NeXT system. + + `tower' + NCR Tower 32 system. + + `altos' + Altos 3068. Note that you must use the GNU assembler, + linker and debugger, with COFF-encapsulation. Also, you + must fix a kernel bug. Details in the file `ALTOS-README'. + + `3b1' + AT&T 3b1, a.k.a. 7300 PC. Note that special procedures are + needed to compile GNU CC with this machine's standard C + compiler, due to bugs in that compiler. *Note 3b1 + Install::. You can bootstrap it more easily with previous + versions of GNU CC if you have them. + + `3b1-gas' + AT&T 3b1 using the GNU assembler. + + `sequent-ns32k' + Sequent containing ns32000 processors. + + `encore' + Encore ns32000 system. + + `genix' + National Semiconductor ns32000 system. + + `88000' + Motorola 88000 processor. This port is not finished. + + Here we spell out what files need to be set up: + + * Make a symbolic link named `config.h' to the top-level + config file for the machine you are using (*note + Config::.). This file is responsible for defining + information about the host machine. It includes `tm.h'. + + The file is located in the subdirectory `config'. Its name + should be `xm-MACHINE.h', with these exceptions: + + `xm-vms.h' + for vaxen running VMS. + + `xm-vaxv.h' + for vaxen running system V. + + `xm-i386v.h' + for Intel 80386's running system V. + + `xm-sun386i.h' + for Sun roadrunner running any version of the + operating system. + + `xm-hp9k320.h' + for the HP 9000 series 300. + + `xm-genix.h' + for the ns32000 running Genix + + If your system does not support symbolic links, you might + want to set up `config.h' to contain a `#include' command + which refers to the appropriate file. + + * Make a symbolic link named `tm.h' to the + machine-description macro file for your machine. It should + be in the subdirectory `config' and its name should be + `tm-MACHINE.h'. + + If your system is a 68000, don't use the file `tm-m68k.h' + directly. Instead, use one of these files: + + `tm-sun3.h' + for Sun 3 machines with 68881. + + `tm-sun3-nfp.h' + for Sun 3 machines with no hardware floating point. + + `tm-sun3os3.h' + for Sun 3 machines with 68881, running Sunos version 3. + + `tm-sun3os3nf.h' + for Sun 3 machines with no hardware floating point, + running Sunos version 3. + + `tm-sun2.h' + for Sun 2 machines. + + `tm-3b1.h' + for AT&T 3b1 (aka 7300 Unix PC). + + `tm-isi68.h' + for Integrated Solutions systems. This file assumes + you use the GNU assembler. + + `tm-isi68-nfp.h' + for Integrated Solutions systems without a 68881. + This file assumes you use the GNU assembler. + + `tm-news800.h' + for Sony NEWS systems. + + `tm-hp9k320.h' + for HPUX systems, if you are using GNU CC with the + system's assembler and linker. + + `tm-hp9k320g.h' + for HPUX systems, if you are using the GNU assembler, + linker and other utilities. Not all of the pieces of + GNU software needed for this mode of operation are as + yet in distribution; full instructions will appear + here in the future. + + `tm-tower-as.h' + for NCR Tower 32 systems, using the standard system + assembler. + + For the vax, use `tm-vax.h' on BSD Unix, `tm-vaxv.h' on + system V, or `tm-vms.h' on VMS. + + For the Motorola 88000, use `tm-m88k.h'. The support for + the 88000 does not currently work; it requires extensive + changes which we hope to reconcile in version 2. + + For the 80386, don't use `tm-i386.h' directly. Use + `tm-i386v.h' if the target machine is running system V, + `tm-i386gas.h' if it is running system V but you are using + the GNU assembler and linker, `tm-seq386.h' for a Sequent + 386 system, or `tm-compaq.h' for a Compaq, or + `tm-sun386i.h' for a Sun 386 system. + + For the Mips computer, there are five choices: `tm-mips.h' + for the M series, `tm-mips-bsd.h' for the RS series with + BSD, `tm-mips-sysv.h' for the RS series with System V, + `tm-iris.h' for the Iris version of the machine, and + `tm-decstatn.h' for the Decstation. + + For the 32000, use `tm-sequent.h' if you are using a + Sequent machine, or `tm-encore.h' for an Encore machine, or + `tm-genix.h' if you are using Genix version 3; otherwise, + perhaps `tm-ns32k.h' will work for you. + + Note that Genix has bugs in `alloca' and `malloc'; you must + get the compiled versions of these from GNU Emacs and edit + GNU CC's `Makefile' to use them. + + Note that Encore systems are supported only under BSD. + + For Sparc (Sun 4) machines, use `tm-sparc.h' with operating + system version 4, and `tm-sun4os3.h' with system version 3. + + For Convex systems before version 8.1, use `tm-conv1os7.h' + or `tm-conv2os7.h'. For versions 8.1 and greater, use + `tm-convex1.h' or `tm-convex2.h'. You should also + bootstrap GCC with `pcc' rather than `cc'; one way to do + this is with the following commands. + + ln -s /bin/pcc ./cc + set path = (. $path) + + * Make a symbolic link named `md' to the machine description + pattern file. It should be in the `config' subdirectory + and its name should be `MACHINE.md'; but MACHINE is often + not the same as the name used in the `tm.h' file because + the `md' files are more general. + + * Make a symbolic link named `aux-output.c' to the output + subroutine file for your machine. It should be in the + `config' subdirectory and its name should be `out-MACHINE.c'. + + 4. Make sure the Bison parser generator is installed. (This is + unnecessary if the Bison output files `c-parse.tab.c' and + `cexp.c' are more recent than `c-parse.y' and `cexp.y' and you + do not plan to change the `.y' files.) + + Bison versions older than Sept 8, 1988 will produce incorrect + output for `c-parse.tab.c'. + + 5. If you have a previous version of GCC installed, then chances + are you can compile the new version with that. Do the following: + + make CC="gcc -O" + + Since this produces an optimized executable right away, there is + no need to bootstrap the result with itself except to test it. + Therefore, you can skip directly to the `make install' step below. + + 6. Build the compiler. Just type `make' in the compiler directory. + + Ignore any warnings you may see about "statement not reached" + in the `insn-emit.c'; they are normal. Any other compilation + errors may represent bugs in the port to your machine or + operating system, and should be investigated and reported (*note + Bugs::.). + + Some commercial compilers fail to compile GNU CC because they + have bugs or limitations. For example, the Microsoft compiler + is said to run out of macro space. Some Ultrix compilers run + out of expression space; then you need to break up the statement + where the problem happens. + + 7. If you are using COFF-encapsulation, you must convert `gnulib' + to a GNU-format library at this point. See the file + `README-ENCAP' in the directory containing the GNU binary file + utilities, for directions. + + 8. Move the first-stage object files and executables into a + subdirectory with this command: + + make stage1 + + The files are moved into a subdirectory named `stage1'. Once + installation is complete, you may wish to delete these files + with `rm -r stage1'. + + 9. Recompile the compiler with itself, with this command: + + make CC=stage1/gcc CFLAGS="-g -O -Bstage1/" + + This is called making the stage 2 compiler. + + On a 68000 or 68020 system lacking floating point hardware, + unless you have selected a `tm.h' file that expects by default + that there is no such hardware, do this instead: + + make CC=stage1/gcc CFLAGS="-g -O -Bstage1/ -msoft-float" + + 10. If you wish to test the compiler by compiling it with itself one + more time, do this (in C shell): + + make stage2 + make CC=stage2/gcc CFLAGS="-g -O -Bstage2/" + foreach file (*.o) + cmp $file stage2/$file + end + + This is called making the stage 3 compiler. Aside from the `-B' + option, the options should be the same as when you made the + stage 2 compiler. + + The `foreach' command (written in C shell) will notify you if + any of these stage 3 object files differs from those of stage 2. + On BSD systems, any difference, no matter how innocuous, + indicates that the stage 2 compiler has compiled GNU CC + incorrectly, and is therefore a potentially serious bug which + you should investigate and report (*note Bugs::.). + + On systems that use COFF object files, bytes 5 to 8 will + always be different, since it is a timestamp. On these systems, + you can do the comparison as follows (in Bourne shell): + + for file in *.o; do + echo $file + tail +10c $file > foo1 + tail +10c stage2/$file > foo2 + cmp foo1 foo2 + done + + On MIPS machines, you should use the shell script `ecoff-cmp' + to compare two object files. + + 11. Install the compiler driver, the compiler's passes and run-time + support. You can use the following command: + + make install + + This copies the files `cc1', `cpp' and `gnulib' to files + `gcc-cc1', `gcc-cpp' and `gcc-gnulib' in directory + `/usr/local/lib', which is where the compiler driver program + looks for them. It also copies the driver program `gcc' into + the directory `/usr/local/bin', so that it appears in typical + execution search paths. + + *Warning: there is a bug in `alloca' in the Sun library. To + avoid this bug, install the binaries of GNU CC that were + compiled by GNU CC. They use `alloca' as a built-in function + and never the one in the library.* + + *Warning: the GNU CPP may not work for `ioctl.h', + `ttychars.h' and other system header files unless the + `-traditional' option is used.* The bug is in the header files: + at least on some machines, they rely on behavior that is + incompatible with ANSI C. This behavior consists of + substituting for macro argument names when they appear inside of + character constants. The `-traditional' option tells GNU CC to + behave the way these headers expect. + + Because of this problem, you might prefer to configure GNU CC + to use the system's own C preprocessor. To do so, make the file + `/usr/local/lib/gcc-cpp' a link to `/lib/cpp'. + + Alternatively, on Sun systems and 4.3BSD at least, you can + correct the include files by running the shell script + `fixincludes'. This installs modified, corrected copies of the + files `ioctl.h', `ttychars.h' and many others, in a special + directory where only GNU CC will normally look for them. This + script will work on various systems because it chooses the files + by searching all the system headers for the problem cases that + we know about. + + Use the following command to do this: + + make includes + + If you selected a different directory for GNU CC installation + when you installed it, by specifying the Make variable `prefix' + or `libdir', specify it the same way in this command. + + Note that some systems are starting to come with ANSI C + system header files. On these systems, don't run `fixincludes'; + it may not work, and is certainly not necessary. + + *Warning:* `fixincludes' does not work on many MIPS systems, + because those systems come with circular symbolic links which + cause `ls -lR' to go into an infinite loop. + + If you cannot install the compiler's passes and run-time support +in `/usr/local/lib', you can alternatively use the `-B' option to +specify a prefix by which they may be found. The compiler +concatenates the prefix with the names `cpp', `cc1' and `gnulib'. +Thus, you can put the files in a directory `/usr/foo/gcc' and specify +`-B/usr/foo/gcc/' when you run GNU CC. + + Also, you can specify an alternative default directory for these +files by setting the Make variable `libdir' when you make GNU CC. + + +File: gcc.info, Node: Other Dir, Next: Sun Install, Prev: Installation, Up: Installation + +Compilation in a Separate Directory +=================================== + + If you wish to build the object files and executables in a +directory other than the one containing the source files, here is +what you must do differently: + + 1. Go to that directory before running `config.gcc': + + mkdir gcc-sun3 + cd gcc-sun3 + + On systems that do not support symbolic links, this directory + must be on the same file system as the source code directory. + + 2. Specify where to find `config.gcc' when you run it: + + ../gcc-1.36/config.gcc ... + + 3. Specify where to find the sources, as an argument to `config.gcc': + + ../gcc-1.36/config.gcc -srcdir=../gcc-1.36 sun3 + + The `-srcdir=DIR' option is not needed when the source + directory is the parent of the current directory, because + `config.gcc' detects that case automatically. + + Now, you can run `make' in that directory. You need not repeat +the configuration steps shown above, when ordinary source files +change. You must, however, run `config.gcc' again when the +configuration files change, if your system does not support symbolic +links. + + +File: gcc.info, Node: Sun Install, Next: 3b1 Install, Prev: Other Dir, Up: Installation + +Installing GNU CC on the Sun +============================ + + Make sure the environment variable `FLOAT_OPTION' is not set when +you compile `gnulib'. If this option were set to `f68881' when +`gnulib' is compiled, the resulting code would demand to be linked +with a special startup file and would not link properly without +special pains. + + There is a bug in `alloca' in certain versions of the Sun library. +To avoid this bug, install the binaries of GNU CC that were compiled +by GNU CC. They use `alloca' as a built-in function and never the +one in the library. + + Some versions of the Sun compiler crash when compiling GNU CC, +with a segmentation fault in cpp. This can sometimes be due to the +bulk of data in the environment variables. You may be able to avoid +it by using the following command to compile GNU CC with Sun CC: + + make CC="TERMCAP=x OBJS=x LIBFUNCS=x STAGESTUFF=x cc" + + Another problem that often happens on Suns is that you get a crash +when building stage 2, when `genflags' is run. + + One reason for such as crash is if you configured GNU CC for the +wrong version of SunOS. Starting with version 1.38, configurations +`sun3' and `sun4' are for SunOS 4, so this problem should no longer +happen. + + Another cause of the same symptom is having installed the GNU +linker with an earlier version of SunOS. The version that worked +before stopped working due to a change in the format of executables +in SunOS 4.1. Many sites have installed the GNU linker as +`/usr/local/lib/gcc-ld', often as part of installing GNU C++. So if +you get such crashes and you have used the proper configuration, try +deleting `/usr/local/lib/gcc-ld'. + + The current version of the GNU linker, found in the current +binutils release, does work with SunOS 4.1. + + +File: gcc.info, Node: 3b1 Install, Next: SCO Install, Prev: Sun Install, Up: Installation + +Installing GNU CC on the 3b1 +============================ + + Installing GNU CC on the 3b1 is difficult if you do not already +have GNU CC running, due to bugs in the installed C compiler. +However, the following procedure might work. We are unable to test it. + + 1. Comment out the `#include "config.h"' line on line 37 of + `cccp.c' and do `make cpp'. This makes a preliminary version of + GNU cpp. + + 2. Save the old `/lib/cpp' and copy the preliminary GNU cpp to that + file name. + + 3. Undo your change in `cccp.c', or reinstall the original version, + and do `make cpp' again. + + 4. Copy this final version of GNU cpp into `/lib/cpp'. + + 5. Replace every occurrence of `obstack_free' in `tree.c' with + `_obstack_free'. + + 6. Run `make' to get the first-stage GNU CC. + + 7. Reinstall the original version of `/lib/cpp'. + + 8. Now you can compile GNU CC with itself and install it in the + normal fashion. + + If you have installed an earlier version of GCC, you can compile +the newer version with that. However, you will run into trouble +compiling `gnulib', since that is normally compiled with CC. To +solve the problem, uncomment this line in `Makefile': + + CCLIBFLAGS = -B/usr/local/lib/gcc- -tp -Wp,-traditional + + +File: gcc.info, Node: SCO Install, Next: VMS Install, Prev: 3B1 Install, Up: Installation + +Installing GNU CC on SCO System V 3.2 +===================================== + + The compiler that comes with this system does not work properly +with `-O'. Therefore, you should redefine the Make variable +`CCLIBFLAGS' not to use `-O'. + + You should also edit `Makefile' to enable the lines that set +`CLIB' to `-lPW', and the ones specifically labeled as being for SCO, +that set `RANLIB', and that set `CC' and `OLDCC' to `rcc'. + + Also, edit the definition of `USER_H' to remove the file `limits.h'. + + Then you can run `config.gcc i386-sco' and finish building GNU CC +normally. + + The same recipe should work on ESIX, but use `config.gcc +i386-esix' instead. + + +File: gcc.info, Node: VMS Install, Next: HPUX Install, Prev: SCO Install, Up: Installation + +Installing GNU CC on VMS +======================== + + The VMS version of GNU CC is distributed in a backup saveset +containing both source code and precompiled binaries. + + To install the `gcc' command so you can use the compiler easily, +in the same manner as you use the VMS C compiler, you must install +the VMS CLD file for GNU CC as follows: + + 1. Define the VMS logical names `GNU_CC' and `GNU_CC_INCLUDE' to + point to the directories where the GNU CC executables + (`gcc-cpp', `gcc-cc1', etc.) and the C include files are kept. + This should be done with the commands: + + $ assign /super /system disk:[gcc.] gnu_cc + $ assign /super /system disk:[gcc.include.] gnu_cc_include + + with the appropriate disk and directory names. These commands + can be placed in your system startup file so they will be + executed whenever the machine is rebooted. You may, if you + choose, do this via the `GCC_INSTALL.COM' script in the `[GCC]' + directory. + + 2. Install the `GCC' command with the command line: + + $ set command /table=sys$library:dcltables gnu_cc:[000000]gcc + + 3. To install the help file, do the following: + + $ lib/help sys$library:helplib.hlb gcc.hlp + + Now you can invoke the compiler with a command like `gcc + /verbose file.c', which is equivalent to the command `gcc -v -c + file.c' in Unix. + + We try to put corresponding binaries and sources on the VMS +distribution tape. But sometimes the binaries will be from an older +version that the sources, because we don't always have time to update +them. (Use the `/verbose' option to determine the version number of +the binaries and compare it with the source file `version.c' to tell +whether this is so.) In this case, you should use the binaries you +get to recompile the sources. If you must recompile, here is how: + + 1. Copy the file `tm-vms.h' to `tm.h', `xm-vms.h' to `config.h', + `vax.md' to `md.' and `out-vax.c' to `aux-output.c'. The files + to be copied are found in the subdirectory named `config'; they + should be copied to the main directory of GNU CC. + + 2. Setup the logical names and command tables as defined above. In + addition, define the vms logical name `GNU_BISON' to point at + the to the directories where the Bison executable is kept. This + should be done with the command: + + $ assign /super /system disk:[bison.] gnu_bison + + You may, if you choose, use the `INSTALL_BISON.COM' script in + the `[BISON]' directory. + + 3. Install the `BISON' command with the command line: + + $ set command /table=sys$library:dcltables gnu_bison:[000000]bison + + 4. Type `@make' to do recompile everything. + + If you are compiling with a version of GNU CC older than + 1.33, specify `/DEFINE=("inline=")' as an option in all the + compilations. This requires editing all the `gcc' commands in + `make-cc1.com'. (The older versions had problems supporting + `inline'.) Once you have a working 1.33 or newer GNU CC, you + can change this file back. + + Due to the differences between the filesystems of Unix and VMS, +the preprocessor attempts to translate the names of include files +into something that VMS will understand. The basic strategy is to +prepend a prefix to the specification of the include file, convert +the whole filename to a VMS filename, and then try to open the file. +The preprocessor tries various prefixes until one of them succeeds. + + The first prefix is the `GNU_CC_INCLUDE:' logical name: this is +where GNU_C header files are traditionally stored. If a header file +is not found there, `SYS$SYSROOT:[SYSLIB.]' is tried next. If the +preprocessor is still unable to locate the file, it then assumes that +the include file specification is a valid VMS filename all by itself, +and it uses this filename to attempt to open the include file. If +none of these strategies succeeds, the preprocessor reports an error. + + If you wish to store header files in non-standard locations, then +you can assign the logical `GNU_CC_INCLUDE' to be a search list, +where each element of the list is suitable for use with a rooted +logical. + + With this version of GNU CC, `const' global variables now work +properly. Unless, however, the `const' modifier is also specified in +every external declaration of the variable in all of the source files +that use that variable, the linker will issue warnings about +conflicting attributes for the variable, since the linker does not +know if the variable should be read-only. The program will still +work, but the variable will be placed in writable storage. + + Due to an assembler bug, offsets to static constants are sometimes +incorrectly evaluated. This bug is present in GAS 1.38.1, and should +be fixed in the next version. + + Under previous versions of GNU CC, the generated code would +occasionally give strange results when linked to the sharable +`VAXCRTL' library. Now this should work. + + Even with this version, however, GNU CC itself should not be +linked to the sharable `VAXCRTL'. The `qsort' routine supplied with +`VAXCRTL' has a bug which can cause a compiler crash. + + Similarly, the preprocessor should not be linked to the sharable +`VAXCRTL'. The `strncat' routine supplied with `VAXCRTL' has a bug +which can cause the preprocessor to go into an infinite loop. + + It should be pointed out that if you attempt to link to the +sharable `VAXCRTL', the VMS linker will strongly resist any effort to +force it to use the `qsort' and `strncat' routines from `gcclib'. +Until the bugs in `VAXCRTL' have been fixed, linking any of the +compiler components to the sharable VAXCRTL is not recommended. +(These routines can be bypassed by placing duplicate copies of +`qsort' and `strncat' in `gcclib' under different names, and patching +the compiler sources to use these routines). Both of the bugs in +`VAXCRTL' are still present in VMS version 5.4-1, which is the most +recent version as of this writing. + + The executables that are generated by `make-cc1.com' and +`make-cccp.com' use the non-shared version of `VAXCRTL' (and thus use +the `qsort' and `strncat' routines from `gcclib.olb'). + + Note that GNU CC on VMS now generates debugging information to +describe the programs symbols to the VMS debugger. However, you need +version 1.37 or later of GAS in order to output them properly in the +object file. + + The VMS linker does not distinguish between upper and lower case +letters in function and variable names. However, usual practice in C +is to distinguish case. Normally GNU C (by means of the assembler +GAS) implements usual C behavior by augmenting each name that is not +all lower-case. A name is augmented by truncating it to at most 23 +characters and then adding more characters at the end which encode +the case pattern the rest. + + Name augmentation yields bad results for programs that use +precompiled libraries (such as Xlib) which were generated by another +compiler. Use the compiler option `/NOCASE_HACK' to inhibits +augmentation; it makes external C functions and variables +case-independent as is usual on VMS. Alternatively, you could write +all references to the functions and variables in such libraries using +lower case; this will work on VMS, but is not portable to other +systems. In cases where you need to selectively inhibit +augmentation, you can define a macro for each mixed case symbol for +which you wish to inhibit augmentation, where the macro expands into +the lower case equivalent of the name. + + +File: gcc.info, Node: HPUX Install, Next: Tower Install, Prev: VMS Install, Up: Installation + +Installing GNU CC on HPUX +========================= + + To install GNU CC on HPUX, you must start by editing the file +`Makefile'. Search for the string `HPUX' to find comments saying +what to change. You need to change some variable definitions and (if +you are using GAS) some lines in the rule for the target `gnulib'. + + To avoid errors when linking programs with `-g', create an empty +library named `libg.a'. An easy way to do this is: + + ar rc /usr/local/lib/libg.a + + To compile with the HPUX C compiler, you must specify get the file +`alloca.c' from GNU Emacs. Then, when you run `make', use this +argument: + + make ALLOCA=alloca.o + + When recompiling GNU CC with itself, do not define `ALLOCA'. +Instead, an `-I' option needs to be added to `CFLAGS' as follows: + + make CC=stage1/gcc CFLAGS="-g -O -Bstage1/ -I../binutils/hp-include" + + +File: gcc.info, Node: Tower Install, Prev: HPUX Install, Up: Installation + +Installing GNU CC on an NCR Tower +================================= + + On an NCR Tower model 4x0 or 6x0, you may have trouble because the +default maximum virtual address size of a process is just 1 Mb. Most +often you will find this problem while compiling GNU CC with itself. + + The only way to solve the problem is to reconfigure the kernel. +Add a line such as this to the configuration file: + + MAXUMEM = 4096 + +and then relink the kernel and reboot the machine. diff --git a/gcc-1.40/Makefile b/gcc-1.40/Makefile new file mode 100644 index 0000000..0d1e180 --- /dev/null +++ b/gcc-1.40/Makefile @@ -0,0 +1,708 @@ +# Makefile for GNU C compiler. +# Copyright (C) 1987, 1988 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 1, 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. + + +# Variables that exist for you to override. +# See below for how to change them for certain systems. + +CFLAGS = -g $(XCFLAGS) +CC = cc +BISON = bison +BISONFLAGS = -v +# This should be the version of ar to use with output from GCC. +AR = ar +SHELL = /bin/sh +# on sysV, define this as cp. +INSTALL = install -c +# Directory not specified here so that, if a GNU ranlib +# is earlier in the path, it will be used. +# That is likely to be true on systems that have the GNU ar +# installed earlier in the path. +RANLIB = ranlib + +# Compiler to use for compiling gnulib. +# OLDCC should not be the GNU C compiler. +OLDCC = cc + +# CFLAGS for use with OLDCC, for compiling gnulib. +# NOTE: -O does not work on some Unix systems! +# On them, you must take it out. +CCLIBFLAGS=-O + +# This should be the version of ar to use with output from $(OLDCC). +OLDAR = ar + +# CFLAGS for use with OLDCC, for compiling hard-params. +HARD_PARAMS_FLAGS= + +# Directory where sources are, from where we are. +srcdir = . +# Directory in which to put the executable for the command `gcc' +bindir = $(prefix)/usr/local/bin +# Directory in which to put the subprograms used by the compiler. +libdir = $(prefix)/usr/local/lib +# Directory in which to put man pages. +mandir = $(prefix)/usr/local/man/man1 +# Number to put in man-page filename. +manext = 1 + +# Additional system libraries to link with. +CLIB= + +# Change this to a null string if obstacks are installed in the +# system library. +OBSTACK=obstack.o + +# Directory to link to, when using the target `maketest'. +DIR = ../gcc + +# End of variables for you to override. + + +# Variables you should change for certain systems. + +# These are what you would need on HPUX: +# CFLAGS = -Wc,-Ns2000 -Wc,-Ne700 -Wc,-Np300 +# If you are using the GNU assembler and linker on HPUX, +# add -I../hp-include to CFLAGS. +# -g is desirable in CFLAGS, but a compiler bug in HPUX version 5 +# bites whenever tree.def, rtl.def or machmode.def is included +# (ie., on every source file). +# If you have a floating point accelerator, you might want -lsetjmp as well. +# CCLIBFLAGS = -Wc,-Ns2000 -Wc,-Ne700 -O +# HARD_PARAMS_FLAGS = -Wc,-Ns2000 -Wc,-Ne700 +# INSTALL = cp +# For CCLIBFLAGS you might want to specify the switch that +# forces only 68000 instructions to be used. +# If using the GNU assembler and linker, set AR to the GNU ar program, +# wherever that is. +# To get a working alloca, you may need to get alloca.s from Emacs +# and assemble it into alloca.o rather than using alloca.c. + +# On the Sequent, you may need to set CCLIBFLAG to empty. + +# On the 3b1, this line may help you compile gnulib +# if you already have a prior version of gcc installed. +# CCLIBFLAGS = -B/usr/local/lib/gcc- -tp -Wp,-traditional + +# On SysV from SCO, uncomment these lines as well as those for SysV in general. +# You might also want to remove limits.h from the definition of USER_H, +# since the one that comes with the system is good for POSIX. +# RANLIB = : +# CC = rcc +# OLDCC = rcc + +# On a 386 running an ISC system, uncomment the following lines. +# You also need to add -D_POSIX_SOURCE to CFLAGS +# when compiling with GCC. +# INSTALL = cp +# CLIB = -lPW -lcposix + +# If you are making gcc for the first time, and if you are compiling it with +# a non-gcc compiler, and if your system doesn't have a working alloca() in any +# of the standard libraries (as is true for HP/UX or Genix), +# then un-comment the following line when compiling with the system's cc: +# ALLOCA = alloca.o +# But don't do that if compiling using GCC. + +# If your system has a working alloca in /lib/libPW.a, +# un-comment the following line. Note that -lPW doesn't work on HPUX or IRIX. +# CLIB= -lPW + +# On SysV R4, when compiling with PCC, you can get alloca as follows: +# CLIB = -lc /usr/ucblib/libucb.a +# -lc is needed because if libucb.a were searched before libc.a, +# you would get an incompatible stdio package that won't work. + +# On the NCR Tower 32 running SVR3, says ra@intsys.no : +# Do *not* enable optimization in CFLAGS when using the native cc, because: +# a) The optimizer seems to loop when invoked with -O2. +# b) The -O1 level does stack/frame pointer optimizations that make the +# assembler alloca in libPW.a fail, and the C alloca eats *lots* of memory. +# c) gcc will eventually be recompiled with itself, so all this doesn't matter. +# CFLAGS = -g -O0 +# HARD_PARAMS_FLAGS = -O0 +# CCLIBFLAGS = -O2 +# CLIB = -lmalloc -lPW + +# On a pyramid, you need to uncomment the following line: +# CLIB = -lc /usr/.attlib/libPW.a + +# If your system's malloc() routine fails for any reason (as it does on +# certain versions of Genix), try getting the files +# malloc.c and getpagesize.h from GNU Emacs and un-comment the following line: +# MALLOC = malloc.o + +# To build gcc for Apollo 68K machines you must be running at least SR10.2 +# with the 6.7 version of the C compiler. Use 'apollo68' as the argument to +# config.gcc, then go into a bsd4.3 environment and use this: +# CFLAGS = -g -O -Acpu,3000 -Arun,bsd4.3 -Asys,any -Anansi $(XCFLAGS) +# CCLIBFLAGS = -O -Acpu,3000 -Arun,bsd4.3 -Asys,any -Anansi +# HARD_PARAMS_FLAGS= -Anansi +# (Says vasta@apollo.com.) + + +# Dependency on obstack, alloca, malloc or whatever library facilities +# are not installed in the system libraries. +LIBDEPS= $(OBSTACK) $(ALLOCA) $(MALLOC) + +# How to link with both our special library facilities +# and the system's installed libraries. +LIBS = $(OBSTACK) $(ALLOCA) $(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$(srcdir) -I$(srcdir)/config +SUBDIR_INCLUDES = -I.. -I../$(srcdir) -I../$(srcdir)/config + +# Always use -I$(srcdir)/config when compiling. +.c.o: + $(CC) -c $(CFLAGS) $(CPPFLAGS) $(INCLUDES) $< + +# Language-specific object files for C. +C_OBJS = c-parse.tab.o c-decl.o c-typeck.o c-convert.o + +# Language-specific object files for C++. +# (These are not yet released.) +CPLUS_OBJS = cplus-parse.o cplus-decl.o cplus-typeck.o \ + cplus-cvt.o cplus-search.o cplus-lex.o \ + cplus-class.o cplus-init.o cplus-method.o + +# Language-independent object files. +OBJS = toplev.o version.o tree.o print-tree.o stor-layout.o fold-const.o \ + rtl.o rtlanal.o expr.o stmt.o expmed.o explow.o optabs.o varasm.o \ + symout.o dbxout.o sdbout.o emit-rtl.o insn-emit.o \ + integrate.o jump.o cse.o loop.o flow.o stupid.o combine.o \ + regclass.o local-alloc.o global-alloc.o reload.o reload1.o caller-save.o \ + insn-peep.o final.o recog.o insn-recog.o insn-extract.o insn-output.o + +# Files to be copied away after each stage in building. +STAGE_GCC=gcc +STAGESTUFF = *.o insn-flags.h insn-config.h insn-codes.h \ + insn-output.c insn-recog.c insn-emit.c insn-extract.c insn-peep.c \ + stamp-flags stamp-config stamp-codes \ + stamp-output stamp-recog stamp-emit stamp-extract stamp-peep \ + genemit genoutput genrecog genextract genflags gencodes genconfig genpeep \ + cc1 cpp cccp # cc1plus + +# Members of gnulib. +LIBFUNCS = _eprintf _builtin_new _builtin_New _builtin_del _bb \ + _umulsi3 _mulsi3 _udivsi3 _divsi3 _umodsi3 _modsi3 \ + _lshrsi3 _lshlsi3 _ashrsi3 _ashlsi3 \ + _divdf3 _muldf3 _negdf2 _adddf3 _subdf3 _cmpdf2 \ + _fixunsdfsi _fixdfsi _floatsidf _truncdfsf2 _extendsfdf2 \ + _addsf3 _negsf2 _subsf3 _cmpsf2 _mulsf3 _divsf3 + +# Library members defined in gnulib2.c. +LIB2FUNCS = _adddi3 _subdi3 _muldi3 _divdi3 _moddi3 _udivdi3 _umoddi3 _negdi2 \ + _anddi3 _iordi3 _xordi3 _lshrdi3 _lshldi3 _ashldi3 _ashrdi3 _one_cmpldi2 \ + _bdiv _cmpdi2 _ucmpdi2 _fixunsdfdi _fixdfdi _floatdidf _varargs + +# Header files that are made available to programs compiled with gcc. +USER_H = stddef.h assert.h va-i860.h va-mips.h va-pyr.h va-sparc.h \ + va-spur.h limits.h proto.h + +# The files that "belong" in CONFIG_H are deliberately omitted +# because having them there would not be useful in actual practice. +# All they would do is cause complete recompilation every time +# one of the machine description files is edited. +# That may or may not be what one wants to do. +# If it is, rm *.o is an easy way to do it. +# CONFIG_H = config.h tm.h +CONFIG_H = +RTL_H = rtl.h rtl.def machmode.def +TREE_H = tree.h real.h tree.def machmode.def +CPLUS_TREE_H = $(TREE_H) cplus-tree.h c-tree.h + +# Note that dependencies on obstack.h are not written +# because that file is not part of GCC. +# Dependencies on gvarargs.h are not written +# because all that file does, when not compiling with GCC, +# is include the system varargs.h. + +all: config.status gnulib gcc cc1 cpp float.h gnulib2 # cc1plus + +# Use this instead of `all' if you need to convert the libraries +# before you can use the compiler. +# Don't forget to do `make gnulib2' before installation. +all-libconvert: config.status gnulib gcc cc1 cpp float.h # cc1plus + +lang-c: config.status gnulib gcc cc1 cpp gnulib2 +# lang-cplus: config.status gnulib gcc cc1plus cpp gnulib2 + +config.status: + @echo You must configure gcc. Look at the INSTALL file for details. + @false + +doc: $(srcdir)/cpp.info $(srcdir)/gplus.info $(srcdir)/gcc.info + +compilations: ${OBJS} + +gcc: gcc.o version.o $(LIBDEPS) + $(CC) $(CFLAGS) $(LDFLAGS) -o gccnew gcc.o version.o $(LIBS) +# Go via `gccnew' to avoid `file busy' if $(CC) is `gcc'. + mv gccnew gcc + +cc1: $(C_OBJS) $(OBJS) $(LIBDEPS) + $(CC) $(CFLAGS) $(LDFLAGS) -o cc1 $(C_OBJS) $(OBJS) $(LIBS) + +cc1plus: $(CPLUS_OBJS) $(OBJS) $(LIBDEPS) + $(CC) $(CFLAGS) $(LDFLAGS) -o cc1plus $(CPLUS_OBJS) $(OBJS) $(LIBS) + +#Library of arithmetic subroutines +# Don't compile this with gcc! +# (That would cause most arithmetic functions to call themselves.) +gnulib: gnulib.c $(CONFIG_H) config.status + -rm -f stamp-gnulib2 + rm -f tmpgnulib gnulib; \ + for name in $(LIBFUNCS); \ + do \ + echo $${name}; \ + rm -f $${name}.c; \ + cp $(srcdir)/gnulib.c $${name}.c; \ + $(OLDCC) $(CCLIBFLAGS) $(INCLUDES) -c -DL$${name} $${name}.c; \ + $(OLDAR) qc tmpgnulib $${name}.o; \ + rm -f $${name}.[co]; \ + done + -if [ -f /usr/bin/ranlib -o -f /bin/ranlib ] ;then $(RANLIB) tmpgnulib; else true; fi +# Actually build it in tmpgnulib above, then rename now, +# so that gnulib itself remains nonexistent if compilation is aborted. + mv tmpgnulib gnulib +# On HPUX, if you are working with the GNU assembler and linker, +# the previous two command lines must be replaced with the following line. +# No change is needed here if you are using the HPUX assembler and linker. +# ../hp-bin/hpxt tmpgnulib gnulib + +gnulib2: stamp-gnulib2; +stamp-gnulib2: gnulib2.c gnulib cc1 gcc cpp $(CONFIG_H) + for name in $(LIB2FUNCS); \ + do \ + echo $${name}; \ + ./gcc -B./ -fstrength-reduce -O $(INCLUDES) $(GNULIB2_CFLAGS) -c -DL$${name} $(srcdir)/gnulib2.c -o $${name}.o; \ + $(AR) rc gnulib $${name}.o; \ + rm -f $${name}.o; \ + done + -if [ -f /usr/bin/ranlib -o -f /bin/ranlib ] ; then $(RANLIB) gnulib; else true; fi +# On HPUX, if you are working with the GNU assembler and linker, +# the previous line must be commented out. +# No change is needed here if you are using the HPUX assembler and linker. + touch stamp-gnulib2 + +float.h: +# Originally, we used `make' rather than $(MAKE), to avoid propagating +# a CC=gcc command option. However, since hard-params is now made +# with $(OLDCC) explicitly, this is no longer important. +# However, $(MAKE) fails on some systems where it isn't defined. +# `make' has the disadvantage of sometimes running the system's make, +# instead of GNU make. And the system's make might not support VPATH. +# However, the compilation of hard-params should not need to use VPATH, +# due to the explicit use of `$(srcdir)'. + make hard-params \ + HARD_PARAMS_FLAGS="$(HARD_PARAMS_FLAGS)" \ + CPPFLAGS="$(CPPFLAGS)" \ + LDFLAGS="$(LDFLAGS)" + -./hard-params -f > float.h + +# Compile hard-params with standard cc. It avoids some headaches. +hard-params: hard-params.o + $(OLDCC) $(HARD_PARAMS_FLAGS) $(LDFLAGS) hard-params.o -o $@ +hard-params.o: $(srcdir)/hard-params.c + -cp $(srcdir)/hard-params.c . > /dev/null 2>&1 + $(OLDCC) $(HARD_PARAMS_FLAGS) $(CPPFLAGS) -DNO_SC -c hard-params.c + +# C language specific files. + +c-parse.tab.o : $(srcdir)/c-parse.tab.c $(CONFIG_H) $(TREE_H) c-parse.h c-tree.h input.h + $(CC) $(CFLAGS) $(CPPFLAGS) $(INCLUDES) -c $(srcdir)/c-parse.tab.c +$(srcdir)/c-parse.tab.c : $(srcdir)/c-parse.y + $(BISON) $(BISONFLAGS) $(srcdir)/c-parse.y -o $@ + +c-decl.o : c-decl.c $(CONFIG_H) $(TREE_H) c-tree.h c-parse.h flags.h +c-typeck.o : c-typeck.c $(CONFIG_H) $(TREE_H) c-tree.h flags.h +c-convert.o : c-convert.c $(CONFIG_H) $(TREE_H) + +# C++ language specific files. + +cplus-parse.o : $(srcdir)/cplus-parse.c $(CONFIG_H) $(CPLUS_TREE_H) flags.h + $(CC) -c $(CFLAGS) $(INCLUDES) \ + -DPARSE_OUTPUT=\"$(PWD)/cplus-parse.output\" \ + `echo $(srcdir)/cplus-parse.c | sed 's,^\./,,'` + +$(srcdir)/cplus-parse.h $(srcdir)/cplus-parse.c : $(srcdir)/cplus-parse.y + @echo expect 49 shift/reduce conflicts and 4 reduce/reduce conflicts + $(BISON) $(BISONFLAGS) -d -o $(srcdir)/cplus-parse.c $(srcdir)/cplus-parse.y + +cplus-lex.o : cplus-lex.c $(CONFIG_H) $(CPLUS_TREE_H) $(srcdir)/cplus-parse.h +cplus-decl.o : cplus-decl.c $(CONFIG_H) $(CPLUS_TREE_H) flags.h +cplus-typeck.o : cplus-typeck.c $(CONFIG_H) $(CPLUS_TREE_H) flags.h +cplus-class.o : cplus-class.c $(CONFIG_H) $(CPLUS_TREE_H) +cplus-init.o : cplus-init.c $(CONFIG_H) $(CPLUS_TREE_H) +cplus-method.o : cplus-method.c $(CONFIG_H) $(CPLUS_TREE_H) +cplus-cvt.o : cplus-cvt.c $(CONFIG_H) $(CPLUS_TREE_H) +cplus-search.o : cplus-search.c $(CONFIG_H) $(CPLUS_TREE_H) +new-method.o : new-method.c $(CONFIG_H) $(CPLUS_TREE_H) + +# Language-independent files. + +gcc.o: gcc.c $(CONFIG_H) gvarargs.h obstack.h + $(CC) $(CFLAGS) $(INCLUDES) \ + -DSTANDARD_STARTFILE_PREFIX=\"$(libdir)/\" \ + -DSTANDARD_EXEC_PREFIX=\"$(libdir)/gcc-\" -c \ + `echo $(srcdir)/gcc.c | sed 's,^\./,,'` + +version.o: version.c +obstack.o: obstack.c + +tree.o : tree.c $(CONFIG_H) $(TREE_H) flags.h +print-tree.o : print-tree.c $(CONFIG_H) $(TREE_H) +stor-layout.o : stor-layout.c $(CONFIG_H) $(TREE_H) $(RTL_H) +fold-const.o : fold-const.c $(CONFIG_H) $(TREE_H) +toplev.o : toplev.c $(CONFIG_H) $(TREE_H) $(RTL_H) flags.h input.h + +rtl.o : 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 expr.h \ + insn-codes.h hard-reg-set.h +stmt.o : stmt.c $(CONFIG_H) $(RTL_H) $(TREE_H) flags.h \ + insn-flags.h insn-config.h insn-codes.h expr.h regs.h hard-reg-set.h recog.h +expr.o : expr.c $(CONFIG_H) $(RTL_H) $(TREE_H) flags.h \ + insn-flags.h insn-codes.h expr.h insn-config.h recog.h typeclass.h +expmed.o : expmed.c $(CONFIG_H) $(RTL_H) $(TREE_H) flags.h \ + insn-flags.h insn-codes.h expr.h insn-config.h recog.h +explow.o : explow.c $(CONFIG_H) $(RTL_H) $(TREE_H) flags.h expr.h insn-codes.h +optabs.o : optabs.c $(CONFIG_H) $(RTL_H) $(TREE_H) flags.h \ + insn-flags.h insn-codes.h expr.h insn-config.h recog.h +symout.o : symout.c $(CONFIG_H) $(TREE_H) $(RTL_H) symseg.h gdbfiles.h +dbxout.o : dbxout.c $(CONFIG_H) $(TREE_H) $(RTL_H) flags.h +sdbout.o : sdbout.c $(CONFIG_H) $(TREE_H) $(RTL_H) + +emit-rtl.o : emit-rtl.c $(CONFIG_H) $(RTL_H) regs.h insn-config.h real.h + +integrate.o : integrate.c $(CONFIG_H) $(RTL_H) $(TREE_H) flags.h expr.h \ + insn-flags.h insn-codes.h + +jump.o : jump.c $(CONFIG_H) $(RTL_H) flags.h regs.h +stupid.o : stupid.c $(CONFIG_H) $(RTL_H) regs.h hard-reg-set.h + +cse.o : cse.c $(CONFIG_H) $(RTL_H) regs.h hard-reg-set.h flags.h real.h +loop.o : loop.c $(CONFIG_H) $(RTL_H) insn-config.h insn-codes.h \ + regs.h hard-reg-set.h recog.h flags.h expr.h +flow.o : flow.c $(CONFIG_H) $(RTL_H) basic-block.h regs.h hard-reg-set.h +combine.o : combine.c $(CONFIG_H) $(RTL_H) flags.h \ + insn-config.h regs.h basic-block.h recog.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 +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 +global-alloc.o : global-alloc.c $(CONFIG_H) $(RTL_H) flags.h \ + basic-block.h regs.h hard-reg-set.h insn-config.h + +reload.o : reload.c $(CONFIG_H) $(RTL_H) flags.h \ + reload.h recog.h hard-reg-set.h insn-config.h regs.h +reload1.o : reload1.c $(CONFIG_H) $(RTL_H) flags.h \ + reload.h regs.h hard-reg-set.h insn-config.h basic-block.h recog.h +caller-save.o : caller-save.c $(CONFIG_H) $(RTL_H) flags.h \ + reload.h regs.h hard-reg-set.h insn-config.h basic-block.h recog.h +final.o : final.c $(CONFIG_H) $(RTL_H) flags.h regs.h recog.h conditions.h \ + gdbfiles.h insn-config.h real.h output.h +recog.o : recog.c $(CONFIG_H) $(RTL_H) \ + regs.h recog.h hard-reg-set.h insn-config.h real.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 +# from the GNU Emacs distribution. +# Note some machines won't allow $(CC) without -S on this source file. +alloca.o: alloca.c + $(CC) $(CFLAGS) -S `echo $(srcdir)/alloca.c | sed 's,^\./,,'` + as alloca.s -o alloca.o + +# Now the source files that are generated from the machine description. + +.PRECIOUS: insn-config.h insn-flags.h insn-codes.h \ + insn-emit.c insn-recog.c insn-extract.c insn-output.c insn-peep.c + +# The following pair of rules has this effect: +# genconfig is run only if the md has changed since genconfig was last run; +# but the file insn-config.h is touched only when its contents actually change. + +# Each of the other insn-* files is handled by a similar pair of rules. + +insn-config.h: stamp-config ; +stamp-config : md genconfig $(srcdir)/move-if-change + ./genconfig md > tmp-config.h + $(srcdir)/move-if-change tmp-config.h insn-config.h + touch stamp-config + +insn-flags.h: stamp-flags ; +stamp-flags : md genflags $(srcdir)/move-if-change + ./genflags md > tmp-flags.h + $(srcdir)/move-if-change tmp-flags.h insn-flags.h + touch stamp-flags + +insn-codes.h: stamp-codes ; +stamp-codes : md gencodes $(srcdir)/move-if-change + ./gencodes md > tmp-codes.h + $(srcdir)/move-if-change tmp-codes.h insn-codes.h + touch stamp-codes + +insn-emit.o : insn-emit.c $(CONFIG_H) $(RTL_H) expr.h real.h insn-codes.h \ + insn-config.h insn-flags.h + $(CC) $(CFLAGS) $(INCLUDES) -c insn-emit.c + +insn-emit.c: stamp-emit ; +stamp-emit : md genemit $(srcdir)/move-if-change + ./genemit md > tmp-emit.c + $(srcdir)/move-if-change tmp-emit.c insn-emit.c + touch stamp-emit + +insn-recog.o : insn-recog.c $(CONFIG_H) $(RTL_H) insn-config.h real.h recog.h + $(CC) $(CFLAGS) $(INCLUDES) -c insn-recog.c + +insn-recog.c: stamp-recog ; +stamp-recog : md genrecog $(srcdir)/move-if-change + ./genrecog md > tmp-recog.c + $(srcdir)/move-if-change tmp-recog.c insn-recog.c + touch stamp-recog + +insn-extract.o : insn-extract.c $(CONFIG_H) $(RTL_H) + $(CC) $(CFLAGS) $(INCLUDES) -c insn-extract.c + +insn-extract.c: stamp-extract ; +stamp-extract : md genextract $(srcdir)/move-if-change + ./genextract md > tmp-extract.c + $(srcdir)/move-if-change tmp-extract.c insn-extract.c + touch stamp-extract + +insn-peep.o : insn-peep.c $(CONFIG_H) $(RTL_H) regs.h real.h + $(CC) $(CFLAGS) $(INCLUDES) -c insn-peep.c + +insn-peep.c: stamp-peep ; +stamp-peep : md genpeep $(srcdir)/move-if-change + ./genpeep md > tmp-peep.c + $(srcdir)/move-if-change tmp-peep.c insn-peep.c + touch stamp-peep + +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 output.h aux-output.c + $(CC) $(CFLAGS) $(INCLUDES) -c insn-output.c + +insn-output.c: stamp-output ; +stamp-output : md genoutput $(srcdir)/move-if-change + ./genoutput md > tmp-output.c + $(srcdir)/move-if-change tmp-output.c insn-output.c + touch stamp-output + +# Now the programs that generate those files. +# $(CONFIG_H) is omitted from the deps of the gen*.o +# because these programs don't really depend on anything +# about the target machine. They do depend on config.h itself, +# since that describes the host machine. + +genconfig : genconfig.o rtl.o $(LIBDEPS) + $(CC) $(CFLAGS) $(LDFLAGS) -o genconfig genconfig.o rtl.o $(LIBS) + +genconfig.o : genconfig.c $(RTL_H) config.h + +genflags : genflags.o rtl.o $(LIBDEPS) + $(CC) $(CFLAGS) $(LDFLAGS) -o genflags genflags.o rtl.o $(LIBS) + +genflags.o : genflags.c $(RTL_H) config.h + +gencodes : gencodes.o rtl.o $(LIBDEPS) + $(CC) $(CFLAGS) $(LDFLAGS) -o gencodes gencodes.o rtl.o $(LIBS) + +gencodes.o : gencodes.c $(RTL_H) config.h + +genemit : genemit.o rtl.o $(LIBDEPS) + $(CC) $(CFLAGS) $(LDFLAGS) -o genemit genemit.o rtl.o $(LIBS) + +genemit.o : genemit.c $(RTL_H) config.h + +genrecog : genrecog.o rtl.o $(LIBDEPS) + $(CC) $(CFLAGS) $(LDFLAGS) -o genrecog genrecog.o rtl.o $(LIBS) + +genrecog.o : genrecog.c $(RTL_H) config.h + +genextract : genextract.o rtl.o $(LIBDEPS) + $(CC) $(CFLAGS) $(LDFLAGS) -o genextract genextract.o rtl.o $(LIBS) + +genextract.o : genextract.c $(RTL_H) config.h + +genpeep : genpeep.o rtl.o $(LIBDEPS) + $(CC) $(CFLAGS) $(LDFLAGS) -o genpeep genpeep.o rtl.o $(LIBS) + +genpeep.o : genpeep.c $(RTL_H) config.h + +genoutput : genoutput.o rtl.o $(LIBDEPS) + $(CC) $(CFLAGS) $(LDFLAGS) -o genoutput genoutput.o rtl.o $(LIBS) + +genoutput.o : genoutput.c $(RTL_H) config.h + +# Making the preprocessor +cpp: cccp + -rm -f cpp + ln cccp cpp +cccp: cccp.o cexp.o version.o $(LIBDEPS) + $(CC) $(CFLAGS) $(LDFLAGS) -o cccp cccp.o cexp.o version.o $(LIBS) +cexp.o: $(srcdir)/cexp.c $(CONFIG_H) + $(CC) $(CFLAGS) $(CPPFLAGS) $(INCLUDES) -c $(srcdir)/cexp.c +$(srcdir)/cexp.c: $(srcdir)/cexp.y + $(BISON) -o $(srcdir)/cexp.c $(srcdir)/cexp.y +cccp.o: cccp.c $(CONFIG_H) + $(CC) $(CFLAGS) $(INCLUDES) \ + -DGCC_INCLUDE_DIR=\"$(libdir)/gcc-include\" \ + -DGPLUSPLUS_INCLUDE_DIR=\"$(libdir)/g++-include\" \ + -c `echo $(srcdir)/cccp.c | sed 's,^\./,,'` + +$(srcdir)/cpp.info: $(srcdir)/cpp.texinfo + makeinfo `echo $(srcdir)/cpp.texinfo | sed 's,^\./,,'` + +$(srcdir)/gplus.info: $(srcdir)/gplus.texinfo + makeinfo `echo $(srcdir)/gplus.texinfo | sed 's,^\./,,'` + +$(srcdir)/gcc.info: $(srcdir)/gcc.texinfo + makeinfo `echo $(srcdir)/gcc.texinfo | sed 's,^\./,,'` + +# gnulib is not deleted because deleting it would be inconvenient +# for most uses of this target. +clean: + -rm -f $(STAGESTUFF) $(STAGE_GCC) +# Delete the temp files made in the course of building gnulib. + -rm -f tmpgnulib + for name in $(LIBFUNCS); do rm -f $${name}.c; done + -rm -f stamp-*.[ch] tmp-* + -rm -f *.s *.s[0-9] *.co *.greg *.lreg *.combine *.flow *.cse *.jump *.rtl *.tree *.loop *.dbr *.jump2 + -rm -f core float.h hard-params + +# Like clean but also delete the links made to configure gcc. +# Also removes gnulib, since that is desirable if you are changing cpus. +cleanconfig: clean + -rm -f tm.h aux-output.c config.h md config.status gnulib stamp-gnulib2 + +# Get rid of every file that's generated from some other file (except INSTALL). +realclean: cleanconfig + -rm -f cpp.aux cpp.cps cpp.fns cpp.info cpp.kys cpp.pgs cpp.tps cpp.vrs +# -rm -f cplus-parse.tab.c cplus-parse.output + -rm -f c-parse.tab.c c-parse.output c-parse.tab.output + -rm -f gnulib cexp.c TAGS + -rm -f cpp.info* cpp.?? cpp.??s cpp.log cpp.toc cpp.*aux + -rm -f gcc.info* gcc.?? gcc.??s gcc.log gcc.toc gcc.*aux + -rm -f gplus.info* gplus.?? gplus.??s gplus.log gplus.toc gplus.*aux + -rm -f *.dvi + +# Copy the files into directories where they will be run. +install: all $(USER_H) float.h gvarargs.h gstdarg.h gcc.1 + -mkdir $(libdir) + -if [ -f cc1 ] ; then $(INSTALL) cc1 $(libdir)/gcc-cc1 ; else true; fi + -if [ -f cc1plus ] ; then $(INSTALL) cc1plus $(libdir)/gcc-cc1plus ; else true; fi + $(INSTALL) gnulib $(libdir)/gcc-gnulib + -if [ -f /usr/bin/ranlib -o -f /bin/ranlib ] ; then (cd $(libdir); $(RANLIB) gcc-gnulib) ; else true; fi + $(INSTALL) cpp $(libdir)/gcc-cpp + $(INSTALL) gcc $(bindir) + -mkdir $(libdir)/gcc-include + -chmod ugo+rx $(libdir)/gcc-include + for file in $(USER_H); do \ + for eachfile in $(srcdir)/$${file} ; do \ + $(INSTALL) $(srcdir)/`basename $${eachfile}` $(libdir)/gcc-include/`basename $${eachfile}`; \ + done ; done + $(INSTALL) float.h $(libdir)/gcc-include/float.h + $(INSTALL) $(srcdir)/gvarargs.h $(libdir)/gcc-include/varargs.h + $(INSTALL) $(srcdir)/gstdarg.h $(libdir)/gcc-include/stdarg.h + -chmod a-x $(libdir)/gcc-include/*.h + $(INSTALL) $(srcdir)/gcc.1 $(mandir)/gcc.$(manext) + -chmod a-x $(mandir)/gcc.$(manext) + +# do make -f ../gcc/Makefile maketest DIR=../gcc +# in the intended test directory to make it a suitable test directory. +maketest: + ln -s $(DIR)/*.[chy] . + ln -s $(DIR)/config . + ln -s $(DIR)/*.def . + -rm -f =* + ln -s $(DIR)/.gdbinit . + -ln -s $(DIR)/bison.simple . + ln -s $(DIR)/config.gcc . + ln -s $(DIR)/move-if-change . +# The then and else were swapped to avoid a problem on Ultrix. + -if [ ! -f Makefile ] ; then ln -s $(DIR)/Makefile . ; else false; fi + -rm tm.h aux-output.c config.h md + make clean +# You must then run config.gcc to set up for compilation. + +bootstrap: all force + $(MAKE) stage1 + $(MAKE) CC="stage1/gcc -Bstage1/" CFLAGS="-O $(CFLAGS)" libdir=$(libdir) + $(MAKE) stage2 + $(MAKE) CC="stage2/gcc -Bstage2/" CFLAGS="-O $(CFLAGS)" libdir=$(libdir) + +bootstrap2: force + $(MAKE) CC="stage1/gcc -Bstage1/" CFLAGS="-O $(CFLAGS)" libdir=$(libdir) + $(MAKE) stage2 + $(MAKE) CC="stage2/gcc -Bstage2/" CFLAGS="-O $(CFLAGS)" libdir=$(libdir) + +bootstrap3: force + $(MAKE) CC="stage2/gcc -Bstage2/" CFLAGS="-O $(CFLAGS)" libdir=$(libdir) + +# Copy the object files from a particular stage into a subdirectory. +stage1: force + -mkdir stage1 + -mv $(STAGESTUFF) $(STAGE_GCC) stage1 + -rm -f stage1/gnulib + -ln gnulib stage1 || cp gnulib stage1 + -if [ -f /usr/bin/ranlib -o -f /bin/ranlib ] ; then $(RANLIB) stage1/gnulib; else true; fi + +stage2: force + -mkdir stage2 + -mv $(STAGESTUFF) $(STAGE_GCC) stage2 + -rm -f stage2/gnulib + -ln gnulib stage2 || cp gnulib stage2 + -if [ -f /usr/bin/ranlib -o -f /bin/ranlib ] ; then $(RANLIB) stage2/gnulib; else true; fi + +stage3: force + -mkdir stage3 + -mv $(STAGESTUFF) $(STAGE_GCC) stage3 + -rm -f stage3/gnulib + -ln gnulib stage3 || cp gnulib stage3 + -if [ -f /usr/bin/ranlib -o -f /bin/ranlib ] ; then $(RANLIB) stage3/gnulib; else true; fi + +stage4: force + -mkdir stage4 + -mv $(STAGESTUFF) $(STAGE_GCC) stage4 + -rm -f stage4/gnulib + -ln gnulib stage4 || cp gnulib stage4 + -if [ -f /usr/bin/ranlib -o -f /bin/ranlib ] ; then $(RANLIB) stage4/gnulib; else true; fi + +TAGS: force + mkdir temp + -mv c-parse.tab.c cplus-parse.c cplus-parse.h cexp.c temp + etags *.y *.h *.c + mv temp/* . + rmdir temp + +includes: force + export LIB; LIB=$(libdir)/gcc-include ./fixincludes + +#In GNU Make, ignore whether `stage*' exists. +.PHONY: stage1 stage2 stage3 stage4 clean realclean TAGS bootstrap + +force: diff --git a/gcc-1.40/OChangeLog b/gcc-1.40/OChangeLog new file mode 100644 index 0000000..ccba87b --- /dev/null +++ b/gcc-1.40/OChangeLog @@ -0,0 +1,6671 @@ + +Wed Dec 21 02:46:34 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * Version 1.32 released. + + * toplev.c (main): Vax pcc enforces goto-less programming + with fatal error. + + * stmt.c (fixup_memory_subreg): New arg INSN says where to emit insns. + (walk_fixup_memory_subreg): Likewise. All callers changed. + +Tue Dec 20 01:26:56 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * c-decl.c (start_function): Don't clear TREE_PERMANENT in fn decl. + Make the result decl a permanent node. + (finish_function): Don't clear DECL_RESULT in an inline function. + (duplicate_decls): Don't lose DECL_RESULT or DECL_SAVED_INSNS + or old decl, when defn is followed by redeclaration. + Likewise DECL_ARGUMENTS and DECL_RESULT_TYPE. + + * stmt.c (expand_function_end): End any sequences left unterminated. + + * cse.c (predecide_loop_entry): If "loop" has no label, do nothing. + + * recog.c (asm_noperands): Now return -1 if not that kind of insn. + All callers changed. + * combine.c (check_asm_operands): Calling changes not quite trivial. + * final.c (final): Likewise. + * reload.c (find_reloads): Likewise. + * recog.c (asm_noperands): Other changes: + Loop computing # of SETs in a PARALLEL was off by 1. + Validate all elts of any PARALLEL, to block invalid combinations. + + * ns32k.md (andsi3, andhi3): Make new CONST_INTs; don't clobber old. + + * integrate.c (copy_rtx_and_substitute): When looking in `parm_map', + if our mode mismatches parm's mode, use change_address to extract part. + On BYTES_BIG_ENDIAN machines, adjust the offset. + +Mon Dec 19 23:50:14 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * cexp.y ('/' and '%' ops): If divide by 0, print error, don't die. + +Sun Dec 18 14:03:02 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * toplev.c (main): Avoid shadowing I in inner block. + + * flow.c (propagate_block): The insn at the end of a libcall + may be dead, but the libcall might still be needed if the + hard return reg is used later. Detect this case. + (libcall_dead_p): New fn used to check that the libcall is dead. + + * output-m68k.c, tm-m68k.h (standard_sun_fpa_constant_p): Fn renamed. + +Sat Dec 17 13:23:51 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * stmt.c (expand_end_bindings): error_with_file_and_line => ..._decl. + + * combine.o (try_combine): Accept combination making a valid + asm with operands. + (check_asm_operands): Recognize asm with operands that are valid. + + * loop.c (strength_reduce): Don't accept a reg as a giv + if the reg was made by loop-optimize. + + * stmt.c (balance_case_nodes): A list of 3 always splits in middle. + +Fri Dec 16 17:22:07 1988 Tiemann (rms at sugar-bombs.ai.mit.edu) + + * sparc.md (fetch from constant address): Split into two patterns, + one fixed point and one floating. + (store at constant address): Handle remembered hi-half differently. + Other bug fixes. + (fix_truncsfsi2): Use f1, not f0, as temp. + (fix_truncdfsi2): Don't clear CC_F1_IS_0. + + * output-sparc.c (singlemove_string): Changed handling of case + where op1 is not memory and op0 has varying address. + (output_fp_move_double): Avoid reloading high half address + in the ldd and std cases with constant address. + (make_f0_contain_0): Handle f0 and f1 individually. + + * tm-sparc.h (GO_IF_LEGITIMATE_ADDRESS): CONST is now illegitimate. + + * rtl.c (note_stores): Pass entire SET rtx, not flag, as 2nd arg to FN. + * local-alloc.c (reg_is_set): New type for 2nd arg. + + * Makefile: Comment out cc1plus, since not ready for release. + +Thu Dec 15 16:39:47 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * local-alloc.c (reg_is_set): If a hard reg is clobbered, make it free + before and after the insn. + * stupid.c (stupid_mark_refs): Likewise. + * global-alloc.c (global_conflicts): Likewise. + Use note_stores to call mark_reg_{store,clobber}. + (mark_reg_store): Changed calling conventions + All work done on set/clobbered regs is now done here. + Ignore CLOBBERs. + (mark_reg_clobber): Similar fn, but ignore SETs and handle CLOBBERs. + (regs_set, n_regs_set): New static vars for comm. among the above. + + * stmt.c (expand_asm_operands): call protect_from_queue on operands. + This requires preexpanding the outputs into a vector of rtx's. + + * Makefile (install): cd to $(libdir) before ranlib. + + * c-typeck.c (c_expand_asm_operands): emit_queue at the end. + + * reload.c (find_reloads): Count # alternatives properly for + an asm insn, and check that all operands correspond. + + * loop.c (verify_loop): Reject loops containg setjmps. + * cse.c (cse_main): Don't cse across a call to setjmp. + + * expr.c (expand_expr): Permit any non0 DECL_RTL for a VAR_DECL. + + * stmt.c (balance_case_nodes): Count ranges double when balancing. + +Wed Dec 14 13:50:45 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * final.c (output_addr_const): Output just `-', not `+-'. + + * make-cc1.com: Update filenames changed to `c-'. + * make-cccp.com: Pass needed -D options when compiling cccp.c. + Use /nomap when linking. + + * loop.c (strength_reduce): Paraphrase setting NEW_REG, for Iris cc. + + * output-m68k.c (output_move_const_single): %'s must be doubled twice. + + * loop.c (record_giv): A giv can be replaceable if its uses are + all in the same basic block as its sole setting. + (last_use_this_basic_block): Subroutine to test that. + +Tue Dec 13 13:41:57 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * expr.c (do_store_flag): Allow for COMPARISON to be a const_int. + + * c-decl.c (pushdecl): Warn if type mismatch with another external decl + in a global scope. + + * fixincludes: Fix typo in msg of deleting unchanged file. + + * Makefile (insn-*): Use two-step rules with a separate time-stamp file + to avoid rerunning gen* unless md has changed again. + +Mon Dec 12 13:32:05 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * i386.md (tstsf, tstdf, cmpsf, cmpdf): Use fnstsw, not fstsw. Faster. + + * tm-vax.h (ASM_OUTPUT_REG_POP): Use correct asm syntax for pop insn. + + * combine.c (subst): Handle (subreg (mem)) by making a changed mem. + This avoids producing any (subreg (mem))s except in the special + case they are supposed to be made here. + Also set undo_storage in a couple of cases that forgot to. + + * reload.c (push_reload): When handling (SUBREG (MEM)) for IN, + if there is an OUT, make that a separate reload. + Return its number in `output_reloadnum' + (find_reloads): When pushing matching-reloads, note that the + two operands can have different reload-numbers. + + * tm-3b1.h (ASM_OUTPUT_CASE_END): Test flag on TABLE, not its pattern. + (ASM_OUTPUT_CASE_LABEL): If /i flag set, don't output the dummy entry + since the fetcher-insn will not be off by 2 in this case. + * m68k.md (casesi_2 recognizer): For 3b1 syntax, compensate for that. + +Sun Dec 11 12:51:49 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * genrecog.c (try_merge_2): No longer put all explicit decompositions + before all predicates. Patterns are now tested in the order written. + * vax.md: Move the push-or-move-address patterns to the end. + * m68k.md: Move load-address pattern to end. + Rearrange the special-case movsi patterns. + * ns32k.md: Move special load-reg-17 pattern before movsi. + * i386.md: Move the QI and DI push patterns to logical places. + This should not actually change anything. + + * stmt.c: Add Andy Hitchins's binary-tree case statement code. + (struct case_stmt): case_list field is now a case_node chain. + Replace has_default field with default_label field. + (pushcase, pushcase_range): Build case_list in its new type, + and keep it sorted. + (expand_end_case): Use case_list in its new type. + Count a range of > 1 as two cases, when choosing strategy. + (group_case_nodes, balance_case_nodes): New fns, rearrange case_list. + (node_has_{low,high}_bound, node_is_bounded): New fns test + relationships of values of various case_list tree nodes. + (emit_jump_if_reachable): New fn. + (emit_case_nodes): Emit compares and jumps based on tree of case_list. + + * cccp.c (finclude): Handle nonordinary files (stat doesn't give size). + + * tm-3b1.h (PRINT_OPERAND_ADDRESS): Handle case of breg and no ireg. + +Sat Dec 10 16:30:32 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * sparc.md (movstrsi): Separate define_expand and define_insn; + clobber some pseudos to get temp regs to use in the output. + * output-sparc.c (output_block_move): Use those temp regs, + guaranteed to be free. + + * sparc.md (andcc patterns for bitfields from memory): + Test immed. arg for being in range. + (load DFmode constant): Use %m for output in one case. + * output-sparc.c (singlemove_string, output_move_double): Likewise. + + * output-sparc.c (singlemove_string): New case for mem-to-mem move. + +Fri Dec 9 11:42:15 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * stupid.c (stupid_mark_refs): for CLOBBER of a pseudo, + it is born just before this insn and dies just after. + + * tm-vax.h (NOTICE_UPDATE_CC): For aob, sob insns, forget the cc's. + + * basic-block.h (REG_BLOCK_UNKNOWN, REG_BLOCK_GLOBAL): Move defn here. + * local-alloc.c: Use them. + + * c-decl.c (store_parm_decls): Additional explanatory message + for some prototype mismatches. + + * gnulib.c (SItype): New macro used instead of `int' + for SImode operands and values. Definition is `long int'. + +Thu Dec 8 18:45:48 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * reload.c (operands_match_p): Move the label `slow' so that + it doesn't cause a REG and a SUBREG to be compared wrong. + + * toplev.c (compile_file): Output a label `gcc_compiled.' for GDB. + If new macro ASM_IDENTIFY_GCC is defined, run that instead. + * tm-3b1.h (ASM_IDENTIFY_GCC): Define this as no-op. + +Wed Dec 7 12:20:42 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * i386.md (adddf3): Typo: paren was in a constraint. + + * c-decl.c (grokparms): Avoid duplicate msgs for incomplete type ptrs. + + * gnulib.c: Rename all fns to start with `__'. + * optabs.c, expr.c: Rename all references. + + * gnulib.c (__cmpdi2, __ucmpdi2): New fns. + * optabs.c (emit_cmp_insn): Use them. + + * Makefile (stage*): Ignore errors on the main `mv' (for cc1plus). + Run ranlib if we have to copy gnulib. + + * expmed.c (expand_divmod): Split `label' into several local vars. + + * jump.c (jump_back_p): Do nothing unless cc's were set from integers. + +Tue Dec 6 12:00:21 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * c-parse.y (extend_token_buffer): Use xrealloc, not realloc. + + * integrate.c (output_inline_function): fix args of expand_function_end + (expand_inline_function): Add missing arg to expand_end_bindings. + + * cse.c (cse_insn): Add missing MODE arg to canon_hash. + + * reload1.c (reload_as_needed): Del. extra arg of choose_reload_targets + (reload): Add missing MODE arg to immediate_operand. + + * expmed.c (expand_mult): Delete extra arg to expand_unop. + + * c-typeck.c (default_conversion): + Add missing NOCONVERT arg to build_unary_op. + + * c-decl.c (duplicate_decls, finish_struct): Add missing arg + KNOWN_ALIGMENT to layout_decl. + * stor-layout.c (layout_record): Likewise. + * varasm.c (assemble_variable): Likewise. + + * dbxout.c (dbxout_init): Add missing LOCAL arg to dbxout_symbol. + + * expr.c (clear_storage): Remove excess arg to emit_move_insn. + + * loop.c (consec_sets_invariant_p): Add parens in hairy if-condition. + + * fold-const.c (fold): Typo, missing `case'. + + * cccp.c (main): Typo handling `-I-' option. + + * tm-i386.h (NO_FUNCTION_CSE): Define this; cse is said to slow + things down with less than 7 calls. + + * stmt.c (fixup_var_refs_insn): When scanning the reg-notes, + don't touch other insns they point at. + + * expr.c (do_jump): Use invert_exp, not reverse_condition, + to invert sense of a jump. + * jump.c reverse_condition now static, invert_exp now global. + +Mon Dec 5 10:51:39 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * tm-sun386.h (ASM_FILE_START): In the .file arg, exclude directories. + + * stmt.c (expand_expr_stmt): If -W, warn if stmt has no side effect. + + * cccp.c (monthnames): Capitalize each name. + + * rtl.def: New code MATCH_OPERATOR. + * genconfig.c (walk_insn_part): Handle it. + * genextract.c (walk_rtx): Handle it. + * genpeep.c (match_rtx): Handle it. + * genrecog.c (add_to_sequence): Handle it. + * genemit.c (max_operand_1, gen_exp, gen_expand): Handle it. + * genoutput.c (scan_operands): Handle it. + (insn_n_alternatives): New array in the output. + (struct data): New slots n_alternatives and op_n_alternatives. + (scan_operands, gen_insn, gen_peephole): + Record op_n_alternatives for each operand. + (output_epilogue): Verify that all operands have same # of alternatives + Also output insn_n_alternatives. + + * reload.c (find_reloads): use insn_n_alternatives to control + the loop over all alternatives. + An empty constraint or empty alternative in a constraint + is always satisfied. + * recog.c (constrain_operands): Likewise. + + * c-decl.c (lang_decode_option): For each -f option, recognize a form + with `no-' and a form without, as contraries. + + * toplev.c (main): Decode -f options using a table + so that each option automatically has a `no-' variant. + + * combine.c (try_combine): Give up if I1 or I2 follows a compare insn. + +Sun Dec 4 12:00:36 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * varasm.c (data_section): If flag_shared, use SHARED_SECTION_ASM_OP + if that is defined. + + * cccp.c (include_default): Add /usr/local/include. + + * Makefile (install): Install the makefile. + + * varasm.c (assemble_external): New fn to declare an external. + (assemble_variable): Output nothing for externals. + * c-parse.y (primary => identifier): Call assemble_variable on 1st use. + + * toplev.c (main): Print version info on stderr, not stdout. + * tm-*.h (TARGET_VERSION): Likewise. + + * tm-isi68.h, tm-news800.h: Rename __HAVE_FPU__ to __HAVE_68881__. + + * sparc.md (seq, etc): Entire page rewritten by Tiemann + to avoid incorrect use of PARALLEL. + * output-sparc.c (gen_scc_insn): Corresponding changes. + +Sat Dec 3 00:03:19 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * gcc.c (do_spec_1): %P is an ANSIfied form of %p: + put __ at beg and end of each predefined macro name. + + * tm-sun3.h (CPP_SPEC): Don't define -Dmc68010, etc., if -ansi. + * tm-sun2.h (CPP_SPEC): Likewise. + + * c-decl.c (shadow_tag): Don't complain if declare a new tag + at top level, or if redeclare a tag. + + * c-decl.c (grokparms): Warn if parm points to incomplete type. + (We already err if its own type is incomplete.) + + * stmt.c (fixup_var_refs_insns): Fix any (SUBREG (MEM)) in REG_NOTES. + (walk_fixup_memory_subreg): New subroutine used for this. + + * integrate.c (copy_rtx_and_substitute): Handle MEM refs to the middle + of a stack-parm--at least in the case of reading the parm. + + * rtl.c (rtx_equal_p): REG_FUNCTION_VALUE_P is significant + only until end of reload pass. + * toplev.c (rest_of_compilation): + Control that by setting new var rtx_equal_function_value_matters. + + * c-decl.c (init_decl_processing): Don't declare the builtins + that aren't really implemented. + + * output-sparc.c (output_move_double): "in structure" implies + 8-byte alignment only for DFmode, not for DImode. + + * final.c (output_operand_lossage): Cleaner text for error msg. + No longer need to write text into .s file, now that linenum is correct. + + * c-decl.c (pushdecl): -traditional stops warning + about "declared extern, later static". + + * c-typeck.c (build_indirect_ref): Don't handle flag_volatile here. + * expr.c (expand_expr): Handle it here, in INDIRECT_REF case. + This prevents -fvolatile from causing additional warnings. + + * output-sparc.c (output_load_address): Allow REG+REG for operands[3]. + + * m68k.md (movsi): If we output the label LIn, + set the RTL_INTEGRATED flag in the switch table's pattern. + * tm-3b1.h (ASM_OUTPUT_CASE_END): Define LD%n only if LI%n was output. + + * i386.md (push-and-add pattern): Comment it out. + It's said to result in slower code. + + * i386.md (tstqi, tsthi, tstsi): Output real `test' insn if op is reg. + + * i386.md (push for DI): Allow `oiF' for 2nd operand. + +Fri Dec 2 13:57:35 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * i386.md (movdi): Allow F constraint for 2nd operand. + + * i386.md (push for QI): define pattern to push a QImode + which really uses pushw and therefore really pushes a halfword. + * tm-i386.h (PUSH_ROUNDING): Round up to multiple of 2. + + * gcc.c (do_spec_1): Handle %e, which means report an error. + Use it to prohibit -pg with -fomit-frame-pointer. + + * tree.h (DECL_RESULT_TYPE): New field in FUNCTION_DECL holds the type + of the widened returned value (not nec. the declared return type). + * c-decl.c (start_function): Set DECL_RESULT_TYPE. + * integrate.c (expan_inline_function): Use that, not DECL_RESULT. + +Thu Dec 1 16:44:10 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * cse.c (fold_rtx): When reordering constant args, insist on + manifest constants; regs with known contents won't do. + + * i386.md (mulsi3): Don't use rtx_equal_p to compare regs. + + * expr.c (move_by_pieces_1): Don't call change_address + if address is autoinc, since that may not be memory_address_p. + Subroutine-macro add_offset deleted. + + * optabs.c (bcc_gen_fctn, setcc_gen_fctn): Moved to this file. + (init_optabs): Init those tables here. + * expr.c (init_conditions): Not here. + + * stmt.c (assign_stack_local): Make a list of all stack slots. + * emit-rtl.c (unshare_all_rtl): Unshare all the stack slots. + + * final.c (final): Handle BARRIER with ASM_OUTPUT_ALIGN_CODE. + * tm-ns32k.h (ASM_OUTPUT_ALIGN_CODE): Align to 4-byte bdry. +?? * tm-sequent.h (ASM_OUTPUT_ALIGN_CODE): Override: just 2-byte bdry. + + * tm-m68k.h (PRINT_OPERAND): use new macros to print floats. + (ASM_OUTPUT_FLOAT_OPERAND): New macro. + (ASM_OUTPUT_DOUBLE_OPERAND): New macro. + * tm-sun3.h: Override those macros, to check for infinities. + +Wed Nov 30 06:35:47 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * tm-ns32k.h (FUNCTION_{PRO,EPI}LOGUE): if no frame pointer, + do explicit push or pop insns. + + * tm-genix.h (PRINT_OPERAND): Fix typo `file'. + Extedn decl for paren_base_reg_printed. + (MAIN_FUNCTION_PROLOGUE): Deleted. + (ASM_OUTPUT_EXTERNAL): Defined. + + * c-parse.y (yyerror): Better error msg for unprintable char in token. + (primary => identifier): Set TREE_USED if implicit decl made. + + * Makefile (cleanlinks): New target. + (INSTALL): New variable, has program used for installing files in sys. + + * output-ns32k.c (print_operand_address): If addr is sum of 2 consts, + output ADDR first, then OFFSET. + + * ns32k.md (addsi3): Allow adding const+reg with result in another reg. + + * tm-seq386.h (FUNCTION_PROFILER): Provide overriding definition. + + * tm-hp9k320.h: Alternate ASM_SPEC if using GAS. + Define STANDARD_STARTFILE_PREFIX if using GAS. + (FUNCTION_PROLOGUE): on 68020 for big stack frame use link.l. + + * gcc.c (STANDARD_STARTFILE_PREFIX): New cust. macro replaces `/lib/'. + + * va-sparc.h, va-spur.h: Prefix non-interface identifiers with `__'. + + * optabs.c (init_optabs): Don't set up libcalls for ftrunc_optab + because (1) they aren't supported and (2) they are never used. + + * gnulib.c (__builtin_saveregs): If not sparc, define the symbol anyway + to avoid a warning in ranlib. + +Mon Nov 28 01:46:12 1988 Michael Tiemann (mdt at choctaw) + + * c-parse.y (yylex): Typo, `=' for `==' making wide strings. + + * sparc.md (various places): make sure that all patterns which store + can store using const0_rtx (i.e., make all operands to `st' %rx). + + * output-sparc.c (various places): changed dispatches on SYMBOL_REF + to dispatches on CONSTANT_ADDRESS_P since we now recognize any CONST + (and not just SYMBOL_REFs). Don't recognize special case CONST for + output_block_move. Compiler doesn't have enough information to use + it. + + * stmt.c (expand_fixup): If the control stack is nested within the + nesting stack, then no fixup is needed. Otherwise, compiler must + check for possible fixups between the current nesting stack and the + nesting stack that immediately contains the control stack. + + * stmt.c (expand_function_start): functions which are nested use + DECL_CONTEXT. For these functions, test that their DECL_CONTEXT is + a LET_STMT node. + + * tree.h: declare `build_offset_type'. + +Sun Nov 27 10:34:53 1988 Richard Stallman (mdt at yahi) + + * output-sparc.c (output_move_double): + Don't try to use ldd/std if OP1 is a constant. + * sparc.md (movdi): Allow immediate args moved into general regs. + + * c-decl.c (grokparms): Reject incomplete parm types even if just + declarating, not defining. Change types to error_mark_node + in both the PARM_DECL and the list of types. + + * dbxout.c (dbxout_type): It's not a bug if a RECORD_TYPE + has a typedef as its TYPE_NAME. That happens in C++. + + * Make each `asm' with operands record its source file/line + with reg-notes. It doesn't work to emit a special note before the insn + because the insn can be moved by loop_optimize. + * stmt.c (expand_asm_operands): New args FILENAME, LINE. + Record them in the insn, in reg notes. + * c-typeck.c (c_expand_asm_operands): New args, passed along. + * c-parse.y: Pass those args. + (maybe_type_qual): Line #s for asm stmts emitted like all others. + * rtl.h (REG_ASM_FILE, REG_ASM_LINE): New kinds of reg notes. + * toplev.c (error_for_asm): Get the info from those notes. + + * reload.c (find_reloads): Don't clear BADOP for a reg letter + if the alternative ultimately doesn't allow any regs. + + * reload.c (find_reloads): If an `asm' insn gets an error, + change it to a USE to avoid duplicate error msgs or later trouble. + + * reload.c (find_reloads_address): Reloading a constant address, + specify Pmode as the mode for push_reloads, in case of CONST_INT. + + * expr.c (emit_push_insn): Fix calc. of space needed when PARTIAL > 0. + Both scalar case and BLKmode case needed fixing. + + * sparc.md (load/store constant address): + Moving DF from mem to cpu regs, don't go via %f0. + Don't use std/ltd if alignment is wrong or uncertain. + +Sun Nov 27 10:34:53 1988 Michael Tiemann (mdt at yahi) + + * reload.c (push_reload): Allow VOIDmode for INMODE, OUTMODE; + default the mode from the operand values. + + * sparc.md: remove patterns which generate annulled branch insns. + They are correct, but those insns confuse GDB. + + * tm-sparc.h (GO_IF_LEGITIMATE_ADDRESS): + Treat any constant address like a SYMBOL_REF. + * sparc.md: Check for CONSTANT_ADDRESS_P rather than SYMBOL_REF. + + * sparc.md: Peepholes now accept SYMBOL_REF addresses. + The output routine can now split them properly even as delay insns. + + * print-tree.c (dump): added entry for METHOD_TYPE and + METHOD_CALL_EXPR. Also added entry for WITH_CLEANUP_EXPR. Suggest + that we make first_rtl of WITH_CLEANUP_EXPR 2 instead of 1. + +Sun Nov 27 00:15:33 1988 Michael Tiemann (mdt at yahi) + + * print-tree.c (dump): added entry for OP_IDENTIFIER. + + * tree.c (build_op_identifier): new function. Needed because + `build_nt' expects an "e" node, but OP_IDENTIFIER is an "x" node. + + * store_layout.c (layout_record): use DECL_FIELD_CONTEXT instead of + DECL_CONTEXT. + + * tree.h (DECL_FIELD_CONTEXT): new macro. Points to the type that a + FIELD_DECL is a member of. For C, this is just DECL_CONTEXT. + + * tree.c (build_method_type): typo used "==" to assign basetype to + TYPE_METHOD_BASETYPE with predictably poor results. + +Sat Nov 26 22:55:32 1988 Michael Tiemann (mdt at yahi) + + * output-sparc.c (output_sized_memop): new function to output a load + or store insn based on the size of the operand loaded or stored. + (make_f0_contain_0): use info from condition codes to decide whether + the register %f0 needs to have 0 loaded from memory or not in order + to contain zero. + (gen_scc_insn): new function used by define_expands for + set-on-condition-code insns. + (output_delay_insn): now knows how to handle load and store + scheduling when the load or store operation takes two insns instead + of one. The rewrite is now understands is this: + + sethi %hi(address),%g1 -> sethi %hi(address),%g1 + ld/st [%g1+%lo(address)],%reg -> b target + b target -> ld/st [%g1+%lo(address)],%reg + nop -> ;; gone + + * jump.c (reverse_condition): make this function publicly visible, + now needed in expr.c. + + * output-sparc.c (reg_or_0_operand): new function, returns nonzero + if operand is const0_rtx or a register of specified mode. + (hardreg): deleted. + + * expr.c, stmt.c: fixed random syntax errors. + + * tree.c (build_method_type): now corresponds to defn in tree.def + expr.c (expand_call): removed code to get FUNCTION_TYPE from + METHOD_TYPE. This should probably be looked at harder. + + * tree.def (METHOD_TYPE): Changed definition so that TREE_TYPE (m) + (where m is a METHOD_TYPE) is the type of the return value of the + method, not the FUNCTION_TYPE from which the METHOD_TYPE is derived. + + * Makefile: Changed target of BINDIR from /usr/local to + /usr/local/bin. + +Sat Nov 26 16:29:22 1988 Michael Tiemann (mdt at chickasaw) + + * tm-sparc.h (GO_IF_LEGITIMATE_ADDRESS): Allow any SYMBOL_REF. + (NOTICE_UPDATE_CC): Remember high half of %g1 as a "condition code" + to avoid reloading it if it does not change. + (NOTICE_UPDATE_CC): Test SET_SRC, not SET_DEST, for a CALL rtx. + (PRINT_OPERAND): New code-letter `m' says output operand as an address. + + * toplev.c (flag_syntax_only): New flag variable. + * flags.h: Likewise. + + * toplev.c (error_with_decl): Extra arg, passed to fprintf. + (warning_with_decl): Likewise. + + * tree.c (build_offset_type): New function. + + * tree.h (TYPE_METHOD_BASETYPE): New name for TYPE_METHOD_CLASS. + Uses in tree.c and... renamed. + + * combine.c (SUBST_INT): New macro, for replacing an int. + (subst): Collapse nested SUBREGs even if SUBREG_WORDs are not 0. + + * expr.c (bcc_gen_fctn, setcc_gen_fctn): new tables, + initialized in init_comparisons. + Used in expand_expr, do_jump, do_store_flag + instead of explicit construction of a jump. + + * expr.c (save_noncopied_parts): New function. + + * expr.c (expand_expr): + ARRAY_REF: Special case for array of constants. + WITH_CLEANUP_EXPR: Handle it. + INIT_EXPR: Case deleted. + MODIFY_EXPR: Use save_noncopied_parts. + + * expr.c (expand_call): blkmode_parms_forced can be >0 + even when no stack arg space otherwise needed. + Don't use a hard reg as a target if there are cleanups. + + * stmt.c (struct block): New elt. outer_cleanups. + (struct case): New elt. num_ranges. + (struct fixup): Changed meaning of cleanup_list_list. + Changes in expand_fixup, fixup_gotos. + (expand_fixup): Detect some internal forward-jumps + that need no fixups--for speed. + (fixup_gotos): New arg THISBLOCK. + (expand_expr_stmt): Handle flag_syntax_only. + (use_variable): No longer static. + (use_variable_after): new fn. + (expand_end_bindings): handle cleanups like a stack level. + (expand_decl): Handle a cleanup with no decl. + (move_cleanups_up): Preserve relative order of cleanups. + (expand_anon_union_decl): New fn. + (pushcase): New fast clause if no ranges yet. + (pushcase_range): Turned on. + (expand_function_start): New temp var `fntype'. + Set TREE_USED for a parm we are ignoring. + (expand_function_end): Really use the `filename' arg. + Use use_variable_after for SAVE_EXPR regs. + + * dbxout.c (dbxout_type): Handle OFFSET_TYPE. + + * gnulib.c (__builtin_new, etc.): Support for C++. + + * emit-rtl.c (next_insn, prev_insn): New fns. + +Sat Nov 26 16:29:22 1988 Richard Stallman (mdt at chickasaw) + + * tree.h (TREE_LANG_FLAG_[1234]): New attributes. + (TYPE_METHOD_BASETYPE): New name for TYPE_METHOD_CLASS. + (TYPE_OFFSET_BASETYPE): New macro. + (NUM_TREE_CODE): New macro. + (TYPE_NONCOPIED_PARTS): new field in a type-node. + + * varasm.c (make_decl_rtl): Split out from assemble_variable. + (assemble_variable): No longer creates the rtl. + No longer handles policy of whether to output tentative decl yet. + (output_constant_def): Don't lose if wasn't temp allocation + when this was called. + (output_constant): Handle REFERENCE_EXPR. + + * Makefile (BISONFLAGS): new variable. + (prefix): New variable, used in bindir and libdir. + (C_OBJS, CPLUS_OBJS): New vars, split off from OBJS. + (LIBFUNCS): C++ support functions added. + (CPLUS_TREE_H): New variable. + (cc1plus): New target. + (lang_c, lang_cplus): Combines all targets for one language. + (gplus.info): New target. + (cplus-*.o): New targets. + (realclean): Handle new C++ files and recent renamings. + (install, TAGS): Likewise. + + * print-tree.c (prtypeinfo): Handle TREE_LANG_FLAG_[1-4]. + + * tm-sparc.h (ASM_OUTPUT_DOUBLE): Special case for infinity. + (ASM_OUTPUT_FLOAT): Likewise. + + * gcc.c: Don't define __GNU__. + For .cc files, pass -+ to cpp, and don't handle -ansi. + Use cc1plus as name of compiler for .cc files. + + * stor-layout.c (layout_type): abort if given a LANG_TYPE node. + (layout_union): Complain if union has basetypes or static members. + (layout_record): Handle anonymous union members. + + * tree.def (LANG_TYPE): New tree code for language-specific purposes. + (WITH_CLEANUP_EXPR): New tree code for expressions whose values + need to be cleaned up when they are deallocated. + (OP_IDENTIFIER): New tree code for certain C++ purposes. + + * toplev.c (rest_of_decl_compilation): Call make_var_rtl + before assemble_variable. + +Wed Nov 23 02:15:45 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * xm-sunos4.h: Rename included config files to xm-*. + * xm-*.h: Likewise. + + * fixincludes: Avoid altering args to names other than CTRL + that end in ...CTRL. + If a file isn't actually changed, delete the copy. + +Mon Nov 21 12:48:22 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * loop.c (move_movables): Never move a reg w/ # > old_max_reg. + (strength_reduce): For nonreplaceable giv, put insn to load it + after the insn that used to compute it, in case the latter + is the last of a libcall sequence. + + * stmt.c (expand_function_end): If returning BLKmode, also copy + address where value is returned to the place that GDB will + expect to see it after the return. + + * c-parse.y (readescape): Warn about hex constant out of range + for a target integer. + (yylex): Warn about escape out of range for non-wide char or string. + Use a buffer of ints to read a wide string. + +Sat Nov 19 02:18:02 1988 Richard Stallman (rms at apple-gunkies.ai.mit.edu) + + * Version 1.31 released. + + * sparc.md: Change `K' to `I' in all constraints. + + * loop.c (gen_iv_mult): Handle TARGET==0. + + * c-decl.c (duplicate_decls): Undo last change. + + * c-decl.c (pushdecl): Instead of that change, + save old-decl's file/line before calling duplicate_decls, + and pass them later to warning_with_file_and_line. + * toplev.c (warning_with_file_and_line): New fn. + +Fri Nov 18 13:07:06 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * stmt.c (fixup_var_refs_1): (SUBREG (MEM)) was slipping through + in case where a SET was writing in the variable being fixed. + + * recog.c (register_operand, nonmemory_operand, memory_operand): + Changes to handle new var reload_completed: 1 means that + (SUBREG (MEM)) now counts as a mem-ref, since alter_subreg + will make it one. + * toplev.c (rest_of_compilation): Set and clear reload_completed. + + * sparc.md (call patterns): If TARGET_SUN_ASM, and address in reg, + output a jmpl rather than a call. + * tm-sun4os3.h: Like tm-sparc.h but turn on TARGET_SUN_ASM. + + * reload.c (push_reloads): Reinstate handling of reg_equiv_constant. + +Thu Nov 17 09:48:14 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * reload1.c (constraint_accepts_reg_p): Name changed from + constraint_all_regs_p; new arg is reg we are concerned with, + and condition tested takes some advantage of that reg. + + * gcc.c (main): Rename var `error' to `error_count' for name conflict. + + * emit-rtl.c (emit_note): Output line #s even if no debug info wanted. + (emit_line_note): New fn, does what emit_note did. + (emit_line_note_force): New name for emit_note_force. + * stmt.c, c-parse.y: Call emit_line_note instead of emit_note. + + * c-parse.y (maybe_type_qual): Call emit_note instead of emit_line_note + Now we can find the line # of every `asm' from the RTL. + * toplev.c (error_for_asm): New fn, gets line # by searching for NOTE. + * reload.c (find_reloads): Use error_for_asm. + * reload1.c (choose_reload_targets): Likewise. + * final.c (output_operand_lossage): Likewise. + Variable this_is_asm_operands is now current insn if it's nonzero. + + * loop.c (move_movables): When a reg is moved, update regno_first_uid + and regno_last_uid; say life span includes entire loop. + * Decrement THRESHOLD per reg moved, not per insn moved. + +Wed Nov 16 08:41:32 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * gnulib.c (___builtin_saveregs): New fn, for sparc. + + * tm-sparc.h (GO_IF_LEGITIMATE_ADDRESS): Don't recognize + SYMBOL_REFs, except for the constants pool. + But do recognize REG+REG and SMALLINT+REG. + * sparc.md: New patterns for fetching and storing memory + whose address is symbolic and not "legitimate". + + * sparc.md (movsi): Add `f' to op1 constraint. + New output clause for result in fp reg. + (Floating point fetch patterns): Output sethi insns. + (call_value, related patterns): value-register has `register_operand'. + + * output-sparc.c (hardreg): New function. + (COMPATIBLE): Clause added for n_regs == 2. + (single_insn_src_p): Return 0 for MEM whose address is absolute. + + * tm-genix.h (GO_IF_LEGITIMATE_ADDRESS subroutines): + Redefine, to exclude any possibility of SB-referencing addresses. + + * loop.c (strength_reduce): Can't eliminate a biv if used before + start of the loop. Used before is same as used after, if contained + in another loop. + + * recog.c (asm_noperands, decode_asm_operands): + Handle case of no outputs, but some clobbers. + * stmt.c (expand_asm_operands): Generate right stuff for that case. + + * tm-sun3.h (CPP_SPEC): Don't define __HAVE_68881__ if using fpa. + +Tue Nov 15 00:10:26 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * loop.c (gen_iv_mult): Arg OP0 may not be a constant. + Pay attention to return value of expand_mult. + (eliminate_biv): Call changed. + + * output-m88k.c, output-sparc.c (output_move_double): + Fix typo `optype0' for `optype1'. + + * c-decl.c (duplicate_decls): Don't alter file, line of old decl. + + * c-parse.y (skip_white_space): Don't recognize comments; rely on cpp. + + * rtl.c (rtx_equal_p): Handle vectors. + + * loop.c (scan_loop): Change elts of n_times_set back to positive + for candidates that weren't moved, before doing strength reduction. + + * ns32k.md (movdi, movdf): Use `&' constraint for first operand. + + * reload1.c (reload): Initialize spill_indirect_ok here. + + * config-sun4.h: Recognize `-static' switch. + + * global-alloc.c (set_preference): Avoid using nonsense hard reg #s + that result from adding OFFSET. + + * sdbout.c (sdbout_end_function): Line # in .ef should be relative. + + * final.c (output_source_line): For SDB, don't output negative #s. + + * tm-encore.h (ASM_OUTPUT_LOCAL): Don't ignore SIZE arg. + +Mon Nov 14 11:03:16 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * reload.c: Don't declare refers_to_regno_p. + + * gcc.c (main): Warn if any input files are for the linker + but the linker is not being run. + + * jump.c (sets_cc0_p): Dumb bug fetching elts of a PARALLEL. + + * local-alloc.c: qty_birth, qty_death elements are now -1, not 0, + when the value is not known. + + * expmed.c (extract_bit_field): Bug computing xbitpos, xoffset + when changing units from bytes to words. + + * loop.c: Rename `times_used' field in `struct movable' to `savings'. + (scan_loop): When scanning the consecutive sets, for each libcall, + increment `savings'--leave `consec'. + When making movable for (SET (REG) 0) which is part of zero-extension, + set `savings' to 1 initially, since only 1 insn will be moved. + And don't let any other reg force that insn. + Reduce initial THRESHOLDs. + (move_movables): Don't add `consec' into `savings' + since the initial `savings' was proportional to `consec'. + Decrement THRESHOLD by 3 (not 2) for each move done. + + * reload1.c (choose_reload_targets): Strip subregs from OLD + before writing the output-reload move-insn. + + * reload1.c (reload): counted_for_groups and counted_for_nongroups + are now file-scope. Update them both when spilling. + (new_spill_reg): No need for counted_for_nongroups as arg. + (choose_reload_targets): Don't use for a group + any spill regs for which counted_for_nongroups is set. + + * dbxout.c (dbxout_symbol): Indirect-symbol case checked erroneously + for PARM_DECL. + +Sun Nov 13 08:13:49 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * cse.c (fold_rtx): Don't alter MULT by -1 if arg mode != result mode. + + * loop.c (move_movables): If moving a CALL_INSN, make a new CALL_INSN. + * emit-rtl.c (emit_call_insn_before): New fn. + + * config-sun4.h (LINK_SPEC): Avoid shared libraries if -g. + + * expr.c (store_one_arg): Stabilize ARG->stack so it doesn't use SP + before computing the arg value. + + * combine.c (use_crosses_set_p): Moving a ref to stack ptr + is always forbidden if machine has push insns, since might cross one. + + * vax.md (movqi): Avoid out-of-range immed ops in mcomb. + + * expmed.c (extract_bit_field): Don't say `extzv' in the + clause for `extv'. + + * emit-rtl.c (copy_rtx_if_shared): Even if a MEM can be shared, + unshare its address from everything outside that MEM. + + * expr.c (expand_builtin): Fix omitted arg to `convert_to_mode'. + + * expr.c (store_expr): In case where will not return TARGET + and must do type conversion, don't fail to store into TARGET. + + * dbxout.c (FORCE_TEXT): New macro used before output `.stabs' + to go to the text section on targets that require it. + (DEBUG_SYMS_TEXT): Target macro which turns on that feature. + + * reload1.c (reload): Index in spill_regs was wrong + when checking counted_for_groups. + (choose_reload_targets): When calling find_equiv_reg looking for + a reload reg, reject all spill regs, even those not in use now. + + * tm-sun386.h, tm-sun386i.h, config-sun386i.h: New files. + + * cccp.c (main): Don't die if no output file arg given. + + * fixincludes: Tell `find' to find only ordinary files. + + * config.gcc: If symlink fails, make a hard link. + +Sat Nov 12 20:43:20 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * Makefile (gnulib): Use cp to make the temporary .c files; + less likely to fail than ln. + +Sat Nov 5 12:46:39 1988 Randall Smith (randy at sugar-bombs.ai.mit.edu) + + * tm-m68k.h (HARD_REGNO_MODE_OK): Disallowed d7:a0 as an allowable + pair of registers to hold a double value. This is correct for the + fpa but incorrect for the 68881. It was, however, simpler than + defining a new regclass. + +Tue Oct 25 12:03:49 1988 Randall Smith (randy at gluteus.ai.mit.edu) + + * m68k.md: Added some thoughts (comments) on best method to allow + 68881 code with fpa code. + +Thu Oct 13 14:19:17 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * Version 1.30 released. + + * stupid.c (stupid_life_analysis): Init last_call_suid with + largest possible value, not 0. + +Wed Oct 12 04:40:18 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * output-i386.c (output_asm_insn_double_reg_op): Compensate for + assembler bug that interchanges fsub and fsubr. + + * reload1.c (order_regs_for_reload): Undo 29 Sept change. + It breaks the 386. + + * varasm.c (decode_rtx_const): Don't example value->addr + if what was stored in was value->d. + + * toplev.c (set_float_handler): New fn, specify where to jump + on floating exception signal. + * fold-const.c (combine): Use that to handle overflow in arithmetic. + + * c-decl.c (grokdeclarator): Don't clear CONSTP, VOLATILEP + when making an array type. + + * dbxout.c (dbxout_symbol): Ignore VAR_DECLs in memory whose + addresses we can't represent. + + * fold-const.c (fold): don't convert >= to > if both args are constant. + When converting >= to >, don't fail to change CODE. + +Tue Oct 11 04:13:40 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * vax.md (movhi): Error in truncating mcomw, addh3 args to 16 bits. + + * final.c: Better error checking for %-specs in templates. + (output_operand_lossage): new fn to report errors. + (insn_noperands): new var: # operands in current fn. + (this_insn_asm_operands): new var: 1 for `asm', 0 otherwise. + (output_asm_insn): Check for operand # out of range. + (output_asm_label, output_operand): Call new fn to report errors. + + * reload.c (push_reloads): An input reload for (REG N) can match one + for (POST_INC (REG N)) or (PRE_INC (REG N)), since the value + reloaded is the same in any case. + +Mon Oct 10 06:19:05 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * recog.c (next_insns_test_no_inequality): Like next_insn_tests... + but check all insns that follow this one and can use it's cc's. + * output-m68k.c (output_btst): Use that. + + * vax.md (movsf, movdf): Undo last change; movq/movl set the cc wrong. + + * expr.c (expand_call): Set current_function_calls_setjmp if appro. + * stmt.c (setjmp_protect): New fn: move all vars into stack + unless declared `register'. + * c-decl.c (finish_function): Call it if -traditional and setjmp used. + + * cccp.c (main): Open output after the input. + Handle `-o -'. + +Sun Oct 9 00:28:06 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * tm-sun3.h (CPP_SPEC): Define __HAVE_FPA__ if appropriate. + + * c-decl.c (pushdecl): After duplicate_decls, maybe warn about + "declared extern and later static". + + * expmed.c (store_bit_field): In insv case, avoid turning + VALUE into a subreg of a subreg. + + * loop.c (move_movables): When moving a libcall, + un-cse the function address; put it into the call insn. + +Sat Oct 8 01:48:03 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * cse.c (equiv_constant): Subroutine to find the constant equivalent + of a reg. Now handles SUBREGs too. + (fold_rtx, fold_cc0): Use that function. + Don't handle SUBREGs like arithmetic. + + * reload1.c (choose_reload_targets): Don't call reg_overlap_mentioned_p + if arg is 0. + +Fri Oct 7 01:00:19 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * assert.h: Typo declaring __eprintf. + + * config.gcc: New file for making the links. + Fixed bugs for sun-[23]-os4. Added sun-[234] for sunos 3. + Added sequent-i386. + + * emit-rtl.c (gen_rtx): Return const0_rtx for 0 in DImode. + * varasm.c (immed_double_const): Don't be confused by this. + + * expmed.c (negate_rtx): New 1st arg MODE. + * expr.c (push_block): Calls changed. + * m68k.md, ns32k.md, vax.md: Calls changed. + + * c-decl.c (duplicate_decls): Don't discard DECL_BLOCK_SYMTAB_ADDRESS. + + * tree.c (staticp): INDIRECT_REF with constant address is static. + COMPONENT_REF may not be, if component offset isn't constant. + + * c-typeck.c (default_conversion): Converting array to ptr, if array + isn't a VAR_DECL, go through build_unary_op so that COMPONENT_REFs + will be simplified away. + + * ns32k.md (tbitd patterns): op 0 constraint: reject constants. + * ns32k.md (extzv for SImode and HImode): + Use adj_offsetable_operand; plus_constant was the wrong thing. + +Thu Oct 6 00:10:41 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * Version 1.29 released. + + * loop.c (scan_loop): Don't think a `return' insn enters the loop. + + * ns32k.md (ashrsi3, etc): New define_expands for right shift. + + * reload1.c (choose_reload_targets): Change in the `force_group' + logic to avoid crashes. + +Wed Oct 5 04:09:19 1988 Richard Stallman (rms at corn-chex.ai.mit.edu) + + * expr.c (expand_expr, MINUS_EXPR): When negating integer op1, + truncate it to its mode. + + * expmed.c (extract_bit_field): SUBREG error check was wrong; + SImode SUBREGs are possible and ok in extzv, extv. + + * tm-ns32k.h (REGISTER_NAMES): Had two excess elements; deleted. + +Mon Oct 3 01:15:51 1988 Richard Stallman (rms at corn-chex.ai.mit.edu) + + * toplev.c (main, compile_file): If no files spec'd, use stdin, stdout. + + * flow.c (propagate_block): When checking for stack-adjust insns, + exclude non-SET patterns. + + * jump.c (jump_optimize): When changing jump=>return to return, + must rerecognize the insn. + + * toplev.c (compile_file): Allow `-' for main input or output filename. + +Sun Oct 2 10:30:09 1988 Richard Stallman (rms at apple-gunkies.ai.mit.edu) + + * final.c (final): NOTICE_UPDATE_CC has extra arg, INSN. + * tm-*.h: Change definitions. + + * stmt.c (optimize_bit_field): Use gen_lowpart to make subregs. + + * stmt.c (assign_parms): Don't obey regdecls in inline function. + Don't lose existing REG_NOTES when adding one. + + * stmt.c (expand_function_start): Make return rtx before + marking parms live. + (expand_function_end): Use use_variable to emit USEs for SAVE_EXPRs. + + * stmt.c (expand_return): Handle TRUTH_AND_EXPR like ANDIF; OR also. + + * stmt.c (expand_end_stmt_expr): Always set TREE_VOLATILE, + sometimes TREE_THIS_VOLATILE. + + * jump.c (delete_insn): When finding PREV, skip deleted insns. + + * varasm.c (output_constant): WORDS_BIG_ENDIAN test was backwards. + + * emit-rtl.c (gen_lowpart): Allow MODE > 1 word if X is same size. + + * final.c (final): Don't delete no-op moves (jump did it if appro.). + + * final.c: Support prescan pass. + (final_start_function): init_recog and CC_STATUS_INIT mvd to `final'. + (final): New arg PRESCAN. Do no output if prescanning. + Don't alter conditionals if PRESCAN < 0 (prescan already done). + If jump becomes no-op, change it to a NOTE. + Remember to free the temp space for ASM_OPERANDS. + + * final.c (final): Altering store-flag must check STORE_FLAG_VALUE. + Don't try to do it if that isn't defined. + Don't try it if condition doesn't test CC0. + (alter_cond): No need to check COND != 0. + Handle CC_Z_IN_NOT_N and CC_Z_IN_N. + (m68k.md): Delete code that handled CC_Z_IN_NOT_N. + + * conditions.h: New flag CC_Z_IN_N. + * tm-*.h: Renumber all CC_... flags to make room. + + * combine.c (use_crosses_set_p): Loop start was 1 off. + + * local-alloc.c (reg_is_set): When a reg is CLOBBERed and dies in + one insn, make it live immediately before and after that insn. + + * global-alloc.c: Hard reg preferences for global pseudos. + Var allocno_preferred_reg deleted; new vars hard_reg_preferences + and regs_someone_prefers. + (global_alloc): Init those vars. Pass hard_reg_preferences elt + to find_reg. + (set_preference): New function makes entries in those vars. + (global_conflicts): new arg to mark_reg_store. Call set_preference. + (find_reg): Last arg now a preferred hard_reg_set. + Scan that set first of all. + (mark_reg_store): New arg is offset for renumbered regno. + But the code to use it is turned off. + + * global_alloc (check_frame_pointer_required): Handle reg_equiv_address + like reg_equiv_mem. Don't try to allocate pseudos with equiv mems + that don't use the frame pointer. + * reload1.c (reload): Call changed. + + * jump.c (sets_cc0_p): Tests whether rtx sets cc0, and whether + it does nothing but set cc0. + (find_cross_jump, delete_jump): Use that fn for these tests. + * loop.c (loop_skip_over): Likewise. + * reload.c (push_reload): Likewise. + + * genoutput.c: Output `const' before the data arrays. + Define it as nothing if not __STDC__. + +Sat Oct 1 02:19:29 1988 Richard Stallman (rms at apple-gunkies.ai.mit.edu) + + * expr.c (store_one_arg): 3rd arg to emit_block_move is in bytes. + + * cse.c (fold_rtx): Handling ZERO_EXTEND or SIGN_EXTEND of constant, + if the arg width is too wide to handle, return safely. + + * combine.c (FAKE_EXTEND_SAFE_P): Don't allow extend to > 1 word. + + * rtl.c (refers_to_regno_p): Moved from reload.c. Not static. + (reg_overlap_mentioned_p): New function, calls the above. + * output-*.c: Use that instead of reg_mentioned_p. + * tm-*.h (NOTICE_UPDATE_CC): Likewise. + * reload.c (push_reload, combine_reloads): Likewise. + * reload1.c (choose_reload_targets): Use it to check earlyclobbers. + + * reload1.c (choose_reload_targets): Elimination of previous + output-reload feeding our input now limited to pseudo-regs. + + * flow.c (life_analysis): Delete any insn copying reg to itself. + (propagate_block): Move update of OLD after special life and death + for CALL_INSNs. + + * vax.md (ashrsi3, ashrdi3, rotrsi3): define_expands to negate + the shift count. + * expmed.c (expand_shift): Eliminate negate-the-shift-count feature. + + * vax.md (and*i3): define_expands which use complement and bit-clear. + * expmed.c (expand_bit_and): Eliminate feature to do that. + This function could be eliminated. + + * expmed.c (store_bit_field): Handle nested subregs. + Allow gen_insv to fail; if it does, delete what we did and then + use store_fixed_bit_field. + (store_fixed_bit_field): Use gen_lowpart to make SUBREGs. + Do that for SUBREGs just as for REGs. + Error check OFFSET must be 0 for REGs. + (store_split_bit_field): Error check OP0 is a SUBREG when expected. + (extract_bit_field): Allow gen_ext{,z}v to fail. + Use gen_lowpart to make subregs. + (expand_shift): If a try fails, delete any insns it made. + + * expmed.c (expand_mult): Use expand_unop to negate. + When adding 2 powers of 2, do serial shifts, not parallel. + Handle absval==1 like other powers of 2. + + * explow.c (force_reg): Don't lose any existing reg notes. + + * stmt.c (expand_start_stmt_expr): Eliminate return value. + (expand_end_stmt_expr): No need for argument. + * c-parse.y (primary): Change calls. + +Fri Sep 30 01:50:22 1988 Richard Stallman (rms at corn-chex.ai.mit.edu) + + * integrate.c (copy_rtx_and_substitute, copy_address): + 'u' case erroneously returned the translated single element. + (copy_address): Special cases for frame-ptr and sums containing it. + MEM and LABEL_REF cases passed wrong arg to copy_rtx_and_substitute. + (copy_rtx_and_substitute): adjust mode of inline_target for context. + + * jump.c (true_regnum): For SUBREG of pseudo, use pseudo's # unchanged. + +Thu Sep 29 02:50:46 1988 Richard Stallman (rms at corn-chex.ai.mit.edu) + + * i386.md (movsi, mov{q,h}i): Use find_reg_note to look for REG_WAS_0. + * vax.md (movsi, movhi): Likewise. + + * varasm.c (decode_rtx_const): Was setting un.addr.base wrong + for a CONST. Should be symbol name, not the SYMBOL_REF. + + * rtl.c (rtx_equal_p): When comparing registers, check + REG_FUNCTION_VALUE_P. If there are `u'-slots in the rtx, ignore them. + + * rtl.c (reg_mentioned_p): Some rtx types were mistakenly treated + as uniquified (various constants). + + * rtl.c (read_rtx): Element type 'S' is string that may be omitted. + * rtl.def (define_insn, define_peephole): Add a last element, type 'S'. + * genoutput.c: Collect these optional last elements and output as + array `insn_machine_info' of structs `INSN_MACHINE_INFO'. + The last must be defined as a macro. + * recog.h (insn_machine_info): Declare it if appropriate. + + * regclass.c (record_address_regs): In PLUS case, look inside SUBREGs. + + * reload1.c (reload): Use reg_equiv_address for REG_EQUIVs with + invalid memory addresses. + When changing pseudos to mem refs at end, do FIX_FRAME_POINTER_ADDRESS + on their addresses. + (alter_reg): Check that with reg_equiv_mem. + (spill_hard_reg): If fp reg, spill regardless of basic_block_needs. + + * reload1.c (order_regs_for_reload): Don't put invalid regs into + potential_reload_regs at all. (They used to go at the end.) + + * reload.c (find_reloads): Store all earlyclobber operand in + reload_earlyclobbers (# in n_earlyclobbers): + * reload.1 (choose_reload_targets): Don't use value of find_equiv_reg + if it matches an earlyclobber operand. + + * reload.c (find_reloads_address for REG): + No need for explicitly excluding hard regs in these tests. + (find_reloads, find_reloads_address_1 for REG): likewise. + + * reload.c (push_reload): Code testing reg_equiv_constant should + be obsolete; add error check to verify this. + + * reload.c (hard_reg_set_here_p): Handle CLOBBERs, SUBREGs, overlap. + (refers_to_regno_p): Handle CLOBBERS. Handle overlap. + New arg ENDREGNO specs end of range to check for; + all callers changed (all in this file). + + * reload.c (find_reloads): SUBREG like REG in alternate recovery + for earlyclobber conflict. + The operands to unswap are those that are supposed to commute. + When operands match, copy the regclass of earlier one for later one. + + * stmt.c (optimize_bit_field): Don't use gen_extend_insn; + use convert_move, then reorder the insns. + * optabs.c (gen_extend_insn): Deleted. + + * optabs.c (emit_cmp_insn): Don't emit queue before recursion. + Don't convert size to SImode for cmpstrqi. + + * optabs.c (expand_binop): Keep any old REG_NOTES when adding them. + Always delete_insns_since if returning failure. + (expand_unop, emit_unop_insn): Keep any old REG_NOTES when adding them. + * spur.md (movhi): likewise. + + * RTL_EXPR_SEQUENCE is now a chain of insns, not a SEQUENCE. + * emit-rtl.c (emit_insns): New fn, emit a chain of insns. + * expr.c (expand_expr): Use that. + Also put const0_rtx in the RTL_EXPR_SEQUENCE (mark RTL_EXPR as output). + * stmt.c (expand_end_stmt_expr): Use get_insns to get the chain. + + * stmt.c (expand_end_stmt_expr): Put the RTL_EXPR on rtl_expr_chain. + (fixup_var_refs): Scan all waiting RTL_EXPRs not yet output. + Also scan all stacked sequences on sequence_stack. + + * genemit.c (gen_expand): Generate calls to {start,end}_sequence. + Use `emit' to handle a PARALLEL. + (FAIL, DONE): Change to fit gen_expand changes. + + * emit-rtl.c (change_address): abort if arg isn't a MEM. + + * emit-rtl.c: Sequences work now by saving and restoring first_insn + and last_insn. So these variables are used even when in a sequence. + emit_to_sequence has been deleted. + (start_sequence, end_sequence): Save and restore first_insn, last_insn. + (get_last_insn, add_insn): Sequences no longer need special treatment. + (delete_insns_since, reorder_insns): likewise. + (push_to_sequence): Set up to emit to a given existing insn chain. + + * emit-rtl.c (copy_rtx_if_shared): Don't copy INSNs. + Insert missing return stmt in MEM case (for MEMs ok to share). + (unshare_all_rtx): Now can copy the REG_NOTES simply. + Copy the LOG_LINKS too. + + * emit-rtl.c (make_safe_from): Treat SUBREG as X like a REG. + (delete_insns_since): Don't lose if FROM is the first insn. + (emit): Declare void, since no useful value. + Call simplejump_p properly. + (restore_reg_data_1): When a reg is an address, do mark_reg_pointer. + + * dbxout.c (dbxout_types): Call dbxout_symbol to do the work. + (dbxout_type_def): Deleted. + (dbxout_symbol): Set TREE_ASM_WRITTEN when a TYPE_DECL is output. + Don't output the same one twice. + + * cse.c (fold_cc0): LABEL_REF is not zero. + + * cse.c (cse_insn): Don't insert src, dest if they are the same place. + + * cse.c (lookup_as_function): Return entire rtx, not just operand. + (cse_insn): Caller changed. Also, copy the result before inserting it. + + * cse.c (fold_rtx): Put constant arg last if commutative op. + Handle idempotents and identities for mult, div, booleans, shifts. + + * cse.c (canon_hash): Parens were missing around shifts in "rotates". + + * c-convert.c (convert_to_integer): Truncate TRUTH_ANDIF_EXPR + like TRUTH_AND_EXPR; OR also. + + * c-typeck.c (build_binary_op_nodefault): Do truthvalue_conversion + for TRUTH_ANDIF, etc. + (build_unary_op): More simplifications for TRUTH_NOT_EXPR; + uses new fn `invert_truthvalue'. + + * recog.c (reg_fits_class_p): New name for reg_renumbered_fits_class_p + since it no longer needs to renumber. Also it now really assumes + arg is a REG. Callers changed. + * reload.c: Callers changed. + + * recog.c (general_operand): (SUBREG (MEM...)) need not alter mode. + (register_operand, nonmemory_operand): (SUBREG (MEM...)) is allowed. + (memory_operand): (SUBREG (MEM...)) is *not* allowed. + (mode_independent_operand): Operand names were backwards! + (No change in effect of this function.) + + * print-tree.c (dump): Some expr nodes contain rtx's. Print as rtx's. + +Wed Sep 28 18:51:12 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * reload1.c (choose_reload_targets): If a reload wanted a group, + don't allow a single register for it. + +Tue Sep 27 11:43:56 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * final.c (output_addr_const): Handle DImode CONST_DOUBLEs. + * tm-*.h (PRINT_OPERAND): Treat DImode CONST_DOUBLE like a CONST_INT. + + * vax.md (rotldi3): Insn deleted; it doesn't really exist. + + * toplev.c (report_error_function): Also mention the file name, + for parallel makes. New arg FILE; all callers changed. + +Mon Sep 26 15:44:18 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * expmed.c (expand_shift): When using extzv, convert OP1 to SImode. + * c-typeck.c (build_binary_op_nodefault): Convert shift-count + to int regardless of result type. + + * output-spur.c (output_move_double): Fix typo, optype0=>optype1. + + * expr.c (expand_call): Avoid null deref on result of FUNCTION_ARG. + + * tm-i386.h (FUNCTION_PROFILER): Use correct assembler syntax. + +Sun Sep 25 12:13:56 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * fixincludes: Handle some files in netdnet, netdna, vaxif, vaxuba. + + * reload.c (find_reloads): Make no optional reloads if not -O. + + * loop.c (strength_reduce): Can't eliminate a biv if it's used + to compute a DEST_ADDR giv. Only DEST_REG givs are safe. + + * loop.c (general_induction_var): Shift & divide ops are linear + only in 1st operand; don't look for biv or giv in 2nd operand. + + * vax.md (fix_truncdfqi2): Use `%#'. + +Sat Sep 24 00:25:48 1988 Richard Stallman (rms at gluteus.ai.mit.edu) + + * loop.c (n_times_set, n_times_used): Now file-scope; + no longer passed as args to several functions. + + * loop.c (basic_induction_var): Accept reg as source value + only if it's invariant. + (strength_reduce): Benefit calculation and threshold changed. + Check reducibility of givs before trying to reduce them. + Check eliminability of biv before considering the givs; + let this affect the threshold. + (record_giv): New subroutine adds a giv to the chain. + + * ns32k.md (incrementing sp): Use cmpd insns to increment by 4 or 8. + + * integrate.c (expand_inline_function): Rename return_label + to local_return_label; avoid shadowing. + +Fri Sep 23 13:57:52 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * loop.c (loop_skip_over): Put the new label after the note that ends + the loop. + + * loop.c: New function strength_reduce and subroutines. + * toplev.c: New var flag_strength_reduce, set from -fstrength-reduce. + + * vax.md (sob insns): They were broken, with plus in one place + and minus in another. Use plus consistently. + + * rtl.h (REG_LIBCALL, REG_NONNEG): Two new kinds of reg-note. + * optabs.c (expand_binop, expand_unop): Make REG_LIBCALL notes. + * loop.c (scan_loop, move_movables): Move entire library calls. + Use m->set_src to get the expression, in case it's from a REG_EQUAL. + (consec_sets_invariant_p): Likewise. + + * loop.c (scan_loop): Start scan from loop_top, if entry is rearranged. + Watch out for pseudo regs created by strength_reduce; + they can't index regno_last_uid. + (replace_regs): # regs mapped is now an arg. + + * loop.c (count_loop_regs_set): Don't increment n_times_set past 127. + (consec_sets_invariant_p): Reject if N_SETS arg is 127. + + * toplev.c (rest_of_compilation): NREGS arg of loop_optimize deleted. + + * c-decl.c (store_parm_decls): Anything but an IDENTIFIER_NODE + in SPECPARMS indicates a parmlist, not an identifier list. + (get_parm_info): Use only PARM_DECLs when making the list of arg types. + + * combine.c (try_distrib): Boolean ops can't distribute through PLUS. + MULT can distribute through PLUS and only PLUS. + +Thu Sep 22 15:57:41 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * jump.c (jump_optimize): uncond jump to a return becomes a return. + + * integrate.c (copy_parm_decls, copy_decl_tree): Set TREE_USED. + Avoid inevitable "unused" warning for these decls. + + * c-typeck.c (comptypes): When comparing array types, + ignore qualifiers of element type. + + * tm-*.h (ASM_OUTPUT_REG_PUSH, ASM_OUTPUT_REG_POP): Define new macros. + * final.c (final_start_function): Use them to protect around + the call to the profiling function. + * stmt.c (expand_function_start): Set current_function_needs_context + and current_function_returns_struct. + + * stmt.c (expand_null_return_1): If clear_pending_stack_adjust + doesn't clear it, do the adjust now. + * expr.c (clear_pending_stack_adjust): No-op if -finline-functions. + + * cccp.c (macarg1, skip_if_group): Backslash makes next char ordinary. + + * reload.c (find_reloads): Delete code to look for an equiv reg + for a reg being input-reloaded. This isn't safe. + * reload1.c (choose_reload_targets): Do it here. + +Wed Sep 21 00:36:22 1988 Richard Stallman (rms at hobbes.ai.mit.edu) + + * tm-sun3.h (CPP_SPEC): Define it based on TARGET_DEFAULT. + (STARTFILE_SPEC): Likewise. + + * reload1.c (choose_reload_targets): When redirecting prev insn + into this insn's reload-reg, check this doesn't break the prev insn + by giving it a reg it can't accept. Use new fn constraint_all_regs_p. + + * tm-sparc.h (ASM_OUTPUT_LOCAL): Use .reserve, not .common. + + * tree.h (TREE_USED): New attribute macro. + * c-parse.y (primary): Set TREE_USED in ..._DECL nodes. + * toplev.c, flags.h: Define and set warn_unused. + * stmt.c (expand_end_bindings): Warn if any var is unused. + * print-tree.c (prtypeinfo): Print this attribute. + +Tue Sep 20 15:29:01 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * assert.h: `assert' must expand to an expression. + Error message should show arg before expansion, not after. + + * c-decl.c (implicitly_declare): Make decl perm if !warn_implicit + since start_function needs to look inside it in that case. + + * toplev.c (announce_function): If we don't print, don't record we did. + +Mon Sep 19 15:21:11 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * c-parse.y (structsp): If pedantic, warn if comma at end of enumlist. + + * reload.c (find_reloads): Check insn_code_number >= 0 when + looking in insn_operand_strict_low. + + * tm-sun[23].h (CPP_SPEC): Rename __HAVE_FPU__ to __HAVE_68881__ + and put a space after that option. + +Sun Sep 18 01:12:56 1988 Richard Stallman (rms at hobbes.ai.mit.edu) + + * reload.c (find_reloads): Make optional reloads for explicit MEMs. + + * tm-m68k.h (MODES_TIEABLE_P): If no 68881, can tie fixed to floating. + * m68k.md (movdi): Allow F's (can be DImode now). + Don't allow f-regs (experiment). Don't preference x-regs. + (DImode push): Allow y-regs. + (DFmode push): Allow y-regs, not x-regs. + + * reload1.c (modes_equiv_for_class_p): New function. + (reload): Compare multiple modes for reg group with that function. + Allows differing modes in some cases when not tieable. + + * c-parse.y (check_newline): Let ASM_OUTPUT_IDENT override .ident. + * tm-3b1.h (ASM_OUTPUT_IDENT): Define this as no-op. + + * emit-rtl.c (reorder_insns): Update sequence_{first,last}_insn if nec. + (get_last_insn): If in a sequence, return last insn of sequence. + (delete_insns_since): If in a sequence, set sequence_last_insn. + + * spur.md (CONST_DOUBLE load insn): Use & for most dests. + (cond branches): pass additional args to output_compare. + (movdf, movdi): Use & loading reg from mem. + (trunc*): Enable these. + (add): New pattern for adding large immediate operand. + (shifts): A define_expand for each kind of shift, + plus a recognizer which outputs repeated insns if necessary. + (call*): Use r9 as temp, not r2. + + * output-spur.c (output_compare): New args NEG_{EXCHANGE_,}OPCODE. + (singlemove_string): Handle reg as operand 1. + (output_add_large_offset): Fake add insn with large immediate arg. + (big_immediate_operand): Match such an arg. + + * tm-spur.h (FUNCTION_PROLOGUE): Align the stack pointer. + Handle bigger frames. + (TARGET_LONG_JUMP, TARGET_EXPAND_SHIFT): New target flags. + + * va-spur.h: Track position in regs and stack separately. + + * c-decl.c (duplicate_decls): Warn if prototype follows + non-prototype definition. + +Sat Sep 17 14:30:23 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * expr.c (expand_builtin): Avoid crash if arg isn't integer type. + + * c-decl.c (duplicate_decls): Just warn if redeclaring a builtin, + and leave it built in unless it is redefined. + + * vax.md (ashlsi3): Use addl3, moval or movad when useful. + (addsi3): Avoid pushab, movab for constants < 64. + Do use movab when > 64 when operands match. + (mov*i): Use mcom* rather than mneg*. + Use add*3 with two quick immediate args when useful. + (movhi): Don't use movzbw or cvtbw; said to be slow. + + * rtl.h: New macros MEM_VOLATILE_P, MEM_IN_STRUCT_P, + INSN_DELETED_P, REG_USER_VAR_P, RTX_UNCHANGING_P, RTX_INTEGRATED_P, + CONSTANT_POOL_ADDRESS_P. + Most places changed to use them. + +Fri Sep 16 11:50:15 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * jump.c (jump_optimize): Was testing volatil on non-MEMs erroneously + when looking for no-op move insns. + + * cccp.c (handle_directive): Ignore comments between # and directive. + + * integrate.c (copy_rtx_and_substitute): Stack-push memrefs need + to be copied. + + * tm-bsd386.h (ASM_OUTPUT_DOUBLE): Undef previous def. + + * reload1.c (alter_reg): Don't reuse spill_stack_slot + if it isn't big enough for this reg's mode. + + * expr.c (emit_move_insn): After force_const_mem, ensure + mem address is valid. + (move_block_to_reg, move_block_from_reg): Likewise. + + * expr.c (expand_call): Spurious TREE_VALUE on args[i].tree_value. + + * m68k.md (zero_extend*): Require register_operand for operand 0. + + * stdarg.h (va_start): Alternate defn for sparc. + +Thu Sep 15 11:39:06 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * c-parse.y (yylex): When atof gives ERANGE, check for "0.0", etc. + + * assert.h (__assert): Alternative definition for -traditional. + + * output-sparc.c (output_block_move): Initialize xoperands. + + * combine.c (try_combine): Never subst for a reg that is incremented. + + * m68k.md (cmpm pattern): Make the match_operands match memrefs + and check that they are pushes in the extra condition. + This makes reloading handle the pushes properly. + + * expr.c (MOVE_RATIO): Make it 15. Allow overriding it. + +Wed Sep 14 09:50:08 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * c-decl.c (build_enumerator): Use saveable_tree_cons. + + * vax.md (movdf): Use movq when safe. + + * Version 1.28 released. + + * tm-sparc.h (FIRST_PARM_CALLER_OFFSET): Defined. + +Tue Sep 13 00:11:37 1988 Richard Stallman (rms at corn-chex.ai.mit.edu) + + * tree.c (saveable_tree_cons): New function. + * c-decl.c (pushtag): Use it; lists of tags needed for inlining. + (get_parm_info): Likewise. + + * print-tree.c (dump): Handle each kind of statement node individually. + + * integrate.c (copy_decl_tree): Don't pass DECL_RTL through + copy_rtx_and_substitute if it's a memref with constant address. + + * sdbout.c (sdbout_symbol): Don't output garbage when DECL_RTL + has a form we don't understand. + + * reload.c (find_reloads_address_1): Don't reload an autoincrement + if it has a suitable hard reg already. + + * c-typeck.c (process_init_constructor): Error check after digest_init. + + * c-parse.y (is_reserved_word): Now static. + +Mon Sep 12 19:19:28 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * i386.md (all push insns): Use `<' for the constraint, + since a push_operand won't fit an `m' constraint on this machine. + + * expr.c (expand_call): If fn name is `__builtin_alloca', + it may be alloca. This case arises if the user redeclares + `__builtin_alloca'. + +Sun Sep 11 01:47:01 1988 Richard Stallman (rms at gluteus.ai.mit.edu) + + * Eliminate MAX_SETS_PER_INSN. + * cse.c (cse_insn): Combine all the tables and dynamically allocate. + (cse_main): Count the actual number of SETs; don't estimate. + * genconfig.c: Don't calculate MAX_SETS_PER_INSN. + * stmt.c (expand_asm_operands): No limit on # of output operands. + + * expr.c (expand_call): + Store all non-reg parms first, then store all partially-in-reg + parms, then all the (precomputed) wholly-in-reg parms. + Special hair for BLKmode parms which must be passed entirely + in memory; also for BLKmode parms initialized from function calls, + for which it is best to allocate the space before computing value. + Use macro FIRST_PARM_CALLER_OFFSET to handle machines where reg + parms "take up space" on the stack below the stack pointer. + (store_one_arg): Handle case of preallocated stack loc for BLKmode. + Update current_args_size here, not in caller. + +Sat Sep 10 19:58:03 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * output-sparc.c (output_scc_insn): Changed asm templates. + Use common code to emit the move insns and label at the end of fn. + (output_mul_by_constant): Use %g1 as temporary reg. + + * sparc.md (indexed load pattern): Deleted. + (fix_truncdfsi2): Don't ignore value of output_fp_move_double. + (cse'd multiply): Operand 1 predicate is general_operand. + (return peepholes): Conditionalize on ! TARGET_EPILOGUE. + + * tm-sparc.h (INIT_CUMULATIVE_ARGS,FUNCTION_ARG...): + Use partial regs for args that start in regs but won't entirely fit. + + * tm-sparc.h (CONST_COSTS): 0 for args that can be immediate. + (STRUCTURE_SIZE_BOUNDARY): Now 8. + (STRUCT_VALUE_OFFSET): Defined as symbolic name for `64'. + + * expr.c (struct arg_data): New component `stack' says where in the + stack to put a BLKmode arg (if it's nonzero). + (store_one_arg): Handle case where it's nonzero. + (target_for_arg): New fn, precompute stack locn for BLKmode arg. + +Fri Sep 9 01:41:13 1988 Richard Stallman (rms at corn-chex.ai.mit.edu) + + * cse.c (fold_rtx): Misnested ifs screwed SUBREG case. + + * reload.c (find_reloads_toplev): Special case for (SUBREG REG) + where REG is equivalent to a CONST_INT. + (find_reloads): Don't ignore the value returned by find_reloads_toplev. + Treat a (SUBREG constant) like a (SUBREG MEM): set force_reload. + + * reload.c (push_reload): Abort if memory subreg is not + paradoxical; the MEM mode should be narrower than the SUBREG. + + * stmt.c (fixup_var_ref_1): Fixup memory subregs in an insn + copying VAR to or from a register. + + * m68k.md (movdi, movdf): the x-reg constraint accidentally allowed + moving rm to rm with no &. + + * vax.md (call_value): Typo. + + * expr.c (emit_block_move, emit_push_insn): prefer movstrqi to movstrsi + + * m68k.md (FPA multiply): bad opcodes for 3-operand multiply insns. + +Thu Sep 8 18:22:14 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * c-parse.y: Use YYERROR instead of synonym YYFAIL. + BISON VERSIONS PRIOR TO THIS DATE WON'T WORK! + + * c-typeck.c (digest_init): Use TYPE_MAIN_VARIANT of array elt type. + + * tm-sun[23].h (CPP_SPEC, ASM_SPEC): Let -m(c|)680[12]0 control + options for CPP and assembler. + +Wed Sep 7 13:44:59 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * New handling of reloading of PRE_DEC, etc. + Now reload_in is the PRE_DEC, etc, and reload_inc is always positive. + * reload.c (push_reloads): Old code to set reload_inc deleted. + (find_reloads_address_1): Call push_reload the new way. + (find_inc_amount): Value always positive. + * reload1.c (choose_reload_targets): Detect this case. + (inc_for_reload): New fn; does the real work for this case. + * m68k.md (call, call_value): Fn address must be offsetable. + + * combine.c (try_distrib): Reject strange cases such as if + result of PREV1 or PREV2 is used in a memory address in INSN. + + * vax.md (movsf): Generate movl instead of movf. + + * expr.c (expand_call): If have regparms, store all BLKmode args + before all the other args. + (store_one_arg): New subroutine broken out. + + * output-sparc.c (output_block_move): Complete rewrite. + + * sparc.md (cse'd multiply insn): Typo in asm-output code. + +Tue Sep 6 20:05:48 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * c-parse.y (yylex, etc.) Install Schmidt's perfect hash table. + + * gcc.c: handle extension `.cc'. + +Mon Sep 5 12:09:58 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * Version 1.27 released. + + * tm-i386.h (PREFERRED_RELOAD_REG): When reloading a QImode, + make sure the class doesn't include %esi or %edi. + * i386.md (movqi): Eliminate only use of the class `x', + for which PREFERRED_RELOAD_REG cannot work. + (In next version, get rid of INDEX_CLASS). + Also use `*' to cause preferencing of Q_REGS. + * tm-m68k.h (PREFERRED_RELOAD_REG): When reloading a QImode, + use DATA_REGS. + + * reload.c (push_reloads): Braino in last change when IN == 0. + + * flow.c (mark_used_regs, mark_set_1): Bug if HARD_REGNO_NREGS + returns 0 for VOIDmode reg (inside a CLOBBER). + + * c-parse.y (asm_operand): Handle `("REGNAME")' as an operand. + * recog.c (decode_asm_operands, asm_noperands): Ignore any CLOBBERs. + * regclass.c (reg_names): Variable now global. + * stmt.c (expand_asm_operands): Generate CLOBBERS when appropriate. + + * stmt.c (assign_parms): Ignore parms that aren't PARM_DECLs. + + * varasm.c (assemble_variable): Do ASM_OUTPUT_EXTERNAL for functions. + + * c-parse.y (yylex): floatflag is now an enum. + Detect invalid use of decimal points (> 1, or in exponent) + and multiple exponent letters. + + * expr.c (expand_call): If inlining fails, set TREE_ADDRESSABLE. + +Sun Sep 4 00:36:30 1988 Richard Stallman (rms at corn-chex.ai.mit.edu) + + * c-decl.c (grokdeclarator): A const array becomes an array of consts. + * c-typeck.c (build_array_ref): Array ref is const if array elts are. + + * output-sparc.c (output_move_double): Change criteria for ldd, std. + (output_fp_move_double): New alternatives avoid ldd, std for + stack refs that aren't aligned. + (output_block_move): Use %g1 as temp reg. + + * sparc.md (floating point load from constant mem address): + Use %g1 as temp reg. Use output_move_double in DF case, not ldd. + (movsf): Asm insn typo in FPreg to FPreg case. + (floatsi{s,d}f2): Constraint changed. + Also new special case pattern in front of it. + (fix_truncdfsi2): Use output_move_double, not ldd. + (addsi3, subsi3): Use %g1 as temp reg. + (cse-optimized multiply): Constraint now `g'; output generalized. + (andsi3, orsi3, xorsi3): Use %g1 as temp reg. + + * reload.c (find_reloads): Force int constants into memory just + like floating ones, if memory is allowed and no regs are. + + * expr.c (expand_call): Don't treat structure_value_addr like a parm + if the first parm would be passed in a register. + Also, write comments for all local vars. + + * tm-386v.h (START_SPEC): Use {g,m}crt1.o, not {g,m}crt0.o. + (LIB_SPEC): Always use crtn.o. + +Sat Sep 3 13:05:50 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * explow.c (plus_constant): Don't put CONST around lone SYMBOL_REF. + + * combine.c (subst): Simplify zero- or sign-extend of a constant. + + * expr.c (expand_expr): for REAL_CST, etc., check for invalid + memory addresses and copy into registers. + + * integrate.c (expand_inline_function): If incoming struct value addr + is in memory, map it like a memory parameter. + + * tm-*.h (FIRST_PARM_OFFSET): Now takes fndecl as argument. + * integrate.c (expand_inline_function): Calc., use and save + this fns value of FIRST_PARM_OFFSET. + (copy_rtx_and_substitute): Use that value. + * stmt.c (assign_parms): Likewise. + + * tm-sparc.h (FIRST_PARM_OFFSET): Make it 64 if value is BLKmode. + (STRUCT_VALUE{,_INCOMING}): Put the value in 64(fp). + + * tm-sparc.h (PRINT_OPERAND_ADDRESS): Print offsets in decimal. + Avoid excess `+' before a negative offset. + + * stmt.c (expand_function_start): Create the return value rtl + before making the tail-recursion loop point. + + * combine.c (gen_lowpart_for_combine): Generate a paradoxical subreg + rather than a wider memref. + + * reload.c (push_reload): Extend last change to case where OUT != 0. + +Fri Sep 2 11:43:20 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * stmt.c (fixup_var_refs): Adjust last_parm_insn when deleting insns. + + * expr.c (emit_push_insn): calling memcpy, bump TEMP 2 pointers worth. + +Thu Sep 1 16:39:57 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * reload1.c (choose_reload_targets): Test for canceled reload + before looking inside reload_out. + + * jump.c (jump_optimize): Bug in last change. + + * m68k.md (return): Pattern disabled; confuses Aug 29 stmt.c change. + * ns32k.md, i386.md: likewise. + + * emit-rtl.c (emit_note_force): New, like emit_note but always do it. + * stmt.c (expand_function_end): Use emit_note_force. + +Wed Aug 31 11:34:08 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * reload1.c (alter_reg): New arg FROM_REG is hard reg that the pseudo + was spilled from. Works with spill_stack_slot. Callers changed. + Now all pseudos spilled from one hard reg get the same slot. + (reload): Initialize new variable spill_stack_slot. + + * cse.c (cse_insn): Don't insert floating point mems if -ffloat-store. + + * reload.c (find_equiv_reg): Allow no equivs for volatile memrefs. + Also none for floating mem refs if -ffloat-store. + + * output-sparc.c (output_mul_by_constant): make `p' and `log' unsigned. + +Tue Aug 30 13:47:12 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * jump.c (jump_optimize): Ignore other NOTEs while looking for + a NOTE_INSN_FUNCTION_END. + + * integrate.c (save_for_inline): Flush extra call to max_reg_num. + Don't copy NOTEs that are NOTE_INSN_FUNCTION_END. + (copy_for_inline): Don't copy NOTEs that are NOTE_INSN_FUNCTION_END. + + * stmt.c (optimize_bit_field): If bit field is SRC, strip subregs + from the DEST. + + * expmed.c (expand_mult): Special case for -1 as one operand. + +Mon Aug 29 12:14:51 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * stmt.c (expand_goto_internal, expand_fixup): New arg LAST_INSN. + (expand_return): Pass that arg in tail-recursive case. + (other callers): Pass 0 for that arg. + (expand_null_return): Handle HAVE_return nonzero w/ FUNCTION_EPILOGUE. + (expand_null_return_1): New fn, has guts of old expand_null_return. + (expand_return): Call expand_null_return_1 to pass LAST_INSN arg. + (expand_return): Handle HAVE_return nonzero w/ FUNCTION_EPILOGUE. + (expand_function_{start,end}): Likewise. + (expand_cleanups): Fix typo in recursive-list case. + (move_cleanups_up): New fn. + + * expr.c (expand_call): Execute cleanups_of_this_call on exiting. + Notice calls to __builtin_new (but don't do anything about them yet). + + * reload.c (push_reload): If reloading a (SUBREG (MEM ...) ...), + really reload just the MEM in the MEM's own mode. + + * sparc.md: Define patterns for insns that set the ccs. + Define set-flag insns. + New patterns for indexed load, and for optimizing signed bit fields. + (mulsi3, umulsi3): Give "r" constraint to operand 0. + Peephole optimizers recognize some cases where delay insns are safe. + Changed patterns for call and return insns as well. + + * output-sparc.c (single_insn_src_p): New fn. + (output_delay_insn): New fn. + + * tm-sparc.h (TARGET_EPILOGUE): New target flag. + (NOTICE_UPDATE_CC): New clause for funny PARALLEL with a REG in it. + + * m68k.md (movqi): Use *'s to ensure preferencing d-regs. + + * c-parse.y (datadef): If traditional, no warning about no specs. + +Sun Aug 28 14:34:33 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * tm-i386.h: Define PROMOTE_PROTOTYPES. + POINTER_BOUNDARY now 32. + + * regclass.c (reg_scan): Compute `max_parallel', max # of sets and + clobbers in any insn in this function. + * global-alloc.c (global_conflicts): Use that, not MAX_SETS_PER_INSN. + + * stmt.c (expand_asm_operands): MAX_SETS_PER_INSN limits # output ops. + + * emit-rtl.c (init_emit_once): Make elt 2 of {f,d}const0_rtx nonzero. + + * c-decl.c (lang_decode_option): Handle -Wwrite-string. + * c-parse.y (combine_strings): If that flag, make array of const char. + + * expr.c (expand_expr): for INTEGER_CST, always use immed_double_const; + never do output_constant_def (it didn't work). + Also heed WORDS_BIG_ENDIAN. + + * varasm.c (output_constant): Handle integer CONST_DOUBLEs. + (output_constant_def): Abort if arg is an INTEGER_CST. + + * emit-rtl.c (gen_rtx): Don't return {f,d}const0_rtx for DImode. + +Sat Aug 27 12:37:23 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * c-decl.c (pushdecl): Global extern decls set TREE_PUBLIC + like local ones. + + * integrate.c (expand_inline_function): Handle parms that were + passed in registers but whose homes are on the stack. + + * varasm.c (force_const_mem): Output ints according to spec'd mode. + ({record,compare}_constant_rtx,const_hash_rtx,decode_rtx_const): + Take mode as argument; pass it along. + + * c-parse.y (read_escape): No warning for `\{' or `\['. + +Fri Aug 26 12:23:07 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * stmt.c (fixup_memory_subreg): Typo calculating big-endian adjust. + + * vax.md (call_value): Handle >255 args as in `call'. + +Thu Aug 25 16:00:51 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * jump.c (delete_jump): Don't delete the cc-setter if it has autoinc. + +Wed Aug 24 16:33:37 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * expr.c (expand_expr): For sun with a COND_EXPR, use SUBTARGET + if validate_subtarget says ok. + + * tree.c (build_index_type): make_index_type moved here and renamed. + + * combine.c (move_deaths_2): New function. + (try_distrib): Use that, not move_deaths. + + * tm-sparc.h (SHIFT_COUNT_TRUNCATED, STORE_FLAG_VALUE): Define them. + + * tm-sparc.h: FUNCTION_{PRO,EPI}LOGUE: Save room for ins and + locals to spill to the frame if any ins *or* locals are live. + + * tm-sparc.h (NOTICE_UPDATE_CC): Delete the clause that always + cleared the cc's for unrecognized insns. + + * reload1.c (reload_as_needed): Don't try to use a spill-reg + in a basic block that wasn't spilled: ignore optional reloads. + +Tue Aug 23 09:45:05 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * output-sparc.c (output_scc_insn): New function. + + * expr.c (expand_builtin, alloca): Round result of alloca + up to a multiple of STACK_BYTES. + + * toplev.c (compile_file): Default main_input_filename is cc1 input. + + * tm-i386.h (FUNCTION_BOUNDARY): 32 avoids extra prefetch. + + * i386.md (movdi, movdf): Add `&' where needed in constraints. + +Mon Aug 22 11:57:51 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * symout.c (symout_finish): Allocate typevector after the symout_types. + +Sun Aug 21 16:10:54 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * tm-3b1.h (ASM_FORMAT_PRIVATE_NAME): Use a `_' as well as `%'. + + * expr.c (expand_expr): Typo setting MODE for MAX_EXPR. + + * Makefile (stage*): If ln fails, copy gnulib to stage*. + (realclean): Do `clean' and then some. + (install): new var USER_H specifies headers to copy. + + * c-typeck.c (build_binary_op_nodefault): LT_EXPR, etc. + on ptr vs int failed to set result_type. + (build_conditional_expr): Don't replace nonzero int + with null_pointer_node. + + * combine.c (remove_links, try_distrib): New fns. + (subst): New simplifications for ZERO_EXTEND, SIGN_EXTEND. + (combine_instructions): Call try_distrib. + (FAKE_EXTEND_SAFE_P): Allow SUBREGs. + + * m68k.md (non-FPA pattern for floatsisf2): Typo, had DF for SF. + +Sat Aug 20 12:04:37 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * integrate.c (copy_address): Variant of copy_rtx_and_substitute. + (copy_rtx_and_substitute): Use copy_address for MEM address that + doesn't satisfy memory_address_p. + + * reload.c (find_reloads): If force_reload set, don't set WIN + for a MEM even if `m', `o' or `g' in constraint. + + * i386.md (expendqihi2): Typo in asm template. + + * toplev.c (rest_of_compilation): Call clear_const_double_mem. + * varasm.c (init_const_rtx_hash_table): Don't call it here. + (immed_real_const): Don't record the rtx in the REAL_CST node. + (force_const_double_mem, clear_const_double_mem): Use cc0_rtx, not 0, + as flag for a CONST_DOUBLE not on the chain. + + * cccp.c (handle_directive): If traditional, do scan strings + but accept unterminated ones. + (collect_expansion): -traditional: Don't recognize comments in strings. + Stringify arguments that appear within strings. + (skip_quoted_string): -traditional: Always exit at newline. + (macroexpand): -traditional: Don't put `"'s around stringified arg. + (macarg): Set stringified_length accordingly. + + * c-decl.c (duplicate_decls): Avoid error redeclaring fcn after + implicit decl if -traditional. + + * toplev.c (announce_function, report_error_function): + Change communication logic between these fcns. + + * c-decl.c (lang_decode_options): Handle -Wall here. + * toplev.c (main): not here. + + * tm-bsd386.h: Don't include tm-i386.h--be like tm-att386.h + +Fri Aug 19 11:08:36 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * config-sun4.h: If sparc, include config-sparc.h. + Never include alloca.h. + + * tm-m68k.h (TARGET_SWITCHES): Define `-mc68020', `-mc68000'. + + * c-decl.c (init_decl_processing): If traditional, use signed sizetype. + + * gcc.c (main): Use stderr for printing version. + +Thu Aug 18 14:42:36 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * Version 1.26 released. + + * m68k.md (movsi): Constraint change for fpa regs. + + * reload1.c (choose_reload_targets): Clear reg_reloaded_contents + for all regs of a multi-reg group. + + * reload.c (find_equiv_reg): HARD_REGNO_NREGS wants mode, not size. + Check properly for overlap against multiword reload regs. + +Tue Aug 16 14:54:18 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * varasm.c, expr.c (immed_double_const): immed_real_const_2 renamed. + + * tm-i386.h (SFVALUE): Should be `double'. + * tm-i386v.h (SFVALUE): Don't override it. + + * tm-i386.h (ASM_OUTPUT_ASCII): Don't define it. + * tm-att386.h: Definition moved here. + + * tm-bsd386.h: New file, for Sequent. + * tm-seq386.h: New file, for Sequent. + * config-i386.h: New file, for Sequent. + + * expr.c (push_block): Take account of STACK_POINTER_OFFSET. + (expand_call): Therefore need not do so here. + + * optabs.c (expand_fix): Typo if going via DImode. + + * reload1.c (choose_reload_targets): Don't * reload_reg_rtx if 0. + +Mon Aug 15 01:11:49 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * integrate.c (copy_for_inline): Don't try copying 0-length vector. + (copy_rtx_and_substitute): Likewise. + + * m68k.md (andsi3): use clrw instead of andw #0. + + * print-tree.c (walk): Don't omit permanent nodes reach from temps. + + * m68k.md (zero_extend...): Reinstall the old zero-extend insns + without names, so they can help the combiner. + + * expr.c (expand_expr): Don't use hard regs as subtargets. + * combine.c (FAKE_EXTEND_SAFE_P): Always consider MEMs safe. + * reload.c (find_reloads): For (SUBREG (MEM ...)) set force_reload. + + * c-parse.y (redescape): Don't warn for `\('. + + * reload.c (find_reloads_address): #if was backwards. + +Sun Aug 14 16:52:22 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * c-typeck.c (shorten_compare): Change switch to chain of ifs. + + * tm-ns32k.h (PRINT_OPERAND): CONST_DOUBLE contains a double + even if it's SFmode. + (FUNCTION_PROLOGUE): If MAIN_FUNCTION_PROLOGUE defined, run it. + + * cccp.c (file_buf): Rename field `free' to `free_ptr'. + + * Makefile (ALLOCA, MALLOC, LIBDEPS): New variables for easier + customization. Executables depend on LIBDEPS instead of OBSTACK1. + (cccp): Deps and libs now work like the others. + + * output-i386.c (notice_update_cc): Rewritten for clarity. + + * tm-i386.h (OUTPUT_JUMP): If CC_IN_OVERFLOW, abort. + + * recog.c (push_operand): Test for stack_pointer_rtx. + + * integrate.c (copy_rtx_and_substitute): Don't submit push-operands + to `memory_address'--it would lose on machines where pushing is + a special insn, not an addressing mode. + + * output-i386.c (top_dead_p): No more redundancy--that didn't work. + Now one method if optimized, one for call_insns if noopt, one for + other insns if noopt. + (call_top_dead_p): fp_top_dead_p renamed + and only the call-insn clause remains. + + * i386.md (cmpsf, cmpdf): Output was backwards. + (", tstsf, tstdf): Set CC_IN_80387. + (incb pattern): Restrict allowable registers. + (movsf, movdf): Call top_dead_p only when absolutely necessary. + (call_value): Use top_dead_p, not subroutine. + +Sat Aug 13 15:19:23 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * stupid.c (stupid_life_analysis): If only 1 reg class, + call stupid_find_reg only once. + + * stmt.c (expand_function_start): + Clear current_function_pretend_args_size. + + * expr.c (store_constructor): If target is hard reg, go via a pseudo. + + * varasm.c (real_constant_chain): Now static in this file. + (force_const_double_mem): Put R on chain if not already on. + (clear_const_double_mem): Set XEXP (,2) to 0; + also clear real_constant_chain and the chain links. + * emit-rtl.c (init_emit_once): Put 0 in XEXP (,2) of {d,f}const0_rtx. + * cse.c (canon_hash): For CONST_DOUBLE, ignore elts other than 0,1. + +Fri Aug 12 11:48:38 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * reload1.c (order_regs_for_reload): Handle REG_ALLOC_ORDER more spots. + + * global-alloc.c (find_reg): error handling REG_ALLOC_ORDER; + also error skipping regs known to be hopeless. + * local-alloc.c (find_free_reg): error skipping hopeless regs. + * stupid.c (stupid_find_reg): likewise. + + * local-alloc.c (qty_compare_1): typo, had q1 for q2. + + * expr.c (expand_expr): Don't use supplied target when optimizing + arithmetic using a comparison or conditional; that target could be + needed for the result of the comparison. + + * reload1.c (reload): Don't set reg_equiv_constant for hard regs. + + * stupid.c (stupid_life_analysis): Ignore reg R if regno_reg_rtx[R]==0. + + * symout.c (symout_finish): Use perm. links in permanent_fwd_refs. + + * i386.md (movhi, movqi): Check no_labels_between_p. + +Thu Aug 11 10:44:46 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * c-parse.y (yylex): Out-of-range float is just a warning. + + * tm-gnx-v3.h: New file for Genix. + * ns32k.md (movsi, call, call_value): GNX_V3 conditionals. + * tm-ns32k.h (PRINT_OPERAND_ADDRESS): Changes for Genix. + + * ns32k.md (insv patterns): Operand 0 is read-write. + + * i386.md (tstsf, tstdf): Don't push the arg if already in st(0). + + * varasm.c (output_constant_def): If EXP is permanent, the rtl is too. + + * tm-*.h (ASM_OUTPUT_{LOCAL,COMMON}): New 4th arg, rounded size + vs unrounded size. + * varasm.c (assemble_variable): Pass new arg. + * symout.c (symout_init): Likewise. + + * cccp.c (rescan): Don't let char const cross lines. + (skip_quoted_string, macarg1, discard_comments): Likewise. + + * expr.c (expand_expr, VAR_DECL case): handle flag_force_addr. + + * tm-i386v.h (TAREGT_DEFAULT): Assume 80387. + * config-i386v.h (alloca): Use __builtin_alloca under GNU C. + +Wed Aug 10 11:23:06 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * reload.c (find_reloads): Alternative loses + if it has no regs for a reg operand. + + * tm-sun3.h (STARTFILE_SPEC): Define, for fpa's sake. + * tm-m68k.h: New hard regs, reg classes, reg class letters, + target flag and switch, operand syntax and CC handling for fpa. + * m68k.md: Add fpa insn patterns. + * output-m68k.c (standard_SunFPA_constant_p): New fn. + (output_move_const_{single,double}): Handle fpa regs. + (singlemove_string): Handle fpa regs. + + * stmt.c (fixup_memory_subreg): Result had wrong mode. + + * ns32k.md (insv patterns): Adjust bit-number along with address. + + * sparc.md (negdf2, absdf2): Order of the words was backwards. + + * reload1.c (new_spill_reg): End confusion about meaning of 1st arg. + Arg counted_for_nongroups had wrong type. + + * tm-m68k.h (FUNCTION_{PRO,EPI}LOGUE): Round frame size to word bdry. + +Tue Aug 9 07:53:59 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * tm-i386.h (ASM_OUTPUT_ASCII): Don't lose the sign bit. + + * tm-i386v.h (STARTFILE_SPEC, LIB_SPEC): Use crt1.o, crtn.o. + + * stmt.c (fixup_var_refs_1): fixup all memory subregs. + + * reload1.c (choose_reload_targets): Don't strip paradoxical + subregs from values to be reloaded. + + * cccp.c: Comment out text after #endif. + + * c-parse.y (init): Allow empty braces as init; warn if pedantic. + + * c-decl.c: Move C-specific options from toplev.c. + * c-tree.h: Move their externs from flags.h. + * c-decl.c (lang_decode_option): New fn called by `main'. + * toplev.c (sorry, really_sorry): New error reporting fns. + * c-decl.c (language_string): New var, name of this language. + + * c-parse.y: Don't include flags.h. + * dbxout.c: Do include it. + + * dbxout.c (dbxout_type): Handle function fields and static fields + and basetypes. Handle METHOD_TYPE and REFERENCE_TYPE. + Abort on unexpected tree code. + (dbxout_args): New fn to output prototype arg types. + (everywhere): Use IDENTIFIER_LENGTH instead of strlen. + (dbxout_type_name): Cleanup; avoid strlen. + + * local-alloc.c (reg_is_set): Don't call {post_,}mark_life for pseudos. + + * tree.h (TYPE_BASECLASSES): New field in type nodes. + + * ns32k.md (insv patterns): Was adjusting the address wrong. + + * c-decl.c (grokdeclarator): Just a warning for inline varargs fn. + +Mon Aug 8 08:16:46 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * varasm.c (immed_real_const_2): Guts of creating a CONST_DOUBLE. + * expr.c (expand_expr): Use that for 64-bit int constants. + + * loop.c (invariant_p): Don't check x->unchanging; it's not safe. + + * c-typeck.c (build_indirect_ref): Handle flag_volatile here + so that it propagates to component_refs. + * expr.c (expand_expr): No need to handle it here. + + * integrate.c (save_for_inline, expand_inline_function): + Set up insn_map to record mapping of old uids to copied insns. + (copy_for_inline, copy_rtx_and_substitute): Map 'u' refs via insn_map. + + * emit-rtl (emit_label, emit_barrier): Return what was emitted. + + * sdbout.c (sdbout_filename): Split off from sdbout_init. + * tm-encore.h, tm-3b1.h, tm-vaxv.h, tm-att386.h (ASM_FILE_START): + Call sdbout_filename. + + * toplev.c: Better messages for invalid options. + + * tm-m68k.h (PRINT_OPERAND_ADDRESS): Handle labelref+basereg. + + * tm-3b1.h (PUT_SDB_DIM): Override sdbout's definition. + (ASM_FORMAT_PRIVATE_NAME): Override tm-hp...s definition. + (PUT_SDB_PLAIN_DEF): Prepend `~' to specified name. + (SDB_GENERATE_FAKE): Prepend `~'. + + * gcc.c: Include config.h before obstack.h. + +Sun Aug 7 11:17:56 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * stor-layout.c (layout_decl): Do nothing with CONST_DECL. + Treat FRIEND_DECLs like variables. + (layout_record): Handle VAR_DECLs and FUNCTION_DECLs in the fieldlist. + Handle basetypes (almost like fields). + (layout_type): Handle REFERENCE_TYPE and METHOD_TYPE. + + * tree.c (temp_tree_cons): New fn. + (array_type_nelts, simple_cst_equal): New fns. + (lvalue_p): CALL_EXPR is an lvalue if it returns REFERENCE_TYPE. + () Manage TYPE_REFERENCE_TO. + (TYPE_HASH_SIZE): Bigger. + (type_list_equal): Compare the TREE_PURPOSE fields. + (build_reference_type, build_method_type): New fns. + + * stmt.c (block_stack): Add field `cleanups' to each element. + (expand_{start,end}_bindings, expand_decl): Update that field. + (stack_block_stack): Now includes blocks that have cleanups. + (goto_fixup_chain): Add field `cleanup_list_list'. + (expand_goto_internal): Execute cleanups for blocks being exited. + (expand_fixup): Make a fixup if any block has cleanups. + (fixup_gotos): New args CLEANUPS and DONT_JUMP_IN. + Execute cleanups for blocks being exited, or add to cleanup_list_list. + (expand_end_bindings): New arg DONT_JUMP_IN. Execute any cleanups. + (expand_decl): New arg CLEANUP. + (expand_cleanups, fixup_cleanups): New functions. + * c-decl.c: Calls to expand_decl pass new arg. + * c-parse.y: Calls to expand_end_bindings pass new arg. + + * stmt.c (expand_return): Handle INIT_EXPR, or bare RESULT_DECL. + + * stmt.c (case_stack): Add field `has_default' to each element. + (pushcase,expand_end_case): Maintain and use that field. + + * stmt.c (pushcase): Handle RANGE_EXPR cases. + (pushcase_range): Create RANGE_EXPR cases. + + * final.c (final): Always pass 3 args to ASM_OUTPUT_CASE_END. + * tm-3b1.h: Delete offending spaces. + +Fri Aug 5 16:17:16 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * integrate.c (copy_rtx_and_substitute): Don't make fp+reg+const + without an intermediate temporary reg. + + * print-tree.c (dump): Don't print an identifier's chain. + + * toplev.c (compile_file): Treat `.i' suffix like `.co'. + + * gcc.c: New config macro CC1_SPEC: extra switches for cc1. + Make a new spec for `.i' files. + + * c-decl.c (pushdecl, finish_decl): Delete duplicate tests. + + * varargs.h: Maybe include va-sparc.h or va-spur.h. + * va-sparc.h: New file. + * va-spur.h: renamed file. + + * tree.h ({TYPE,DECL}_LANG_SPECIFIC): Types and decls can point to + language-specific structures containing other info. + * print-tree.c (dump): Hooks for printing the language-specific + data in types and decls. + +Thu Aug 4 08:54:30 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * tree.def: Add some tree codes for C++. + + * Rename files: parse.[yh] -> c-parse.[yh], decl.c -> c-decl.c, + typecheck.c -> c-typeck.c. + Part of tree.c split out to c-convert.c. + + * expr.c (push_block): No longer static. + (expand_expr): Handle REFERENCE_EXPR and INIT_EXPR. + (expand_call): Turn a METHOD_TYPE to a FUNCTION_TYPE. + This is probably not all that is required. + + * parse.y (yylex): Use p->rid to check for `signed' and `inline'. + + * tm-sparc.h (ASM_OUTPUT_SOURCE_LINE): typo. + + * sparc.md: Add a pattern for andcc. + (cmpsf): Clobber reg 32 in DFmode. + (branches): There are no unsigned floating branches; abort. + (bgt): Correct name of floating variant. + (mov?i): Load small constants via mov. + (movdf for constants): Use mov, not add, to move regs. + (movsf, floatsi*, fix*): Simplify reg-to-reg-via-mem move generation. + (trunc*): Use mov, not or, to move regs. + (negsi2, one_cmplsi2): Avoid "neg" and "not" assembler syntax. + (call...): Generate "call" insns; handle #-reg-parms value. + * Define some peepholes for return insns. + + * tm-sparc.h (TARGET_SUN_ASM): New target flag. + (TARGET_DEFAULT): Now 1. + (FRAME_POINTER_REQUIRED): Now 1. + (STARTING_FRAME_OFFSET): Now -16. + (LEGITIMATE_CONSTANT_P): Only CONST_DOUBLEs fail. + (FUNCTION_{PROLOGUE,EPILOGUE}): Rewritten. + + * output-sparc.c (small_int): Test for int that mov can load. + (singlemove_string): Use mov, not add. + (output_move_double): Changes for overlap and for use of ldd, std. + (output_fp_move_double): Use ldd, std when safe. + (make_f0_contain_0): Simplify. + + * integrate.c (expand_inline_function): Some special CALL_INSN + handling no longer needed due to REG_FUNCTION_VALUE_P. + + * m68k.md (movqi): Constraints allow moving areg to areg. + +Wed Aug 3 08:29:31 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * Version 1.25 released. + + * integrate.c (expand_inline_function): Don't let MEM be inline_target. + +Tue Aug 2 09:13:37 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * integrate.c (INTEGRATE_THRESHOLD): New macro, default dfn here. + (function_cannot_inline_p): Use it. + + * rtl.h (REG_FUNCTION_VALUE_P): New macro. + * stmt.c (expand_function_start): Set that flag in the return reg. + * integrate.c (expand_inline_function, copy_rtx_and_substitute): + Test that flag to test for the return value. + * expmed.c (expand_fixed_bit_field, expand_mult, expand_divmod): ditto. + FUNCTION_VALUE_OUTGOING_REGNO_P no longer needed. + +Mon Aug 1 02:46:08 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * integrate.c (copy_rtx_and_substitute): If NO_FUNCTION_CSE, + don't break out constant fcn addresses here. + + * expmed.c (expand_fixed_bit_field): Tests of FUNCTION_VALUE_REGNO_P + were backwards. + +Sun Jul 31 13:10:07 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu) + + * recog.c (indirect_operand): New function. + + * output-i386.c (print_operand): define %*. eliminate %s. + (fp_top_dead_p): In nonopt case, skip stack-adjusts while looking + for the insn that uses the function value. + + * varasm.c (text_section, data_section): New functions. + Replaced explicit printfs elsewhere with calls to them. + * final.c (final_start_function): Use these fns. + * sdbout.c (sdbout_one_type): Use text_section. + * tm-att386.h (ASM_OUTPUT_LOCAL): Use data_section. + + * expr.c (prepare_call_address): Don't pass const via reg if no -O. + + * tm-sparc.h (FUNCTION_{PROLOGUE,EPILOGUE}) Round the size of saved + registers. Fix bug counting saved registers. + + * tm-sparc.h (ASM_OUTPUT_SOURCE_LINE): Define this macro. + + * tm-sparc.h (DEFAULT_SIGNED_CHAR): Now 1. + + * expr.c (expand_builtin, alloca case): Adding stack offset needs + special code if TARGET is a MEM. + + * dbxout.c (dbxout_init): Define Ltext: after the reference to it. + + * tm-3b1.h (ASM_OUTPUT_CASE_LABEL): `short 0' triggers assembler bug; + `short L%nn-L%nn' supposedly works. + +Sat Jul 30 00:25:52 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * sparc.md (floatsidf2): Minor change in output. + (fix_trunc{sf,df}si2): Similar. + + * output-sparc.c (output_fp_move_double): Minor change in output. + + * stmt.c (assign_parms): Don't count stack space for struct value + address if the function does not have one. + + * sdbout.c: Output .dim's and total size for arrays. + Detect bit-fields properly. + Changed handling of structure tags. + + * reload1.c (new_spill_reg): counted_for_nongroups is a new arg; + store 1 in it if this reg is needed for max_nongroups. + + * reload1.c (choose_reload_targets): Allow inheritance of DFmode + if it needs only one register. + + * reload1.c (choose_reload_targets): Delete the death-note from the + store-insn of an inherited reload if PRESERVE_DEATH_INFO_REGNO_P. + + * reload.c (push_reload): Crash if PREFERRED_RELOAD_CLASS is NO_REGS. + (find_reloads): Smarter handling of forcing CONST_DOUBLE into mem. + Check PREFERRED_RELOAD_CLASS & do this if it says NO_REGS. + + * reload.c (subst_indexed_address): Handle case with 2 regs + and no constant term. + + * local-alloc.c: New variable qty_n_refs, set from reg_n_refs + and tested in qty_compare{,_1}. + (combine_regs): Update qty_n_refs. + Update qty_preferred_or_nothing more intelligently. + + * regclass.c (regclass, reg_class_record, record_address_regs): + Count the number of refs to each reg along with the costs, + and use it when computing the preferred_or_nothing flag. + (Can't use reg_n_refs since that is weighted by loop depth). + + * global-alloc.c (global_alloc): Enable test of OVERLAPPING_REGNO_P + for setting no_global_alloc_regs. + + * expr.c (prepare_call_address): Use force_reg, so it gets a REG_EQUIV. + + * optabs.c (can_{fix,float}_p): Return enum insn_code, not a function. + (init_{fix,float}_tab): Store enum insn_code's in fixtab and floattab. + (expand_{fix,float}): Change calls to can_{fix,float}_p. + Also, use emit_unop_insn to make the actual insns. + +Fri Jul 29 02:42:40 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * cccp.c (initialize_char_syntax): If dollars_in_identifiers is 0, + set entries for `$' to 0. + Set entries to 1 rather than incrementing them. + +Tue Jul 26 11:14:22 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * varasm.c (assemble_variable): Make SDB output only if top-level. + + * local-alloc.c (reg_is_set): Arg to mark_life is regno, not qty. + + * output-ns32k.c (print_operand_address): New flag SEQUENT_BASE_REGS + * tm-sequent.h: Define that flag. + + * Makefile: add some missing deps. + + * tm-encore.h (ASM_FILE_START): Changed to do nothing. + + * sdbout.c (sdbout_init): Fix two dumb errors. + + * sdbout.c (sdbout_end_epilogue): No longer takes arg. + Examine current_function_decl here, not in caller. + * final.c: Call changed. + +Mon Jul 25 01:32:54 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * stor-layout.c (layout_record): Handle PCC_BITFIELD_TYPE_MATTERS. + + * tm-3b1.h (__PTR_TO_INT, __INT_TO_PTR): Define these, to alter + parts of obstack.h. + +Sun Jul 24 17:56:53 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * Padding for an arg may now go below or above it; new macro + FUNCTION_ARG_PADDING can now choose which, or can inhibit padding. + This makes for compatibility with PCC. + * expr.h: Default definition of that macro. + * expr.c (emit_push_insn): Put the padding above or below. + (expand_call): Don't count the padding if none wanted. + * stmt.c (assign_parms): Adjust parm stack addr if padded below. + Don't count the padding if none wanted. + * tm-3b1.h: Define FUNCTION_ARG_PADDING: no padding for > 4 bytes. + + * final.c (alter_subreg): Now returns the altered value + (but may still modify the original structure). + Handles (SUBREG:DI (CONST_DOUBLE:DF...)) by returning the CONST_DOUBLE. + + * m68k.md (DImode push): now allows `F'. + * ns32k.md (movdi): now allows `F'. + + * tm-m68k.h (FIX_FRAME_POINTER_ADDRESS): + Handle indexed references to frame pointer. + * tm-i386.h, tm-m88k.h, tm-sparc.h: Likewise. + + * cse.c (predecide_loop_entry): Must search for the loop top label. + +Sat Jul 23 08:53:01 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu) + + * parse.y (yylex): typo in wide strings. + + * tm-vaxv.h, config-vaxv.h: New files for sysV on vax. + + * config-sun4.h: If sparc and not compiling with GCC, include alloca.h. + +Fri Jul 22 02:38:02 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu) + + * tree.c (build_real_from_int_cst): CHECK_FLOAT_VALUE at proper place. + + * tm-hp9k320.h ({TEXT,DATA}_SECTION_ASM_OP): Should not include a tab. + * final.c (final_start_function): Don't output a tab before those. + + * sdbout.c (PUT_SDB_EPILOGUE_END): New macro. + * sdbout.c (sdbout_end_epilogue): New function to output the C_EFCN. + Like former sdbout_mark_end_function. Uses that macro. + * final.c (final_end_function): Call that function. + * tm-3b1.h: Override PUT_SDB_EPILOGUE_END like the other PUT_SDB... + + * tm-3b1.h (PRINT_OPERAND_ADDRESS, ASM_OUTPUT_INTERNAL_LABEL, + ASM_OUTPUT_CASE_{LABEL,END}): Put a % in names of internal labels. + (ASM_GENERATE_INTERNAL_LABEL, ASM_OUTPUT_ADDR_{VEC,DIFF}_ELT): + New macros, for same reason. + (FUNCTION_PROFILER): New macro, for % and also to put addr in a0. + + * final.c (output_source_line): For fcn's first line, use lineno 1. + * sdbout.c (sdbout_end_function): Clear sdb_begin_function_line + so can recognize first line of next function. + + * sdbout.c (sdbout_init): Output the .file pseudo here. + * tm-3b1.h, tm-att386.h (ASM_FILE_START): Don't do it here. + + * sdbout.c (PUT_SDB_VAL): Output leading tab, like the other macros. + * tm-3b1.h (PUT_SDB_VAL): Likewise. + + * regclass.c (regclass): Cast enums to int, not char. + * varasm.c (record_constant): Likewise. Avoids 3b1 PCC bug. + + * decl.c (pushdecl): Better choice of error message for extern/static. + + * emit-rtl.c: Do look for STRUCT_VALUE_INCOMING_REGNUM. + +Thu Jul 21 02:13:03 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * cse.c (canon_hash): CONST_INT case failed to add to prev. value + of HASH; was inconsistent with cse_insn mem address hashing. + + * m68k.md (divide insns): Alternate 3B1 syntax for `swap' insn. + +Wed Jul 20 18:27:10 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * m68k.md: In shift-by-24 patterns, rejects autoincrement memrefs + since they are mode-dependent. + +Tue Jul 19 13:01:38 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * parse.y (check_newline): Handle #ident by writing .ident to output. + * cccp.c: Don't handle #ident; delete IDENT_DIRECTIVE conditionals. + + * stmt.c (expand_end_case): In compares, put constant arg second. + + * jump.c (jump_optimize): Delete conditional jump if followed by + an unconditional jump to the same place. + +Mon Jul 18 17:49:13 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * emit-rtl.c (init_emit_once): Now STRUCT_VALUE_INCOMING is an + expression for an rtx. It can make a MEM. Likewise STRUCT_VALUE + for outgoing structure value addresses. + + * stmt.c (assign_parms): If incoming struct addr on stack, leave room. + * expr.c (expand_call): If outgoing addr on stack, push it like an arg. + + * PROMOTE_PROTOTYPES means if proto says `char', pass `int'. + * decl.c (get_parm_info): Alter DECL_ARG_TYPE to do this. + * typecheck.c (actualparameterlist): Convert value for this. + * tm-m68k.h: Define PROMOTE_PROTOTYPES. + +Sun Jul 17 14:25:47 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * jump.c (jump_optimize): peephole can delete insns following INSN. + Set NEXT after peephole. + + * decl.c (finish_decl): Always restart perm alloc if global. + + * stmt.c (assign_parms): When a float is passed as double, store the + float in low-numbered word. Avoids trouble with parm_map in integrate. + + * vax.md: New pattern for decrement and compare against -1. + +Sat Jul 16 14:18:00 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * decl.c (pushdecl): Ignore previous decl if it's really an error_mark. + + * stmt.c (expand_start_case): Make sure case_stmt.start is a NOTE. + + * combine.c (subst): In the simplification for + (set (zero_extract ...) (and/or/xor (zero_extract ...) const)), + require same memory location in both extracts. + + * *386*: New files. + + * cse.c (fold_rtx): Save time in memory address if it didn't change. + Don't replace cheaper expression with coslier one. + (cse_insn): Reenable generation of REG_WAS_0. It wasn't obsolete. + + * cccp.c: `ident' has 5 letters. + + * final.c (output_source_line): SDB can't handle multiple source + files, so ignore line-NOTEs for other files. + + * hard-reg-set.h: New var reg_class_size (# regs in the class). + * regclass.c (init_reg_class): Set it up. + + * reload.c (find_reloads): If an earlyclobber is in a class of size 1 + as an output, reload it as input instead of as output. + + * reload1.c (choose_reload_targets): Improve elimimation of spilled + pseudos made dead by reloading: if pseudo is limited to one block + and that block contains just stores, delete all the stores. + + * reload1.c (choose_reload_targets): reg_has_output_reload is now + static and survives through reload pass. + (forget_old_reloads): Don't cancel data on spilled regs of output + reloads of the insn just made. + + * sdbout.c (sdbout_one_type): Go to .text before defining a type. + (sdbout_block): Test against do_block was backwards. + + * stmt.c (expand_end_function): New args to make a NOTE for last line. + * decl.c (finish_function): Pass the args. + + * rtl.c (no_labels_between): New function. + * vax.md (movsi): Call it. + + * print-tree.c (dump): Don't follow chain of a decl. + + * rtl.c (volatile_refs_p): Moved from flow.c. + +Fri Jul 15 13:36:20 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu) + + * sdbout.c (PUT_SDB...): Allow config to override any of them. + * sdbout.c (PUT_SDB_{BLOCK,FUNCTION}_{START,END}): New macros. + * tm-3b1.h: Override all of them. + * sdbout.c (SDB_GENERATE_FAKE): New macro to create dummy tag name. + (gen_fake_label): Use SDB_GENERATE_FAKE. + * tm-3b1.h: Override its defn. + + * sdbout.c (sdbout_mark_function_end): Unused; deleted. + + * tm-3b1.h: Define SDB_DEBUGGING_INFO. + +Thu Jul 14 01:55:15 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu) + + * config-sunv4.h: New file for Sunos version 4. + + * tm-sun3.h (CPP_SPEC): Define mc68010 or mc68020, depending. + +Tue Jul 12 15:31:30 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * stmt.c (expand_fixup, expand_goto_internal): New functions to + emit a jump that can restore the stack level, even without tree node. + (expand_null_return, expand_exit_loop, etc.): Use expand_goto_internal. + (expand_end_function): Do fixup_gotos after emitting return_label. + + * cse.c (predecide_loop_entry): Avoid using JUMP_LABEL. + * flow.c (find_basic_blocks): Avoid using JUMP_LABEL. + + * flow.c (insn_dead_p): Delete special case for stack-adjust insns. + (life_analysis): Mark those insns with INSN_VOLATILE here. + (mark_used_regs): a SET of a hard reg, in a volatile insn, + always makes its source live. + +Mon Jul 11 10:46:26 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * ns32k.md (floatqidf2): Commented out since assemblers warn about it. + +Sun Jul 10 11:49:23 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * decl.c (xref_tag): Default the TYPE_MODE of enum xrefs + to avoid making MEM and REG with VOIDmode. + + * vax.md (call): If > 255 args, pop them explicitly. + +Sat Jul 9 10:53:47 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * symout.c (symout_types): Fix up forward refs to previously + undefined structure types. + (filter_undefined_types): New function. + (symout_finish, symout_function_end): Output any never-defined structs. + * toplev.c (rest_of_compilation): call symout_function_end. + + * parse.y: Don't declare errno if it's a macro. + + * tm-hp9k320 (FUNCTION_PROFILER): Pass ptr in a0, not d0. + + * typecheck.c (truthvalue_conversion): Flush unnec recursive call. + (build_cond_expr): Bug testing zeroness of IFEXP with TREE_LITERAL. + + * cse.c (fold_cc0): Constants not CONST_INT are certainly nonzero. + * fold-const.c (fold): ADDR_EXPR is not equal to zero. + + * cccp.c (macroexpand): Disable the macro even if traditional. + (rescan): Error if use a disabled macro. + + * combine.c (try_combine): Don't substitute a different reg into + an auto-increment. Handle multiple REG_INC notes in I1 or I2. + + * decl.c (implicitly_declare): Don't reuse old implicit decl. + + * varasm.c (assemble_variable): Avoid syntax err if no DBX and no SDB. + * final.c (output_source_line): likewise. + + * fold-const.c (fold): PLUS/MINUS_EXPR: in case of cancellation, + convert result to original type. + + * regclass.c (reg_class_record): Changed arguments include address + of entire vector of constraints. + +Fri Jul 8 07:59:00 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * reload1.c (reload): Find groups of more than 2 registers. + +Thu Jul 7 08:33:07 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * expr.c (emit_push_insn): Typo adjusting arg for bcopy + if not STACK_GROWS_DOWNWARD. + + * gnulib.c (_cmpsf2): Value is int, not SFVALUE. + +Wed Jul 6 11:53:46 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * tm-encore.h, tm-3b1.h: Replace ASM_FILE_START; output a .file. + + * *m88*: New files for Motorola 88000. They don't really work. + +Tue Jul 5 14:40:03 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * local-alloc.c (combine_regs): Don't tie a reg to itself. + + * finxincludes: Make a variable LIB for the target dir. + + * m68k.md (movhi, addhi3, addsi3): Micro-optimize choice of asm insns. + + * expr.c (expand_expr): Use new macros NO_DEFER_POP, OK_DEFER_POP + in several places, to keep stack predictable. + +Mon Jul 4 09:50:18 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * integrate.c (function_cannot_inline_p): Increase threshold size. + + * flags.h (use_gdb_dbx_extensions): New variable. + * toplev.c: + + * sdbout.c (PUT_SDB_TAG): Delete duplicate defn. + + * expr.c (expand_expr): For FIX_TRUNC_EXPR to unsigned short/char, + REALLY go via signed int. + + * loop.c (may_trap_p): Was detecting floating arithmetic incorrectly. + + * tm-news800.h (CPP_PREDEFINES): Add sony and sony_news. + + * parse.y (check_newline): Avoid infinite loop at eof. + +Sat Jul 2 10:35:17 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * Version 1.24 released. + + * stmt.c (expand_asm_operands): Produce proper no-outputs insn. + * recog.c (asm_noperands): Detect no-outputs insns. + (decode_asm_operands): Likewise. + * reload.c (find_reloads): Likewise (add case ASM_OPERANDS:). + + * local-alloc.c (block_alloc): Tests of qty_compare were backwards. + + * flow.c (life_analysis): Turn off code that finds regs live at + function start and marks them not local to any basic block. + + * cse.c (insert_regs): Fix typo (UNITS_PER_WORD). + + * cccp.c: Define max. + + * expr.c (expand_expr): Put each SAVE_EXPR's reg on save_expr_regs, + if not optimizing. + * stmt.c (expand_function_end): Mark each of those regs live + at the end and also retroactively at the beginning of the function. + + * output-vax.c (print_operand_address): New function from old macro. + * tm-vax.h (PRINT_OPERAND_ADDRESS): Call that function. + + * config-vms.h: If not under GNU C, define X_OK, etc. + + * expr.c (move_by_pieces_1): Use * to call GENFUN. + (expand_expr): Compare DECL_FUNCTION_CODE against an enum const. + (preexpand_calls): Likewise. + * genrecog.c (write_tree): Likewise. + * final.c (final): Use * to call the output function. + * reload.c (push_reload): Rename `noshare' to `dont_share'. + + * genoutput.c (output_epilogue): Put more newlines in insn_outfun. + * genemit (gen_exp): Put in more newlines. + +Fri Jul 1 00:23:57 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * global-alloc.c (allocno_compare): Avoid comparisons of floats + since that is sensitive to roundoff errors. + +Thu Jun 30 09:25:40 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * sdbout.c (PUT_SDB_{DEF,TAG}): Use ASM_OUTPUT_LABELREF. + (PUT_SDB_PLAIN_DEF): New name for old defn of PUT_SDB_DEF + (sdbout_one_type): Use PUT_SDB_PLAIN_DEF for `.eos'. + + * tree.c (allocation_temporary_p): New fcn. + (all_types_permanent): New variable. + (make_node): If that's set, make each ...TYPE node permanent. + * decl.c (grokdeclarator): If traditional, make decl data permanent. + (finish_decl): Make the rtl permanent too. + * stor-layout.c (layout_type): If type is permanent, + make its layout data permanent too. + + * cccp.c: Choose C++ or C at run time via var `cplusplus'. + Separate cplusplus_include_default from include_default. + Get GNU-specific include directory names from macros + GCC_INCLUDE_DIR and GPLUSPLUS_INCLUDE_DIR. + (main): Initialize based on CPLUSPLUS; `-+' sets it. + * Makefile: Set *_INCLUDE_DIR based on $(libdir). + +Tue Jun 28 09:25:49 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * tree.c (copy_node): Round LENGTH up to multiple of sizeof (int). + + * expr.c (emit_push_insn): Avoid using PUSH_ROUNDING if not defined. + + * sparc.md (floatsisf2): Insert missing brace. + (mulsi3): Replace reg_o0_rtx, reg_o1_rtx. + + * tm-sparc.h: Define DBX_DEBUGGING_INFO. + + * parse.y (yylex): If traditional, no error for out-of-range float. + + * Makefile: Comment saying how to compile on an Apollo. + + * tm-sparc.h (ASM_FILE_START): Switch to new calling convention. + + * decl.c (init_decl_processing): Create type nodes for 64-bit ints. + (grokdeclarator): use them for `long long'. Warn only if pedantic. + + * optabs.c (init_optabs): Add missing DImode insn names. + + * expr.c (emit_block_move, emit_push_insn): Use movstrqi if appro. + + * expr.c (convert_move): use extendsidi if appropriate. + + * cccp.c (initialize_builtins): Don't install __STDC__ if traditional. + (main): Call initialize_builtins after option processing. + + * integrate.c (output_inline_function): Set current_function_decl. + + * cse.c (fold_rtx): Typo in avoiding 32-bit shifts. + + * cccp.c: Add forward-decl. + +Mon Jun 27 18:06:42 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * hard-reg-set.h (reg_alloc_order): New variable + based on REG_ALLOC_ORDER, a new machine-description macro. + * regclass.c (reg_alloc_order): Define it. + * local-alloc.c (find_free_reg): Handle reg_alloc_order. + * global-alloc.c (find_reg): Likewise. + * stupid.c (stupid_find_reg): Likewise. + +Sun Jun 26 10:47:47 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * Version 1.23 released. + + * tm-3b1.h: Define IDENT_DIRECTIVE. + + * tm-encore.h: Define SDB_DEBUGGING_INFO. + Define SCCS_DIRECTIVE and IDENT_DIRECTIVE. + + * output-ns32k.c: Decl of paren_base_reg_printed must be outside fcns. + + * tm-encore.h (ASM_OUTPUT_DOUBLE): Do 0f, not 0l. + (CPP_PREDEFINES): No -Dns32032. + + * sdbout.c: Include syms.h, not storclass.h. + (unnamed_struct_member): Decl was missing. + (PUT_SDB_INT_VAL, PUT_SDB_VAL): Fix typos. + (sdbout_types, sdbout_one_type, sdbout_parms): Fix typos. + + * Makefile: Add file sdbout.o. + Changed comments pertaining to sysV. + Make a separate target `doc' to make the info files. + + * m68k.md (bit-field insns): Use nonimmediate_operand for the thing + to extract from. + * vax.md (QImode bit-field insns): Likewise. + + * recog.c (nonimmediate_operand): Accept any nonconst general operand. + +Sat Jun 25 07:54:42 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * cse.c (lookup_as_function): arg to exp_equiv_p was missing. + +Fri Jun 24 09:14:47 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * recog.c (memory_operand): Allow (subreg (mem...)). + +Thu Jun 23 07:34:07 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * decl.c (finish_enum): Compute minimum value like maximum. + If minimum is negative, install it in the type and make it signed. + + * stor-layout.c (layout_record): STRUCTURE_SIZE_BOUNDARY is minimum. + (layout_type): A RECORD_TYPE or UNION_TYPE must be BLKmode if + any member is BLKmode. This is to prevent putting it in a register. + (layout_decl): If decl's type is BLKmode, the decl *must* be BLKmode. + + * local-alloc.c (find_free_reg): Never allocate the frame pointer reg. + + * tm-sequent.h (PRINT_OPERAND): Bug in SFmode CONST_DOUBLE. + * tm-encore.h: Likewise. + + * flow.c (flow_analysis): Bug in n_basic_blocks error check. + + * stmt.c (expand_asm_operands): Emit no insn if an arg is erroneous. + +Tue Jun 21 08:34:24 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * reload.c (find_reloads_address): Write back *loc even if + subst_reg_equivs makes no change, in case subst_index_address did. + + * flow.c: Define macros for -1 and -2 as values of reg_basic_block. + (mark_used_regs): Add an `else'; no change in behavior. + (mark_label_ref): Abort if LABEL_REF doesn't contain a CODE_LABEL. + (find_basic_blocks): Extra error check. + + * output-ns32k.c (print_operand_address): Changes in handling of + register-indirect, and of indexing by sb register. + +Mon Jun 20 04:55:38 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * cccp.c (collect_definition): Compute needed space more accurately. + Abort if use more space than was allocated. + (rescan) [USE_C_ALLOCA]: Do alloca (0) after handle_directive. + + * genflags.c (gen_insn): Put parens around defns of HAVE_... macros. + +Sun Jun 19 02:52:53 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * expr.c (emit_push_insn): Consider PARM_BOUNDARY when compensating + for size of a pushed arg to bcopy. + +Sat Jun 18 07:20:54 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * New files sparc.md, tm-sparc.h, config-sparc.h, output-sparc.c. + + * final.c (final): After an ADDR_{,DIFF_}VEC, do ASM_OUTPUT_CASE_END. + * tm-3b1.h: Define ASM_OUTPUT_CASE_END. + (PRINT_OPERAND_ADDRESS): Ref the case tables via an intermediate symbol + `LDnnn' whose def. is output by ASM_OUTPUT_CASE_END. + (ASM_OUTPUT_CASE_LABEL): Add missing newline. + + * reload.c (find_equiv_reg): Reject a MEM containing an autoincrement. + +Fri Jun 17 06:58:37 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu) + + * genpeep.c (main): Write `extern' in the decl for `peep_operand'. + + * flow.c (propagate_block): When a dead insn has a REG_RETVAL note, + call mark_set_regs anyway, so that `significant' is updated. + + * jump.c (follow_jumps): New arg IGNORE_LOOPS. If 0, don't follow + the insn at the beginning of a loop that enters the loop; this avoids + interference with loop optimizer. + (jump_optimize, tension_vector_labels): Pass that arg. + + * loop.c (loop_optimize): Mention invalid multiple-entry loops in log. + + * m68k.md (extv, extzv): Fix # of alternatives mismatch in constraints. + +Thu Jun 16 03:06:48 1988 Richard Stallman (rms at corn-chex.ai.mit.edu) + + * genrecog.c (change_state): Was mishandling printing XVECEXP indices + greater than 9. + + * combine.c (subst, simplify_and_const_int): Avoid making SUBREG + of a non-REG. + + * expr.c (expand_expr): For FIX_TRUNC_EXPR to unsigned short/char, + go via signed int. + + * optabs.c (expand_fix): Copy hard_libcall_value reg only once. + + * reload1.c (order_regs_for_reload): Init all elements + of potential_reload_regs to -1. + + * Prevent generation of (set (reg) (plus ... (label_ref ...))). + * explow.c (memory_address_noforce): Like `memory_address' but + never force it into a register. + * expr.c (do_tablejump): Use that. + * m68k.md (casesi): Use that. + + * rtl.h (struct rtx_def, GET_CODE, PUT_CODE): If SHORT_ENUM_BUG, + define the `code' field as a short. + +Wed Jun 15 01:25:57 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * gcc.c (CPP_SPEC): New spec set by config.h gives flags to cpp. + * tm-*.h for m68k: Define CPP_SPEC to define __HAVE_FPU__ on + appropriate conditions. + + * combine.c (subst): Simplify (not (minus x 1)) and (neg (minus x y)). + +Mon Jun 13 02:22:43 1988 Richard Stallman (rms at corn-chex.ai.mit.edu) + + * typecheck.c (build_array_ref): Avoid duplicate errmsg if index + is an error-mark. + +Sun Jun 12 23:04:39 1988 Richard Stallman (rms at corn-chex.ai.mit.edu) + + * cccp.c (handle_directive): If -traditional, quotes aren't special. + (rescan): Assume newline ends a string constant. + + * cccp.c, cexp.y: Make all fcns non-static; add some forward decls. + + * various: add static forward-decls for various functions. + +Fri Jun 10 00:25:18 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * reload1.c (choose_reload_targets): When writing back an incremented + value (handling reload_inc), write back to the real place, not to + OLDEQUIV (a register that holds the same value). + + * tm-m68k.h (LEGITIMIZE_ADDRESS): Don't give force_operand a target. + This can cause the use of multiple insns with same output reg, + which can confuse cse. + + * loop.c (consec_sets_invariant_p): + If invariant_p ever returns 2, we return 2. + New arg is # of consecutive sets to look for, + since this info is no longer in n_times_set at move_movables. + (scan_loop): If consec_sets_invariant_p returns 2, set m->cond. + (move_movables): check consecutive insns if m->consec && m->cond. + + * tm*.h: ASM_DECLARE_FUNCTION_NAME now takes 3rd arg, + the FUNCTION_DECL node. + * varasm.c (assemble_function): Pass this arg. + + * expr.c (expand_call, expand_builtin [alloca]): + If STACK_POINTER_OFFSET is defined, add it to stack pointer contents + before using it as address of actual data on the stack. + * stmt.c (expand_decl): Likewise. + + * stmt.c (assign_parms): If 1st parm named `__builtin_va_alist' + came in regs, pretend it came on stack. + Handle pretending a BLKmode var came on the stack. + If REG_PARM_STACK_SLOT, count stack space for each parm + even if the parm came in a register; and use that stack space + if the parm needs to be addressable or is BLKmode. + Rearrange to simplify conditionals. + +Thu Jun 9 01:21:29 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * local-alloc.c: + `qty_...' vectors' elements for hard-reg-numbers now aren't used. + `reg_qty' elements for hard-reg numbers now aren't used, + and the element for a pseudo is never a hard-reg number. + (local_alloc): No need to reset those elements. + No need to reset elements out of range of prev block's NEXT_QTY. + (reg_is_born, reg_is_set, wipe_dead_reg): + Divide labor in same way for hard regs and pseudos; + simplify using fact that locality-to-basic-block has been precomputed + and recorded in reg_qty; avoid refs to reg_qty[HARDREG]. + (reg_is_born, wipe_dead_regs): Block-number arg no longer needed. + + * local-alloc.c (combine_regs): Remove old code for tying hard regs + to pseudos; great simplification results. + Use find_regno_note, not regno_dead_p. + +Wed Jun 8 00:18:04 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * reload.c (subst_reg_equivs): Set a flag if anything is changed. + (find_reloads_address): Check that flag to avoid extra work. + Also check early for safe reg+const address and avoid work. + + * reload.c (find_reloads): Use loops instead of bcopy. + Check early for insn with no real constraints, and return. + Also check for move from hard reg to hard reg and return. + + * cse.c (canon_reg): Rewrite for speed; use a switch. + (cse_insn): Don't call find_reg_note if REG_NOTES is 0. + + * cse.c (cse_insn): Store modified SET_SRC even if there's a REG_EQUIV. + Inhibition was needed when the SET_SRC was the only place to find the + equivalent value; now it is in the REG_EQUIV note. + + * stmt.c (expand_asm_operands): If NINPUTS is 0, make vec of no elts. + * regclass.c (reg_scan_mark_refs): Don't lose if XVEC (x,i) is 0. + +Tue Jun 7 03:51:28 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * stmt.c (assign_stack_local): If big-endian and MODE is narrow, + the bytes actually used are the least significant. + + * parse.y (skip_white_space): Accept char as arg; let caller read it. + (yylex): Change call. + (check_newline): Return 1st nonwhite char after skipping lines. + (skip_white_space): Change call. + * toplev.c (compile_file): Change call. + + * gcc.c: Pass -traditional to cc1. + + * cse.c (cse_insn): Return very early for (set (reg) (call...)). + Mainly to save time. + (cse-insn) Old code to add REG_WAS_0 note wasted time but did nothing. + + * expr.c (clear_pending_stack_adjust): Really do clear it, + if current fcn doesn't want to be inline. + + * cse.c (cse_insn): Speedup: instead of safe_hash, use canon_hash + or HASHREG. + +Mon Jun 6 21:47:23 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * jump.c (rtx_renumbered_equal_p): Reject ADDR_VEC fast. + + * cse.c (cse_insn): Ignore a REG_EQUIV or REG_EQUAL note if the + equivalent value is the same as the SET_SRC of the insn. + + * flow.c (life_analysis): Don't call volatile_refs_p for a CALL_INSN; + just assume value is 1. + (propagate_block): Don't call mark_{used,set}_regs for a stack-pop + since if it isn't dead it has no effect on any useful life data. + (mark_set_1): Return quickly if setting stack-ptr, and almost as + quickly if setting any hard reg. + (mark_used_regs): Likewise for refs. + Also don't scan the vector of an ADDR_VEC or ADDR_DIFF_VEC. + (volatile_refs_p): Likewise. + + * varasm.c (output_constant): Discard NOP_EXPR and CONVERT_EXPR + in integer case (they were for casting a pointer). + + * parse.y (compstmt_or_error): Parse a compstmt after ignoring error. + Use this for fctn body so that an error after store_parm_decls + won't recover to xdecls and call store_parm_decls again. + Typical cause was missing semi at end of last parmdecl. + + * parse.y: Add missing semicolons in actions. + (yylex): Don't use yylloc. + +Sun Jun 5 16:14:40 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * typecheck.c (build_array_ref): Check arg types here, to make + error message more accurate (not about "addition"). + +Thu Jun 2 02:41:40 1988 Richard Stallman (rms at rice-krispies.ai.mit.edu) + + * cccp.c (collect_expansion): `#' isn't special if -traditional. + + * dbxout.c (dbxout_parms): Don't output a regparm symbol + unless the parm got a hard reg assigned. + + * tm-encore.h (ASM_OUTPUT_DOUBLE): Use 0f... not 0d... + + * tm-vax.h (CHECK_FLOAT_VALUE): Define this. + +Wed Jun 1 17:13:00 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * expr.c (expand_call): Have sequence points between args. + +Tue May 31 00:27:06 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * expmed.c (store_fixed_bit_field): Avoid shifting by 32. + * cse.c (fold_rtx): + * symout.c (subrange_p): likewise. + + * local-alloc.c (block_alloc): If operands 1 and 2 commute, + try tying output to operand 2 if operand 1 won't do. + + * toplev.c (compile_file): Pass main_input_file to symout_init. + + * tree.c (build_real, build_real_from_int_cst): + Call CHECK_FLOAT_VALUE if it's defined, to report out-of-range values. + + * tree.c (build_real, build_real_from_int_cst): New 1st arg TYPE. + * parse.y (yylex): Pass this arg; requires parsing suffixes first. + * fold-const.c (fold, combine, fold_convert): Pass this arg. + Handling of float binops in `combine' simplified. + + * tm-encore.h (CPP_PREDEFINES): Remove -Dencore since CC lacks it. + + * final.c (output_source_line): Let ASM_OUTPUT_SOURCE_LINE + be used for SDB also. + +Mon May 30 00:21:15 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * cse.c (insert): Was inserting in wrong place in list. + (exp_equiv_p): Was failing to check validity when x == y. + + * tree.c (build_pointer_type): Handle saveable_obstack + like current_obstack. + + * decl.c (finish_decl): Error in test for zero-size array warning. + + * reload.c (find_equiv_reg): New arg MODE specifies mode in which + an equivalent value is needed. Equivalence must be good in that mode. + In addition, notice overlap with multiword register modes. + Simplify, knowing that registers have already been renumbered. + It was invalidating memory-goals too easily; setting a reg + only invalidates memory-goal if its address varies. + * reload.c, reload1.c, jump.c: Calls pass the new argument. + + * cccp.c: For correct ANSI, must reject `$' in identifiers. + (dollars_in_ident): Variable says whether to allow them. + (rescan): Handle `$' as randomchar if that's 0. + (main): dollars_in_ident is set to 0 by -$, to 1 by -traditional. + (rescan, do_define): Delete former pedantic warnings for `$'. + (initialize_char_syntax, initialize_builtins): Inits split to two + functions; former is called after options are scanned + so `$' is in is_idchar conditionally. + * gcc.c: For -ansi, pass -$ to cccp. + * toplev.c, flags.h: Define dollars_in_ident. + * parse.y (yylex): Treat $ as punctuation unless dollars_in_ident. + Delete old pedantic warning about $. + * tm-vms.h: Define DOLLARS_IN_IDENTIFIERS as 1. + + * cccp.c (rescan): Preprocessing numbers can have signs, after `e'. + + * integrate.c (expand_inline_function): Abort, don't return failure, + if max_regno is too low. I believe this can't happen. + + * typecheck.c (build_binary_op_nodefault): + For ordered comparisons, no pedantic warning about void *. + For MAX, MIN, ditto, and also don't allow pointer vs 0. + + * typecheck.c (build_unary_op): Don't allow pointer for +. + + * typecheck.c (convert_for_assignment): + Add missing warning for case of unrelated pointer types. + Change criteria for new ANSI C draft. + + * optabs.c (expand_binop): Don't set unused target_is_not_an_operand. + + * fold-const.c (fold_convert): Don't set unused inprec, outprec. + + * emit-rtl.c, parse.y: Delete unused var. + + * stor-layout.c (add_vc_sizes): Unused function deleted. + * loop.c (constant_high_bytes): #if 0 this unused function. + + * gcc.c (fatal): Add missing arg to delete_temp_files. + + * cccp.c (dump_defn_1): Add missing arg to skip_quoted_string. + + * reload.c (find_reloads): If constraints don't fit in an `asm', + print error instead of aborting. + + * regclass.c (reg_class_record): Ignore `&' in constraint. + +Sun May 29 00:20:23 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * Makefile: Run ranlib only if /usr/bin/ranlib exists. + Add comment saying what to do on system V. + + * tree.c (suspend_momentary): Switch to the saveable_obstack + for the sake of inline functions. + + * flags.h (enum debugger): New enum for write_symbols. + * toplev.c, varasm.c, final.c: Use the enum constants where appro. + Add calls to sdbout paralleling the calls to dbxout; + put each in the appropriate conditional {SDB,DBX}_DEBUGGING_INFO. + + * toplev.c (main): Delete -noreg option; it's now the default. + Make -O an alias for -opt. Rename -g to -gg. -g is alias for -G. + Accept and ignore -Wtrigraphs. + * gcc.c: Simplify the specs. + + * toplev.c (compile_file), tm-*.h: + ASM_FILE_START is now a statement, not just a string to be output. + Output it *after* determining the real source file name. + + * fold-const.c (fold): Simplify x >= CST to x > CST-1 (CST positive). + To simplify this, canonicalize relationals to put constat last. + + * decl.c (duplicate_decls): Make a 2nd errmsg to show previous decl. + + * cccp.c (file_size_and_mode): Delete temporary VMS bootstrap patch. + + * tm-att386.h: New file. + + * decl.c (pushdecl): Warn if a local `extern' decl precedes + a file-scope `static' decl. + + * expr.c (expand_call): No warning for failure to inline. + + * expmed.c (extract_bit_field): copy operand 1 of extv or extzv + into register if memory isn't allowed. + +Sat May 28 02:10:56 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * gnulib.c, Makefile: Delete va_end. + + * final.c, symout.c: Check DBX_DEBUGGING_INFO, not NO_DBX_FORMAT. + + * genemit.c (gen_expand): Notice a CALL inside a PARALLEL. + + * regclass.c (init_reg_sets_1): Part of init_reg_set is put in this + new fn which is called after options are scanned. + Now CONDITIONAL_REGISTER_USAGE can depend on the options. + (fix_register): Just alter the data that init_reg_sets_1 will look at. + + * reload1.c (reload): Don't complain if two different but tieable + modes require groups of the same regclass (assuming same size group). + + * cccp.c: Add 3rd arg to all `open' calls. + + * parse.y (check_newline): Typo prevented ignoring whitespace. + + * cccp.c (perror_with_name): fprintf had harmful extra arg. + + * cccp.c (main, trigraph_pcp): -Wtrigraphs means warn if any trigraphs. + + * emit-rtl.c (gen_sequence): If LEN is 1, avoid looking at PATTERN + of something that doesn't have one. + + * reload1.c (alter_frame_pointer_addresses): frame pointer can + occur by itself, not just inside a PLUS. + (reload): Call eliminate_frame_pointer before reload_as_needed. + Otherwise the latter can make reload insns that copy the frame ptr + to a data reg, but 68k can't copy sp+const to a data reg. + + * decl.c (implicitly_declare): Always save the implicit decl + permanently. Reuse an old one if it exists. + * tree.c (resume_temporary_allocation): Used after `end_temporary...' + to go back to temporary allocation. + + * stor-layout (layout_{type,decl}): Call variable_size. + (variable_size): Turn a size into a SAVE_EXPR and either compute + it right away or put it on a list to be computed later. + (get_pending_sizes): Return that list and clear it out. + * stmt.c (expand_start_function): Tell `variable_size' to compute + sizes right away, and compute those saved on the list. + (expand_end_function): Tell it to put them on a list. + +Fri May 27 00:02:34 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu) + + * dbxout.c (dbxout_symbol): For local static var, use 'V', not 'v'. + + * gcc.c (main): Don't handle SIGHUP or SIGTERM if shell ignored it. + + * Makefile, gcc.c: Propagate Make var `libdir' to gcc search path. + + * expr.c (expand_expr): a PARM_DECL with no rtl can occur in size of + `a' in `foo (a,i) int i; struct {int x[i];} a;', so report an error. + + * flow.c (insn_dead_p): insn that makes stack bigger is never dead. + * combine.c (try_combine): Don't splice out stores into stack ptr. + + * reload.c (find_equiv_reg): Test given regno for OVERLAPPING_REGNO_P. + + * varasm.c (assemble_variable): Use saveable_obstack for allocation. + +Thu May 26 01:17:00 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu) + + * integrate.c (save_for_inline): Clear unused slots in parmdecl_map. + (There may be some non-parm regs below max_parm_regno.) + * integrate.c (copy_for_inline): Don't crash if parmdecl_map elt is 0. + + * Don't fail to output a static inline function that was referenced + via a local extern decl before its definition. + * expr.c (expand_call): If need to mark a fcn decl addressable, + mark the identifier addressable also. + * typecheck.c (mark_addressable): If marking fcn addressable, + mark the identifier as well. + * decl.c (start_function): If identifier was marked addressable, + propagate it to the function. + + * parse.y (yylex): Check for ERANGE after atof is called. + (Sun doesn't report ERANGE.) + + * loop.c (may_trap_p): Any floating arithmetic may trap. + +Wed May 25 00:03:34 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu) + + * parse.y: Delete `noalias'. + (asm_operand): Don't allow this to be empty. + (asm_operands): Do allow this to be empty. + + * reload.c (operands_match_p): Don't let REG and SUBREG match + if the reg isn't a hard reg. + No longer nec. to check reg_renumber, now that reload + substitutes the hard regno. + + * reload1.c (reload): Counting existing spilled groups, + check HARD_REGNO_MODE_OK so we don't get fooled by an odd-even pair. + Spill entire need for new groups before spilling any solitary regs. + Reg already counted against max_nongroups can't become part of a group. + (new_spill_reg): Do bookkeeping associated with a new spill-reg. + (n_spills): This var is now static, no longer passed as arg + within the file. + + (reload_reg_class_lower): Handle all group-reloads before solitaries. + (choose_reload_targets): therefore #if 0 the special code for + finding solitary registers that aren't suitable for groups. + But fix two bugs in it: braino deciding whether a reload + is looking for 1 register (not a group). Use CLASS_MAX_NREGS. + Also braino deciding whether a spill reg can be in a group. + Did not fix bug that it fails to test HARD_REGNO_MODE_OK, + so it might split up an even-odd pair. + + * vax.md: Special patterns for 8 and 16-bit fields, to make + move-insns (like the ones for the 68k). + + * tree.c (convert_to_integer): Pass truncation down thru COND_EXPR + as through a binary operator. + + * typecheck.c (build_cond_expr): If unpromoted operand types match, + don't promote them--let containing expression promote (just once). + +Tue May 24 14:46:26 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu) + + * combine.c (subst): Simplify (subreg (sign_extend X) 0). + + * tm-hp9k320.h: Delete NO_DBX_FORMAT. + * Most tm...h files: Define DBX_DEBUGGING_INFO. + * dbxout.c: Change conditional to DBX_DEBUGGING_INFO. + + * integrate.c (expand_inline_function): If inline fcn was declared to + return QI, but actually computes an SI, use SImode for INLINE_TARGET + but actually return a QI. + + * varasm.c (force_const_mem): Failed to determine alignment bdry + from machine mode. + + * jump.c (jump_optimize): Don't delete (move X Y) if X or Y is a + PRESERVE_DEATH_INFO_REGNO_P register. + + * final.c (output_addr_const): In PLUS, output constant term last. + + * final.c (final): Before outputting an insn, do FINAL_PRESCAN_INSN. + + * final.c (next_block_index): No longer static. + (final): Add SDB_DEBUGGING_INFO cases for outputing NOTEs + for beginning and end of a block. + (output_source_line): Add SDB_DEBUGGING_INFO case for line number. + * varasm.c (assemble_function): Add code for SDB symbol output. + + * gnulib.c: Allow config to override INTIFY. + New macro SFVALUE for data type to return a single-float in. + + * combine.c (remove_death): No longer `static'. + + * reload1. (choose_reload_targets): PRESERVE_DEATH_INFO_REGNO_P + selects hard regs for which death info should be updated for final. + + * reload1.c (reload_as_needed): Let INSN_CLOBBERS_REGNO_P + prevent inheritance of certain reloads. + + * reload.c (find_equiv_reg): Let OVERLAPPING_REGNO_P reject + an equiv reg. Needed for funny float regs on 80387. + + * cccp.c (do_ident): Define #ident as a no-op if IDENT_DIRECTIVE. + Warn if pedantic. + (do_sccs): Warn if pedantic. + + * emit-rtl.c (restore_reg_data): Set cur_insn_uid--prevent duplicates. + +Sun May 22 12:25:06 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu) + + * Version 1.22 released. + + * reload1.c (reload): Spilling isn't finished till max_nongroups is 0. + + * tm-encore.h (PRINT_OPERAND): No `$' before a CONST. + +Sat May 21 13:08:54 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu) + + * fold-const.c (combine): Typo in MIN_EXPR, MAX_EXPR. + + * reload1.c (reload): Was counting insn_groups as total size of groups, + not number of groups. + A new spilled group counts against group-needs of superclasses. + + * parse.y (parmlist{,_or_identifiers}_1): In error case, + return a tree list just as in the other cases. + +Fri May 20 02:14:51 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu) + + * config-vax.h, config-m68k.h: If __GNUC__, use builtin-alloca. + + * genpeep.c (match_rtx): Generated code was testing the wrong rtx + when testing an int or string at a nonzero index in the rtx. + + * reload.c (find_reloads): Typo checking `modified' for conflict + with an earlyclobber. + + * reload.c (find_equiv_reg): Reject stack ptr as return value. + + * expr.c (expand_builtin): Alloca must do pending stack adjust. + +Thu May 19 13:01:01 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu) + + * flow.c (propagate_block): Skipping back across libcall didn't happen + due to failing to set PREV. + + * expr.c (emit_library_call): Code to increment and decrement + current_args_size broke since emit_call_1 was changed to restore it. + + * combine.c (try_combine): When i1 or i2 auto-incs a reg, don't combine + if i3 uses that reg. + + * config-hp9k3.h: #define bcopy, bcmp, bzero here. + * conf-hp9k320.h: Delete file. + + * integrate.c: Don't include strings.h--no need. + + * stmt.c (expand_asm_operands): Don't make zero-length vectors. + + * loop.c (scan_loop): After a fcn call, maybe-trap insns can't move. + The fcn call might exit and that would prevent the trap. + + * reload1.c (reload): Set reload_first_uid to next uid to be used. + * reload.c (find_equiv_reg): Use reload_first_uid to ignore insns + that are due to reloading--only if reload_reg_p is not 0 or 1. + +Wed May 18 22:11:20 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu) + + * typecheck.c (build_unary_op): Don't complain about array + as argument to `!'. + + * decl.c (pushdecl): If locally declaring an extern function, + check the identifier's global value in case it's an inline function. + +Mon May 16 03:06:08 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu) + + * output-ns32k.c (output_shift_insn): New fn, maybe turn shift to adds. + (reg_or_mem_operand): Predicate for a non-immediate general_operand. + * tm-ns32k.h (CONST_OK_FOR_LETTER_P): Define letter K. + * ns32k.md: Use output_shift_insn for various addr insns that shift. + Don't allow nonexplicit constants in lprd, multiply or truncate insns. + Use reg_or_mem_operand for constraint in op1 of divide insns; + a constant there causes regclass to screw up. + Split alternative constraints on the bit-field insns to avoid + out-of-range operands in exts, inss. Some cases of extraction + can be done faster via memory. + + * flow.c (mark_set_1): When adding a REG_DEAD note, inc reg_n_deaths. + + * dbxout.c (dbxout_type_def): Do nothing for {integer,char}_type_node. + +Sun May 15 00:56:44 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu) + + * tm-sequent.h, tm-ns32k.h, tm-encore.h (PRINT_OPERAND): + Was treating SF's as SI's. + + * expr.c (emit_move_insn): Check all CONST_DOUBLEs for + LEGITIMATE_CONSTANT_P and put them in memory if not. + + * local-alloc.c (combine_regs): Allow a reg to be tied to a qty + if the reg's class is contained in the qty's class + (as well as if the reg's class contains the qty's class as before). + Rename qty_reg_class to qty_min_class and make it the smallest + class of any reg tied to the qty. + (reg_class_subset_p, reg_meets_class_p, update_qty_class): + New subroutines to implement this. + (local_alloc): Init reg_qty to -1 for pseudos not in cur. basic block. + (reg_is_born): Abort if pseudo not in basic block has -2 in reg_qty. + + * jump.c (rtx_renumbered_equal_p): Insist that modes of REGs match. + +Sat May 14 01:05:35 1988 Richard Stallman (rms at lucky-charms.ai.mit.edu) + + * stmt.c (expand_return): Empty frame frame_offset isn't nec. 0. + + * expr.c (emit_call_1): Use stack_size_rtx everywhere appropriate. + + * decl.c (init_decl_processing): Set sizetype to `unsigned long' + if `int' is less than a word. + + * stddef.h (size_t, ptrdiff_t): Both are now long. + +Fri May 13 01:06:00 1988 Richard Stallman (rms at lucky-charms.ai.mit.edu) + + * emit-rtl.c (gen_lowpart): Handle non-lowpart subreg as arg. + + * recog.c (register_operand): VOIDmode means allow any mode. + (immediate_operand, nonmemory_operand): Likewise. + + * emit-rtl.c (classify_insn): Update for changed CALL_INSN format. + (emit): New function to emit an rtl pattern as the right kind of insn. + * jump.c (simplejump_p): No longer static. + + * genemit.c (gen_expand): For match_operand at top level, call `emit'. + Use `emit_call_insn' when appropriate. + (gen_exp): Handle rtx's that contain strings. + + * final.c, symout.c: If not NO_DBX_FORMAT, include stab.h to get the + N_... symbols. Use their default definitions only if they're undef. + + * expr.c (expand_call) [no PUSH_ROUNDING]: Always set argblock + if there are any stack-passed arguments. + + * typecheck.c (build_unary_op): Mark all increment-exprs volatile. + + * recog.c (reg_renumbered_fits_class_p): Delete private copy of + reg_class_contents. + + * reload1.c (forget_old_reloads): Handle PARALLEL case by recursion. + Explicit store into a spilled reg invalidates old reloaded contents; + this can occur when we drop through into a basic block whose need was 0 + (and so whose local pseudos were not spilled). + + * gcc.c (main): If -v, print gcc's own version; also no error msg + if no input files. + + * loop.c (may_trap_p): Mem ref to nonconstant address may trap. + (scan_loop): Check may_trap_p only when insn is in other respects ok. + + * cexp.y: #include config.h (for decl of alloca on some machines). + +Thu May 12 17:24:19 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu) + + * regclass.c (regclass): When inserting an insn at start of block, + update basic_block_head. + +Wed May 11 00:47:09 1988 Richard Stallman (rms at corn-chex.ai.mit.edu) + + * stmt.c (assign_parms): DECL_OFFSET should be offset as passed + (not including big-endian width-change correction). + + * typecheck.c (shorten_compare): Set unsignedp[01] right in case + where get_narrower makes no change. + (build_binary_op_nodefault): Likewise for shortening shifts. + + * stmt.c (expand_end_case): Use type_for_size to get the type + to convert the index to, since `int' is wrong if -mshort. + + * decl.c (grokdeclarator): Don't check PARM type for completeness. + (grokparms): If fn definition, check all parm types for completeness. + (store_parm_decls): Likewise. + +Tue May 10 22:42:13 1988 Richard Stallman (rms at corn-chex.ai.mit.edu) + + * typecheck.c (store_init): For invalid init, store error_mark_node. + * varasm.c (assemble_variable): Ignore error_mark as an init. + * stmt.c (expand_decl): If init is error_mark, init to 0 if possible. + This avoids a spurious "uninitialized variable" warning. + +Sun May 8 17:08:07 1988 Richard Stallman (rms at lucky-charms.ai.mit.edu) + + * tm-hp9k320.h: Define STRUCTURE_SIZE_BOUNDARY. + + * decl.c (get_parm_info): Replaces get_parm_types. Returns a tree_list + containing parmdecls and tag list as well as type list. + (grokparms): Accept that tree_list as argument. + (grokdeclarator): Calling grokparms, say "not a definition" for the + function declarators for arg or value types within a definition. + + * parse.y: Call get_parm_info. + (parmlist_or_identifiers): If identifiers, make a tree_list + like the one get_parm_info returns. + +Fri May 6 16:44:19 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu) + + * m68k.md (casesi): Delete template aside from match_operand's. + + * tm-encore.h: New file from Robert Brown. + + * ns32k.md: Use %c in some addr insns. + (tst*): Use {d,f,}const0_rtx to make the constant 0; OS-independent. + (call, call_value): Use %? before address in a bsr. + + * output-ns32k.c (print_operand_address): To output a local label, + use `output_asm_label'. + Make SEQUENT_ADDRESS_BUG conditionals happen at compile time. + + * tm-ns32k.h: Delete SEQUENT_HAS_FIXED_THEIR_BUG. + (PRINT_OPERAND): Output nothing for `%?'. + * tm-sequent.h: (PRINT_OPERAND): Output nothing for `%?'. + + * final.c (output_asm_label): No longer `static'. + +Thu May 5 09:03:37 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu) + + * explow.c (memory_address): Ignore flag_force_reg unless optimize. + Also ignore it for addresses of stack slots (avoid invalid REG_EQUIVs). + + * typecheck.c (digest_init): If traditional, allow `char x[100]=0;'. + + * tree.c (get_unwidened): Don't alter a COMPONENT_REF if + innerprec equals the precision of the existing type. + It was changing pointers to integers. + + * m68k.md (movdi): Put all fpregs in separate constraint alternatives + and handicap them so spill reg won't be an fp reg. + + * parse.y (yyerror): Use the arg as part of the error message. + + * decl.c (start_function): Give the RESULT_DECL type int rather + than char or short. + * typecheck.c (c_expand_return): Convert value from fn's return type + to the RESULT_DECL's type. + + * Avoid generating dbx xrefs to enums, since dbx loses on them. + Do this by outputting all types in order of definition. + This is done only for top-level types; problem remains for local ones. + + * decl.c (finish_decl): Do rest_of_decl_compilation for TYPE_DECLs. + * toplev.c (rest_of_decl_compilation): Do dbxout_symbol for them. + + * dbxout.c (dbxout_symbol): Check DECL_RTL only for fns and variables. + For a TYPE_DECL, ignore it if the type was already output + and its preferred name is the TYPE_DECL. Else output type in full. + + * decl.c (pushdecl): Don't prefer typedef names to type tag names. + + * stor-layout.c (chain_type): Build chain in forward order. + + + * tm-3b1.h (ASM_OUTPUT_CASE_LABEL): Error getting length of table. + + * tm-3b1.h: #define SGS_3B1 was missing. + + * typecheck.c (build_compound_expr): Ignore non-volatile subexprs. + + * fold-const.c (fold): Simplify (unsigned) foo >= 0, etc. + + * stor-layout.c (layout_type): Set TYPE_PRECISION of ptr types. + +Wed May 4 08:06:25 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu) + + * parse.y: Don't use the Bison @ construct, since it makes parser slow. + + * decl.c (finish_function): Delete FILENAME and LINE args. + + * typecheck.c (digest_init): No pedantic warning for array="string". + +Tue May 3 09:09:30 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu) + + * toplev.c (main): Ignore `-Wcomment'. + * gcc.c: Pass -Wall to cpp (which treats it like -Wcomment). + + * tm-isi68.h: Greatly simplified; now works only with GAS. + + * tm-m68k.h (EMPTY_FIELD_BOUNDARY): now 16 (right on Sun, ISI and HP). + * tm-sun3.h: No need to redefine it. + + * decl.c (finish_struct): Don't ever make DECL_ALIGN smaller. + + * decl.c: Rename min, max to MIN, MAX. + + * typecheck.c (convert_for_assignment): Avoid warning if assigning + a `void *' from a `const void *'. + + * combine.c (FAKE_EXTEND_SAFE_P): Turn off for mem refs; avoid faults. + +Mon May 2 07:28:27 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu) + + * tm-vax.h: Support -mg switch to use g-float instead of d-float. + New macros TARGET_G_SWITCH, ASM_DOUBLE_CHAR. + Changes in TARGET_SWITCHES, ASM_OUTPUT_DOUBLE. + Define code `#' for PRINT_OPERAND. + * vax.md: use `#' in opcodes for doubleword float. + + * tm-vax.h: Define UDIVSI3_LIBCALL and UMODSI3_LIBCALL. + + * cccp.c (main, do_include): Implement -I- switch. + + * jump.c (jump_optimize): When hunting NOTE_INSN_FUNCTION_END, + skip final RETURN (found on the vax). + + * toplev.c (main): -Wall is equiv to all -W switches combined. + + * stmt.c (expand_decl, expand_end_bindings, + expand_{start,end}_function). The -noreg treatment of `register' vars + is extended to vars used as addresses of vars in memory (varying-size + structures). + (use_variable): Emit USE for regs used in specified rtx. + + * cse.c (fold_cc0): Stack-frame addresses are always nonzero. + (fold_rtx): 0200 bit in prev_insn_cc0 means only zeroness is known. + + * parse.y (parmlist): poplevel needs 3 args. + +Sun May 1 07:20:34 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu) + + * decl.c (start_function): typo checking for incomplete return type. + + * emit-rtl.c (restore_reg_data): If a pseudo appears nowhere, + don't leave its slot empty; create a pseudo for that slot. + + * Version 1.21 released. + + * expr.c (expand_call): Merge duplicate code for structure_value_addr. + + * emit-rtl.c (restore_reg_data): Delete error check; it's legit for + a pseudo reg to appear nowhere in the rtl. + +Sat Apr 30 07:35:31 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu) + + * integrate.c (copy_rtx_and_substitute): Fix typo for arg_pointer_rtx. + + * decl.c (poplevel): Undo previous change with #if 0. + + * stmt.c: `struct nesting' now records the depth on the stack. + Each expand_start... must update and record the depth; + each expand_end... uses macro POPSTACK to pop. + This way, if a level isn't explicitly popped, it won't cause + circular structure. + + * dbxout.c (dbxout_type): Replace with main variant only if incomplete. + + * typecheck.c (build_unary_op): Test of `pedantic' was backwards. + + * expr.c (STACK_BYTES): Typo in definition. + + * typecheck.c (build_binary_op_nodefault): Rename code1 to code0, + and likewise for code2, tt1, tt2. + + * expr.c (expand_call): Wrong arg order for warning_with_decl. + +Fri Apr 29 08:41:06 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu) + + * integrate.c (copy_decl_tree): New arg is depth in recursion. + Always discard the outermost LET_STMT being copied; never discard any + others. This way the copied LET_STMTs correspond to the copied NOTEs. + + * varasm.c (decode_rtx_const): For SYMBOL_REF, use string address + not address of the rtx. Library fns have only one copy of the name + but many copies of the SYMBOL_REF. + + * expr.c (emit_call_1): New arg OLD_ARGS_SIZE is used to reset + current_args_size. + (emit_library_call, expand_call): Pass new arg; don't restore it here. + + * flow.c (life_analysis): Don't mark sp live at end if fn is empty. + + * parse.y (parse_or_identifiers_1): Handle `error' in here, not in + callers notype_declarator etc. Also read the closeparen here. + +Thu Apr 28 12:43:52 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu) + + * expmed.c (expand_shift): In extzv strategy, handle the operand + predicates for operands 0, 1 and 3. (Not needed for 2.) + * vax.md: extzv pattern for SImode op1 must recognize general_operand + since the pattern named "extzv" allows them. + +Wed Apr 27 00:52:44 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu) + + * expr.c (emit_call_1): New arg NEXT_ARG_REG describes # regs + used for passing args. + (emit_library_call, expand_call): Provide that argument. + + * explow.c (round_push): New fn: round arg up to STACK_BOUNDARY. + * expr.c (expand_builtin): Use round_push on size for __builtin_alloca. + * stmt.c (expand_decl): Likewise for variable-size objects. + * expr.c (expand_call): Likewise for args_size.var. + Also use STACK_BOUNDARY to round a constant arg-block size. + Pass emit_call_1 that rounded value. + (emit_library_call): Round arg_size with STACK_BOUNDARY. + * tm-spur.h: Define STACK_BOUNDARY instead of ROUND_CALL_BLOCK_SIZE. + * tm-m68k.h: Define STACK_BOUNDARY as 16. + + * expr.c (emit_call_1): Don't change current_args_size. + (emit_library_call, expand_call): Always restore current_args_size + to ambient value, after calling emit_call_1. + + * tm-hp9k320.h: Don't define USG here. + * config-hp9k3.h: New file. USG defined here. + + * tm-3b1.h: #undef ASM_OUTPUT_ASCII (a defn came from tm-hp9k320.h). + + * decl.c (grokdeclarator primarily): Cast all RID_... to (int) before + using them in arithmetic. Placates CC on Sequent. + + * emit-rtl.c (emit_jump_insn): Return proper value, for a SEQUENCE. + * emit-rtl.c (emit_call_insn): Handle SEQUENCE like emit_jump_insn. + +Tue Apr 26 02:41:26 1988 Richard Stallman (rms at lucky-charms.ai.mit.edu) + + * cccp.c (macroexpand): If traditional, don't disable called macro. + (macarg1): Was failing to count backslash-newline inside a string + in a macro arg as part of file's linenumber. + +Mon Apr 25 18:46:53 1988 Richard Stallman (rms at lucky-charms.ai.mit.edu) + + * jump.c (jump_optimize): Don't do April 20 optimization on first + iteration; let other simpler opts be done before this is considered. + +Sun Apr 24 02:45:28 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu) + + * tree.c (staticp): a CONSTRUCTOR can be static. + + * varasm.c (output_constant_def): Always return memref, not address. + + * decl.c (complete_array_type): New fn, make an array type complete + based on an initializer. + (finish_decl): Use complete_array_type. + * parse.y (expr_no_commas): When parsing a constructor, + Use complete_array_type on constructors for incomplete array types. + + * typecheck.c (digest_init, store_init_value,process_init_constructor): + It's now TREE_STATIC, not TREE_ADDRESSABLE, that records that all elts + in a CONSTRUCTOR are simple constants. + (digest_init): A CONSTRUCTOR with non-null type is treated as ordinary + expression, not as a braced initializer. + Allow init of an array from an array-valued expr; warn if pedantic. + * expr.c (expand_expr, CONSTRUCTOR case): Put in memory only if static. + Was making an extraneous level of MEM; output_constant_def does it all. + + * typecheck.c (build_unary_op): Allow ADDR_EXPR of static CONSTRUCTOR. + (default_conversion): Likewise. + (initializer_constant_valid_p): Constructor is ok if static. + + * gcc.c: Change -fnostd... to -nostd... + * cccp.c (main): Likewise. + + * Everywhere: Use REG_NOTE_KIND to get the kind of a reg note. + + * rtl.c (find_regno_note): New function. + * flow.c (flow_deadp): Deleted; caller uses find_regno_note. + * global-alloc.c (reg_dead_p): Deleted. + (global_conflicts): Use find_regno_note instead of reg_dead_p. + + * final.c (final) Use find_reg_note to look for a REG_INC. + * combine.c (insn_has_inc_p): deleted; callers use find_reg_note. + (try_combine): Use find_reg_note whenever looking for a REG_INC. + (regno_dead_p, remove_death): Check the REG_NOTE_KIND before assuming + that the datum in it is a REG. + * reload1.c (reload): Use find_reg_note to find a REG_EQUIV. + + * gcc.c: Don't delete .o files if not all compilations succeed. + (record_temp_file): New arg SUCCESS_ONLY--delete file only if succeed. + (delete_temp_files): New arg SUCCESS says compilation succeeded. + (store_arg): Now 3 possibilities for arg TEMPNAMEP; 2 = del on success. + (do_spec_1): For %d, set delete_this_arg to 2. + + * decl.c (poplevel): Warn about any still-incomplete type-tags. + +Sat Apr 23 02:54:16 1988 Richard Stallman (rms at rice-krispies.ai.mit.edu) + + * expr.c (expand_builtin): For alloca, round arg up to multiple + of PARM_BOUNDARY. Also to convert it to Pmode unless it already is. + + * stor-layout.c (layout_union): Bug in 14 April change: + use caller-specified alignment as minimum, not as maximum. + + * parse.y (skip_white_space): Avoid infinite loop on unterm. comment. + +Fri Apr 22 00:22:59 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu) + + * cccp.c: Text following #else or #endif is just a warning. + (rescan): Digit-case was dropping into the $-case; reorder. + + * cccp.c (rescan): Comment start when -traditional was output as + `/*'; should be nothing. + + * jump.c (jump_optimize): Fix prev change: + do nothing if range1end == range2end; + don't lose any NOTEs when splicing. + + * flow.c (propagate-block): For CALL_INSN, clobber the call-used regs + only after mark_set_regs is done; avoids confusion about lifespan + of function value reg. + + * gcc.c: Pass -Wcomment to cpp. + + * cccp.c (main, rescan): If -Wcomment, warn if `/*' inside comment. + + * decl.c (duplicate_decls): Ignore `inline' decl following definition. + + * m68k.md (casesi): Split it up into subroutines, so insns emitted + by the call to memory_address (on 68000) come in the right place. + + * combine.c (record_dead_and_set_regs): Notice storing in a SUBREG. + + * integrate.c (expand_inline_function): Insn to copy a subroutine's + return-value was being output twice, once incorrectly. + + * reload.c (find_equiv_reg): A stack-push insn does not invalidate + an equiv for a goal in memory. + Any other write to memory does invalidate any goal in memory + (PARALLEL case failed to check for this). + + * expmed.c (expand_shift): In the extzv clause, force shifted value + out of memory if -fforce-mem. + + * print-tree.c (prtypeinfo): Some attributes were missing. + (dump): In ..._TYPE nodes, ignore the TREE_CHAIN field. + + * cse.c (note_mem_written): Pushing on stack does not invalidate mem. + + * vax.md (extv/andl peephole opt): Made incorrect code if output was + pushed on stack. Added special case code. + (extv, extzv for SImode operand): Require register_operand. + +Thu Apr 21 00:24:52 1988 Richard Stallman (rms at corn-chex.ai.mit.edu) + + * stmt.c (assign_parms): Round current_function_pretend_args_size up. + + * integrate.c: `pushlevel' arg was missing. + + * dbxout.c (dbxout_type): Undo rest of March 29 change: + When a named type is first seen inside another type, output an xref + and let the real definition come out later. + It is strange that Sun dbx has sometimes appeared to demand + one strategy and sometimes appeared to demand the other. + + * typecheck.c (convert_for_assignment): Allow conversion to or from + `const void *', etc., unless pedantic. + + * decl.c (get_parm_types): For `foo (void){}', set last_function_parms + to nil so store_parm_decls won't lose. + + * combine.c (subst): (plus (plus X N) -N) => X. + + * explow.c ({anti_,}adjust_stack): Don't make a copy of + `stack_pointer_rtx'. + + * integrate.c (expand_inline_function): Typo testing for the + USE that indicates a CALL_INSN's value is being returned. + + * expr.c (expand_builtin, alloca case): Copy arg to reg before + adjusting stack, to avoid invalid insns on some machines. + +Wed Apr 20 00:15:14 1988 Richard Stallman (rms at rice-krispies.ai.mit.edu) + + * typecheck.c (build_binary_op_nodefault): When shortening, + get_narrower may make no change because ARGn is already narrow. + In this case, set UNSIGNEPn from ARGn's type. + + * typecheck.c: Rename ARG1,ARG2 to ARG0,ARG1, etc. in several fns. + + * tm-vax.h: Turn off continuation on DBX output. + + * typecheck.c (build_function_call): Don't change __builtin_ffs to an + FFS_EXPR. Note that __builtin_alloca has always made a CALL_EXPR. + * expr.c (expand_builtin): New function expands all CALL_EXPRs that + are really built-in functions. + (preexpand_calls): Do nothing to a CALL_EXPR for a built-in function. + + * loop.c (count_loop_regs_set): Don't move a reg that is in a CLOBBER. + + * stupid.c (stupid_mark_refs): Was getting hard reg's mode from + the wrong place. + + * rtl.c (note_stores): Typo in checking vector elt for SET vs CLOBBER. + + * stmt.c (expand_end_bindings): If restoring stack level, + first do pending stack adjust (so it won't be done erroneously after). + (expand_goto): likewise. + + * rtl.h: LABEL_NUSES was an rtx. It should be an int. + * stmt.c (expand_label, expand_goto): Delete frobbing with LABEL_NUSES; + the value stored there was the same as the CODE_LABEL rtx. + + * jump.c (jump_optimize): Detect if (foo) ...; else { ... break;} + and change to if (! foo) { ... break;} else ...; so can drop out. + (next_label): New fn returns the next label after given insn. + +Tue Apr 19 21:30:05 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu) + + * flow.c (insn_dead_p): Delete special handling for stack ptr. + (mark_set_regs, mark_used_regs): Likewise. + (life_analysis): Mark stack ptr live at end of fn if necessary. + (propagate_block): Mark stack ptr live leading up to a CALL_INSN. + + * jump.c (jump_optimize): #if 0 around stack-adjust-deletion code. + + * cse.c (fold_rtx): Change const_arg from an array to 3 separate + scalars for the first three operands. + Handle SIGN_EXTEND and ZERO_EXTEND. + + * integrate.c (copy_rtx_and_substitute): If arg is 0, return 0. + (expand_inline_function): Separate vars for old pattern and new insn. + + * expr.c (expand_call): Set TREE_ADDRESSABLE if call is not inlined. + +Tue Apr 19 02:25:22 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu) + + * Version 1.20 released. + + * tm-ns32k.h: Define new reg class GEN_OR_FLOAT_REGS + so that GENERAL_REGS and FLOAT_REGS have a union. + + * tm-ns32k.h (GO_IF_LEGITIMATE_ADDRESS): Recognize a stack-push. + * ns32k.md: Many constraints must now allow or reject pushes. + Delete the special patterns for pushing. + +Mon Apr 18 06:02:39 1988 Richard Stallman (rms at rice-krispies.ai.mit.edu) + + * reload1.c (forget_old_reloads): For a multiword hard reg, + forget old reloads for each word. + + * reload.c (find_reloads): Typo in calling push_replacement. + + * tm-ns32k.h (HARD_REGNO_MODE_OK): Failed to allow fp regs for SFmode. + +Sun Apr 17 01:21:35 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu) + + * tm-sequent.h (PRINT_OPERAND): Handle absolute integer memaddress. + + * ns32k.md: Add DImode push insns. Add QImode and HImode push insns. + Supply missing statement in movsf. + + * dbxout.c (dbxout_type): Don't contin before 1st field of struct. + + * dbxout.c (dbx_continue): Use DBX_CONTIN_CHAR instead of backslash. + + * loop.c (scan_loop): Ov vax, the "loop-entry jump" can be a return, + in which case perhaps there is no label following it. + Detect phoniness of loop before looking for that label. + + * decl.c (init_decl_processing): Builtin fn names start with `__'. + + * typecheck.c (shorten_compare): Warn about constant result only in + cases like (char)x < 0x80, where old C compilers made it -0x80. + + * vax.md: All jbs/jbc/jlbs/jlbc patters with op0 in SImode + must reject mode-dependent memory addresses. + + * recog.c (mode_independent_operand): Test for general operand + that doesn't have a mode-dependent memory address. + + * varasm.c (assemble_function): ASM_DECLARE_FUNCTION_NAME, if def, + is now responsible for outputting the function name as a label. + +Sat Apr 16 05:02:55 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu) + + * cccp.c (do_xifdef): Warn about punctuation or other junk in argument. + Warn about no argument. If pedantic, warn if arg starts with digit. + If traditional, ignore all after first non-idchar and never warn. + +Thu Apr 14 01:12:59 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu) + + * integrate.c (expand_inline_function): Typo for addressable parms. + + * cse.c (insert_regs): Copying half a DImode into half of another + does not make the two DImode regs equivalent. + + * recog.c (general_operand): Was failing to accept symbol_ref:SI + when MODE arg was VOIDmode. + + * expr.c (preexpand_calls): For RTL_EXPR, do nothing. + + * decl.c (start_enum, build_enumerator): Remember default for next one + as a tree node (so the high-half isn't lost in a negative one). + + * stor-layout.c (layout_{record,union}): Pay attn to initial value + of TYPE_ALIGN in computing final alignment. + (layout_union): Round size up to multiple of the alignment. + + * decl.c (finish_struct): Don't alter size after type is laid out. + Instead, set TYPE_ALIGN before layout_type. + + * reload1.c (choose_reload_targets): Introduce reg_has_output_reload. + If there are two separate reloads (one in and one out) + for the same (hard or pseudo) reg, always set reg_last_reload_reg + based on the output reload. + +Wed Apr 13 21:26:16 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu) + + * reload.c (find_reloads_address_1): Always barf if a "constant" + register is autoincremented. + + * parse.y (structsp): suspend_momentary before start_enum; + else some nodes made by start_enum might be momentary. + + * stmt.c (expand_start_case): New arg is nominal type for comparison + (which is the promoted type of the index expression). + (pushcase): Always convert VALUE to that nominal type + before validating it. + * parse.y (case stmt): Promote each case-value before pushcase. + * typecheck.c (c_expand_start_case): Promote the index-expr + to determine the nominal type, before get_narrower. + +Wed Apr 13 12:43:08 1988 Chris Hanson (cph at kleph) + + * tm-hp9k320.h: Define ASM_FORMAT_PRIVATE_NAME. HPUX asm forbids + `.' in identifiers, so use `___' (there is some danger in this choice). + +Tue Apr 12 23:26:48 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu) + + * local-alloc.c (block_alloc): Make 1 extra slot in regs_live_at. + + * stmt.c (optimize_bit_field): Function moved from reload1.c. + When need to generate a SIGN_EXTEND or ZERO_EXTEND, make it a separate + insn and use gen_extend_insn to make it. + * optabs.c (gen_extend_insn): New fn, construct body of an insn + to extend Y and store in X. + +Mon Apr 11 19:20:57 1988 Richard Stallman (rms at rice-krispies.ai.mit.edu) + + * decl.c (finish_decl): Error if static var has variable size. + + * parse.y (yylex): Warn if int const is out of range. + + * parse.y: New keyword __alignof. + * typecheck.c (c_alignof): Given a type, return its alignment in bytes. + + * typecheck.c (c_sizeof{,_nowarn)): Don't return integer_one_node; + use build_int to make sure we get something with type `sizetype'. + + * Support variable-sized structures (containing var-sized arrays). + + * stmt.c (assign_parms): Handle parms whose size varies. + Use `memory_address' when constructing memrefs to args; + no need to set `invalid_stack_slot'. + Don't make a REG_EQUIV note for a scalar arg at variable offset. + * stor-layout.c (genop, build_int): No longer `static'. + + * stor-layout.c (convert_units): Optimize ceil (ceil(x,2)*2, 4) etc. + + * stmt.c (expand_decl): Don't abort if var-sized object has init. + Convert variable size from units of DECL_SIZE_UNIT to units of bytes. + + * expr.c (emit_push_insn): Arg ARGS_SO_FAR is now an rtx. + Pay attention to ARGS_ADDR even if machine has push insns. + (expand_call): Handle variable-sized arguments. + If have any such, push entire arg-block in advance. + Record each arg's offset during first loop and don't change args_size + during the actual pushing loop; this way the actual pushing loop + works regardless of arg-order if arg-block was pushed in advance. + (push_block): Copy SIZE to reg unless it's a reg or constant. + + * expmed.c (expand_divmod): If converting CEIL_DIV to FLOOR_DIV, + make new pseudo for incremented value, to help cse understand. + +Sun Apr 10 00:07:45 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu) + + * expr.c (emit_library_call): Two dumb bugs calling emit_call_1. + + * dbxout.c (dbxout_symbol): Handle case of (MEM (REG frameptr)). + + * cccp.c (skip_if_group): Ignore quote-chars if -traditional. + (rescan): If -traditional, don't output a space for a comment. + (handle_directive): If not -traditional, output a space for a comment. + +Sat Apr 9 21:26:51 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu) + + * decl.c (get_parm_types): `void' type is error, except as entire list. + * parse.y (parmlist_1): `void,...' is error. + + * typecheck.c (pointer_int_sum, pointer_diff): + Use an integer type with at least POINTER_SIZE bits. + * expr.c (expand_expr, ARRAY_REF): Likewise. + * tree.c (type_precision): Prec of a pointer is POINTER_SIZE. + (convert_to_pointer): Directly convert any int w/ width==POINTER_SIZE. + Other int types convert via an int of that width. + (convert_to_integer): Pointers convert via an int of that width. + + * decl.c (init_decl_processing): Use INT_TYPE_SIZE, if def, + to set width of `int' and `unsigned int'. + (make_index_type): Give new type the width of a long int. + + * tm-m68k.h: Add new -mshort which controls TARGET_SHORT. + * tm-m68k.h: Define INT_TYPE_SIZE depending on TARGET_SHORT. + +Fri Apr 8 05:02:59 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu) + + * typecheck.c (require_complete_type): Fix typo in detection of `void'. + (build_function_call): Fix backward test to allow `void' values. + + * dbxout.c (dbxout_tags): Output each tag once even if type is defined. + + * m68k.md (movstrictqi): Reject addr-reg always, for both operands. + + * tm-vax.h (STRUCTURE_SIZE_BOUNDARY): Make this always 8, for BSD. + * tm-ultrix.h: New file, overriding STRUCTURE_SIZE_BOUNDARY. + [This change has been taken out; tm-ultrix.h is now equivalent to + tm-vax.h. I must have been confused when testing PCC.] + + * integrate.c (expand_inline_function): Don't let inline_target + be nonzero in BLKmode. + + * decl.c (grokdeclarator): Const array parm becomes ptr-to-const. + +Thu Apr 7 05:02:41 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu) + + * genoutput.c (bcopy, bzero): Renamed to mybcopy, mybzero + so variation in C library and config.h won't affect the results. + * genrecog.c (bzero): likewise. + * genextract.c (bcopy): Fn deleted; used only in a string constant. + + * varasm.c (force_const_mem): Fix typo in arg decl. + + * toplev.c (compile_file): init_file with main_input_filename + so dbx output doesn't lack N_SOL symbols. + + * cccp.c (rescan) [CPLUSPLUS]: Put out // comments as // comments. + +Wed Apr 6 14:06:38 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu) + + * expr.c: Delete SLOW_ZERO_EXTEND conditionals added March 3. + Now that enums types can be unsigned, this isn't needed. + + * emit-rtl.c (emit_jump_insn): Handle SEQUENCEs. + + * genemit.c (gen_expand): Use emit_jump_insn, emit_label, emit_barrier + when the insn rtl requires it. + + * m68k.md (subsi3): Prefer to avoid reverse-subtraction alternative. + + * stmt.c (expand_end_case): Let CASE_DROPS_THROUGH control what to + emit after the table. + * tm-vax.h: Define CASE_DROPS_THROUGH. + +Tue Apr 5 15:47:10 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu) + + * genemit.c (gen_exp): Handle vectors within exprs. + + * stmt.c (expand_end_case): Pass 5th arg (default_label) to gen_casesi. + * m68k.md: Define casesi insn rather than tablejump insn. + + * cccp.c (skip_if_group): For validate_else, pass BP (end of cmd name). + Don't call validate_else if do_else or do_endif will detect error. + + * Bug: inline fcns can refer to the return reg with a strict_low_part + which confuses expand_inline_function. Fix is to change return reg + into inline_target *everywhere* except in or right after a call. + * integrate.c (copy_rtx_and_substitute): Delete special case for SET. + Replace return-value hard regs with INLINE_TARGET in all contexts. + (expand_inline_function): special handling for insn after a CALL_INSN + if it copies the function value out. + Allow notes and stack adjust insns to intervene + between the CALL_INSN and the value-copy. + + * expr.c (emit_call_1): New name for gen_call_1. + + * Bug: ({...}) insns were in wrong place for a subexpression + after a sequence point, as in x ? y : ({...}). + * tree.def: New tree-code RTL_EXPR holds a sequence. + * expr.c (expand_expr): Handle RTL_EXPR by emitting the sequence. + * stmt.c (expand_{start,end}_stmt_expr): Use emit_to_sequence + to make a sequence from everything within the ({...}). + (expand_{start,end,emit}_delayed_expr): Delete these functions. + * parse.y (`for'-statements): Don't call them; nothing special needed. + + * parse.y (yylex): Handle syntax L"..." and L'...' + (combine_strings): Handle wide strings being combined. + * typecheck.c (digest_init): Reject wide string as init for char array. + Allow it for an int array, but don't allow a narrow string. + * decl.c (init_decl_processing): New var int_array_type_node. + + * parse.y: Define keyword `noalias'. + * parse.h: Define RID_NOALIAS. + + * typecheck.c (compparms): Not all parmlists match an empty one; + call `compparms1' to filter them. + + * decl.c (groktypename): Remove special case for `void' as parameter. + (get_parm_types): Special case for list of one decl with type void. + + * decl.c (build_enumerator): Give enum constants the type `int'. + Variable `current_enum_type' eliminated. + (finish_enum): No need to repeat `fixup_unsigned_type' + since the precision has not changed. + * stor-layout.c (layout_type): Allow enum types to be unsigned. + + * emit-rtl.c (unshare_all_rtl): Unshare contents of all reg-notes. + + * parse.y (check_newline): filename is optional in #-lines. + +Mon Apr 4 14:36:54 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu) + + * typecheck.c (shorten_compare): When data type determines the value, + eval the nonconstant arg anyway if it has side effects. + (build_conditional_expr): When merging `foo *' with `void *', + also allow `const void *'. Result type has merged set of qualifiers. + (qualify_type): Merge qualifiers of two types. + + * decl.c (get_parm_types): Store any tags defined in parmlist + into `last_function_parm_types'. + (store_parm_decls): Add those tags into the current binding level. + + * parse.y (parmlist, parmlist_or_identifier): Pass 0 to pushlevel; + no binding levels in C should be transparent to tags. + + * 3b1 support: + * tm-3b1.h: New file. + + * m68k.md: Add HPUX_ASM conditionals for shift-by-24-and-compare. + In one of the dbra patterns, a HPUX_ASM conditional was backwards. + (movhi) [SGS_3B1]: Define the LI... label as in MIT syntax. + (addsi3) [SGS]: Syntax for base-displacement differs from MOTOROLA. + (subsi3) [SGS]: likewise. + (tablejump) [ASM_OUTPUT_CASE_LABEL]: Use 6, not 2, as displacement. + This assumes ASM_OUTPUT_CASE_LABEL on 68k is used for a `swbeg'. + + * final.c (final): Use ASM_OUTPUT_CASE_LABEL (if defined) to output + any CODE_LABEL followed by an ADDR_VEC or ADDR_DIFF_VEC. + It has 4 args; 4th is the insn which is the ADDR_VEC or ADDR_DIFF_VEC. + + * tm-*.h for 68000 (PRINT_OPERAND_ADDRESS): For unscaled indexing in + fetch from a branch table, use L and LI symbols as in the scaled case. + + * cccp.c: If SCCS_DIRECTIVE, define #sccs as no-op. + + * integrate.c (output_inline_function): Real start of function + is FIRST_PARM_INSN, not FIRST_FUNCTION_INSN. + + * tree.c (build_string): String contents must be saveable (for + inline fcn). + + * cse.c (cse_insn): Don't forget to set dest_hash_code when dest + is a stack slot (and so its address is not being optimized). + + * emit-rtl.c (restore_reg_data_1): reg_rtx_no must be 1+ largest REGNO. + + * m68k.md (non-SImode bit-field insns): Change constraint to "o,d" + so a nonoffsetable memref is handled by reloading its address + but a register can still be handled. + + * toplev.c (main): Execute OVERRIDE_OPTIONS, if it's defined. + +Sat Apr 2 00:55:21 1988 Richard Stallman (rms at wheaties.ai.mit.edu) + + * expr.c (convert_move): Handle a SUBREG in direct truncation case. + + * cse.c (lookup_for_remove): Don't test machine mode of registers: + Storing in (REG:SI 0) invalidates (REG:DF 0). + + * decl.c (pushlevel): New arg, nonzero means this level is for + variables only, not for tags. All calls changed. + (lookup_tag): Even if THIS_LEVEL_ONLY, skip variables-only levels. + (pushtag): Define it in the first non-variables-only level. + + * dbxout.c (dbxout_type): Undo Mar 29 change, in the DBX_NO_XREFS case. + So now each struct or union will contain only nameless cross-refs + to any others it uses. The prior change is still in effect when + DBX_NO_XREFS is not defined. + + * Implement variable array bounds for parameters. + * decl.c (poplevel): Don't crash if DECL_NAME gives 0. + * typecheck.c (comptypes): A variable array bound matches anything. + * parse.y (parmlist): Call pushlevel, then pushdecl each parm as it + is parsed; then poplevel after using get_parm_types to extract the + results of the parmlist. + * decl.c (get_parm_types): New function; reverse the current decls, + put them in last_function_parms, and return a list of their types. + (grokparms): Arg is now an idlist or a typelist. Do nothing if latter. + (push_parm_decl): New function, like {start,finish}_decl combined + for a parm in a parmlist. + + * dbxout.c (dbxout_symbol): Ignore sym if its DECL_RTL is 0. + + * symout.c (symout_block_symbols): Ignore sym if type is error_mark. + +Fri Apr 1 11:41:21 1988 Richard Stallman (rms at wheaties.ai.mit.edu) + + * expr.c (prepare_call_address): New function; given two rtx's + for function and context, copy the context to the right hard reg, + put the function address in the right place and return an rtx for it. + (gen_call_1): No longer do those things. Delete args CONTEXT, PROTECT. + (emit_library_call, expand_call): Call `prepare_call_address'. + In between that and `gen_call_1', USE the parm registers. + + * tm-hp9k320.h (ASM_OUTPUT_*): Flush uses of output_arith_constant. + + * varasm.c (assemble_variable): Use ASM_FORMAT_PRIVATE_NAME + to make the name for a local static variable. + * tm-m68k.h, tm-vax.h, tm-ns32k.h, tm-spur.h: + Define ASM_FORMAT_PRIVATE_NAME. Use `.', not `$', to separate. + + * tm-m68k.h, tm-ns32k.h (FIX_FRAME_POINTER_ADDRESS): + To refer to stack ptr, use stack_pointer_rtx, not a copy. + + * tree.c (build_real_from_string): Function deleted. + * parse.y (yylex): Use build_real and atof. + + * parse.y: Allow string concatenation in arg of asm. + + * parse.y (yylex): Always allow `$' in ident, but warn if pedantic. + * tm-vms.h: Delete DOLLARS_IN_IDENTIFIERS (no longer tested). + + * cccp.c (rescan, do_define, initialize_random_junk): + Always allow `$', but warn if pedantic. + (main): If -t, set `traditional'. + (collect_expansion): If `traditional', no special handling for quotes + and no whitespace added at end of macro definition. + + * expr.c (compare, compare1): Last arg to compare_constants + must be a size in bits. + +Thu Mar 31 00:31:52 1988 Richard Stallman (rms at wheaties.ai.mit.edu) + + * expmed.c (expand_mult, expand_divmod, extract_fixed_bit_field): + Reject function return register as target if may need to read it. + (Reading the return register in an inline function doesn't work.) + + * decl.c (start_function): Delete extra arg to `error'. + + * emit-rtl.c (last_parm_insn): Delete this unused var. + + * make-cc1.com: New version from Kashtan. + + * integrate.c (expand_inline_function): Always set up an INLINE_TARGET + for a function that returns a nonvoid nonBLK value. + Since `pushlevel' and `poplevel' are called, must also call + `expand_{start,end}_bindings' to make a pair of NOTEs. + Let them handle USEs at end of scope of formal parameter copies. + + * integrate.c (expand_inline_function): In a new-style CALL_INSN, + don't change the result reg into INLINE_TARGET. Also, + generate a move insn after the call only if INLINE_TARGET is non-0. + + * integrate.c (copy_decl_tree): Don't crash if DECL_RTL is 0. + + * integrate.c (copy_for_inline): Don't treat `return' rtx's specially. + + * stmt.c (expand_{start,end,emit}_delayed_expr): + New fns to handle ({...})'s in expressions output not where parsed + (such as third expression in a `for' statement). + * parse.y: Call them to handle third expression in a `for'. + + * decl.c (duplicate_decls): Result is `inline' if either OLD or NEW is. + + * emit-rtl.c (emit_note): Return the note, or 0 if none. + * stmt.c (expand_start_bindings): Use emit_note's value. + +Wed Mar 30 12:48:22 1988 Richard Stallman (rms at wheaties.ai.mit.edu) + + * obstack.c (_obstack_begin): If ALIGNMENT is 0, use default. + Compute default for the alignment of a `double'. + * obstack.h (obstack_{begin,init}): Pass 0 for the alignment. + + * flow.c (mark_used_regs): Discard multiple SUBREGs, STRICT_LOW_PARTs. + + ** Call insns that return values are now represented as + (set (reg ...) (call ...)), not just (call ...). + + * *.md: Define a "call_value" insn pattern. + + * tm-m68k.h, tm-vax.h, tm-ns32k.h: (NOTICE_UPDATE_CC): + These insns invalidate the CC. + + * local-alloc.c (combine_regs): #if 0 special treatment of + function value hard reg. + (wipe_dead_reg): If hard reg, call reg_is_born so that the death + will not be ignored. + (reg_is_set): For reg that dies in this insn, mark it dead from now on + and post_mark it live after this insn only. + + * combine.c (try_combine): Don't allow a call insn as I1 or I2. + + * loop.c (count_loop_regs_set): Move CALL_INSN into a separate + clause. When finding regs that are function addresses, handle + both old and new format call insns. + + * flow.c (insn_dead_p): A SET that contains a CALL can't be dead. + (volatile_refs_p): Any CALL constitutes a volatile ref. + (mark_used_regs): If setting a reg from a volatile ref, + treat it like setting a reg whose value will be used. + + * expr.c (gen_call_1): New arg VALREG if nonzero means generate + a call_value insn which stores in VALREG. + (expand_call): Use `hard_function_value' to make the VALREG arg + unless expression has type `void'. + + * expr.c (emit_library_call): New 2nd arg OUTMODE is mode of result. + (So can give gen_call_1 the proper value-register.) + All callers (here and optabs.c) pass this arg. + + * cse.c (canon_hash): Consider all CALL rtx's volatile. + + ** end of change in representation of call insns. + + * stmt.c (expand_asm_operands): Replace complex lvalues with + SAVE_EXPRs here + * typecheck.c (c_expand_asm_operands): rather than here. + + * typecheck.c (pointer_diff): Fix typo preventing use of FLOOR_DIV_EXPR + when dividing by power of 2. + (build_c_cast): Flush unused locals. + (store_init_value): likewise. + (process_init_constructor): Delete unused 4th arg `for_static'. + + * toplev.c (fatal_io_error): Arg to fprintf was missing. + + * tm-m68k.h (LEGITIMIZE_ADDRESS): Flush extra arg to `emit_move_insn'. + + * decl.c: Delete some unused local vars. + + * stor-layout.c (layout_decl): `packed_size' now unsigned. + +Tue Mar 29 14:47:07 1988 Richard Stallman (rms at wheaties.ai.mit.edu) + + * Version 1.19 released. + + * loop.c (may_trap_p): Nonzero if X is a division that might trap. + (scan_loop): If insn might trap, move only if loop always executes it. + + * dbxout.c (dbxout_type): Never output a cross-ref for + a type whose definition is known. Sun dbx won't accept them. + +Mon Mar 28 12:34:46 1988 Richard Stallman (rms at wheaties.ai.mit.edu) + + * tm-vms.h (TARGET_DEFAULT): Default is PCC alignment. + The VMS compile driver controls the real default. + + * typecheck.c (c_expand_return): Don't ignore return value + when its type is void. + + * final.c (final): Forget the condition codes after an `asm'. + + * typecheck.c (build_binary_op_nodefault): Warn about ptr < 0 + even if not pedantic, but not if traditional. + + * typecheck.c (convert_for_assignment): Don't warn about + pointers volatile * vs nonvolatile * if -fvolatile specified. + + * decl.c (store_parm_decls): Among the old-style parm decls + there can legitiately be other decls! For example, if a parm + is declared `enum {foo, bar} x;', there are decls for `foo' and `bar'. + Don't let anything but a PARM_DECL match a parm name; + pass all the other decls through into the lexical context. + + * jump.c (jump_optimize): When deleting stack adjusts before a + jump-to-return, don't be fooled by intervening NOTEs. + + * tm-sequent.h (PRINT_OPERAND): Output (MEM (MEM (REG))) properly. + * output-ns32k.c (print_operand_address): Output (MEM (REG)) + properly; output stack-pointer as `tos'. + + * flow.c (find_use_as_address): Reject uses within operand 0 + of a ZERO_EXTRACT or SIGN_EXTRACT reference. It's hard to reload + an autoincrement inside these because they can refer to multiple bytes. + + * reload.c (find_reloads): `o' in constraint means any memref + (except auto-increment) is acceptable with reloading. + Braino: Clear BADOP, not BAD. + + * reload.c (push_reloads): Use rtx_equal_p (via macro MATCHES) + when considering reuse of an old reload. Otherwise equal values + may get reloaded into different registers, and two MEMs that + originally matched may fail to match once reloaded. + + * m68k.md (sign_extract and zero_extract insns): + If operand 0 is QI or HImode, don't allow register--only `o' + (except in some bftst patterns where bitpos is < 8). + And change `m' to `o' in all these patterns. + +Sun Mar 27 15:32:54 1988 Richard Stallman (rms at wheaties.ai.mit.edu) + + * expr.c (expand_expr, case CONSTRUCTOR): + Not all aggregates are BLKmode; use the type's mode. + + * gcc.c: Pass -y* to ld. + + * cse.c (struct hash): New member `equivalence_only'. + (insert): Initialize it. + (cse_insn): Set it to 1 when src_eqv is inserted. + When finding cheapest equivalent of something, + skip elts that are marked with `equivalence_only'. + + * decl.c (duplicate_decls): Don't call `layout_type' + if the type is `error_mark_node'. + + * decl.c (implicitly_declare): If decl will be file-scope, + make sure it's a permanent node, and its associated data too. + +Sat Mar 26 15:48:50 1988 Richard Stallman (rms at wheaties.ai.mit.edu) + + * flow.c (insn_dead_p, mark_used_regs): Storing a reg via a + ZERO_EXTRACT or SIGN_EXTRACT is dead if the reg isn't needed afterward. + + * stmt.c (expand_start_function): Set current_function_name + to the name of this function. + * tm-vms.h (MAYBE_VMS_FUNCTION_PROLOGUE): Use current_function_name. + + * expr.c (expand_increment): A SUBREG in op0 can also a be a copy. + + * ns32k.md: Correct range of args for `adjspb' insn. + Use `adjspw' when appropriate. + New pattern for `lprd' insn. + Change some `const_int' predicates to GET_CODE tests. + + * expr.c (expand_call): Eval function before copying args to hard regs. + + * tree.c (make_node, copy_node): Don't get length of a REAL_CST + from tree_code_length. + + * expmed.c (extract_fixed_bit_field): In memory-word case, abort + if tm.h parms say word could fail to be well-aligned. + * tm-ns32k.h: Define STRUCTURE_SIZE_BOUNDARY so they will be aligned. + * tm-vax.h: Define STRUCTURE_SIZE_BOUNDARY since Unix CC seems to. + + * tm-vms.h (CPP_PREDEFINES): Predefine __GNU__ and __GNUC__. + +Fri Mar 25 13:23:27 1988 Richard Stallman (rms at wheaties.ai.mit.edu) + + * gcc.c (main): Handle SIGHUP, SIGTERM. + + * expmed.c (expand_bit_and): Don't clobber OP1 when trying andcb. + +Thu Mar 24 21:59:09 1988 Richard Stallman (rms at wheaties.ai.mit.edu) + + * stmt.c (assign_parms): Get size of BLKmode local from the type, + not the mode. + (expand_function_start): Init frame_offset before calling assign_parms. + +Wed Mar 23 23:50:37 1988 Richard Stallman (rms at wheaties.ai.mit.edu) + + * expr.c (emit_push_insn): When making a move insn, + go via emit_move_insn; else fails to put constants into memory. + +Tue Mar 22 15:45:10 1988 Richard Stallman (rms at wheaties.ai.mit.edu) + + * expr.c (expand_increment): Flush special case for register_operand; + actually call the predicate whatever it is. + + * genemit.c (gen_expand): Make `operands' a local variable, + not a global static one, in the `gen_...' function. + Avoids lossage when one `gen_...' fcn calls another indirectly. + + * genoutput.c (output_epilogue): Don't give printf a null string. + +Mon Mar 21 15:41:42 1988 Richard Stallman (rms at wheaties.ai.mit.edu) + + * expmed.c (store_bit_field) [HAVE_insv]: + Force VALUE1, not VALUE, into a register. + + * expmed.c (store_fixed_bit_field): Width of mask for clearing + the bit-field depends on mode of OP0. + + * ns32k.md (branch and store-flag insns): + Test cc_prev_status, not cc_status. + + * expmed.c (extract_bit_field): Delete unused var `omode'. + + * dbxout.c (dbxout_type, dbxout_tag): Use the main variant + of the specified type. + + * reload.c (find_reloads): When an alternative succeeds without reload, + initialize goal_alternative_matches from this_alternative_matches. + +Sun Mar 20 17:58:00 1988 Richard Stallman (rms at wheaties.ai.mit.edu) + + * tm-sun*.h: Don't predefine `m68k'; Sun's compiler does not. + +Fri Mar 18 13:48:29 1988 Richard Stallman (rms at wheaties.ai.mit.edu) + + * reload.c (find_reloads): Set up goal_alternative_matches + *after* the label `finish'. + + * stmt.c (assign_parms): GET_MODE_SIZE needs a mode, not an rtx. + + * recog.c (constrain_operands): Set global var `which_alternative' + to indicate which of the alternatives this insn matches. + + * typecheck.c (commontype): long int vs unsigned int + gives long unsigned, if long and int are the same width. + +Thu Mar 17 15:39:45 1988 Richard Stallman (rms at wheaties.ai.mit.edu) + + * emit-rtl.c, tree.c: include local version of varargs.h. + + * decl.c (start_function): Clear TREE_EXTERNAL and set TREE_STATIC + here rather than in finish_function. Affects the case of + `extern foo (); static foo (a) {...}' + + * gcc.c: Handle -fnostdinc and -fnostdlib switches in specs. + + * cccp.c (main): Handle -fnostdinc: don't put default dirs + on the chain to be searched. + + * cccp.c (error, warning, error_with_line): No longer print + charpos within file; lineno is enough. + +Wed Mar 16 16:56:36 1988 Richard Stallman (rms at wheaties.ai.mit.edu) + + * expmed.c (expand_inc, expand_dec): Handy new subroutines + to generate x+=y or x-=y, given x and y as rtl. + * expmed.c (expand_divmod): Use them instead of gen_{add2,sub2}_insn. + + * expr.c (emit_move_insn): Return the move insn emitted. + Eliminate the code here to move a DImode or DFmode by pieces. + + * emit-rtl.c (emit_insn): Return-value was wrong if emit_to_sequence; + cannot use `last_insn' in that case. + + * regclass.c, stupid.c, local-alloc.c, global-alloc.c: + Some vars of type HARD_REG_SET should be `register' only + if HARD_REG_SET is a macro (ie a scalar). + + * expr.c (move_block_from_reg): New function, converse of + move_block_from_reg. + * stmt.c (assign_parms): If a BLKmode arrives in regs, + copy to a stack slot using move_block_from_reg. + +Tue Mar 15 17:33:22 1988 Richard Stallman (rms at wheaties.ai.mit.edu) + + * regclass.c (regclass): Don't convert to two-operand insns + unless optimizing. + + * varasm.c (decode_rtx_const, const_hash_rtx): Fix typos. + + * stmt.c (fixup_var_1): Don't alter insn moving VAR to or from + a subreg of a register. + + * cse.c (fold_rtx): Don't fold if result is not LEGITIMATE_CONSTANT_P. + Construct all results in new local variable NEW; then test that + and decide whether to return it or the original rtx. + + * cse.c (cse_insn): When SRC_EQV is non-0 but set[0] has been + cleared, don't insert SRC_EQV in hash table. + + * All insns emitted by a define_expand become part of the SEQUENCE: + * SEQUENCE now contains a vector of insns, not of bodies. + * insn-emit.c (add_insn): If `emit_to_sequence' nonzero, add the + insn to a separate chain, `sequence_first_insn'. + (gen_sequence): Take everything on that chain and make a SEQUENCE. + (emit_insn): Handle SEQUENCE differently since elts are now insns. + (emit_insn_{before,after}): Handle SEQUENCE. + (classify_insn): #if 0. + * genemit.c (gen_expand): emit all the insns, then call gen_sequence + to make the return value. + Define two macros DONE and FAIL for use in a DEFINE_EXPAND: + Use DONE to inhibit emission of the pattern of the DEFINE_EXPAND. + Use FAIL to make the gen_... function return 0. + +Mon Mar 14 12:47:28 1988 Richard Stallman (rms at wheaties.ai.mit.edu) + + * expr.c (expand_expr): Extend the don't-sign-extend-enums hack + to COMPONENT_REF. (See 3 March.) + + * tm-*.h (FUNCTION_ARG, etc.) New argument NAMED + is nonzero for a named arg, zero for an anonymous extra arg. + * expr.c (expand_call): Pass 1 for NAMED if appropriate. + * expr.c (emit_library_call): Pass 1 for NAMED. + * stmt.c (assign_parms): Pass 1 for NAMED. + + * cccp.c: Test __GNUC__, not __GNU__. + + * integrate.c (copy_and_substitute_rtx): + Replacing a MEM parm with the parm value, convert mode if mismatch. + Always use VOIDmode when generating SETs. + Take heed of FIRST_PARM_OFFSET and distinguish arg-pointer + from frame-pointer when they are different. + (expand_inline_function): Handle (RETURN) insns, by creating a + return_label which is output after the integrated code. + + * parse.y (yylex): Condition for ignoring `inline' was backwards. + + * flow.c (mark_used_regs): Ignore STRICT_LOW_PART, so that + an insn that sets STRICT_LOW_PART (and its source values) may be dead. + (propagate_block): Always pass 1 for strict_low_ok to insn_dead_p. + + * optabs.c (emit_unop_insn): Don't make a REG_RETVAL note. + Change above deletes dead STRICT_LOW_PART stores without one. + + * optabs.c (expand_binop, expand_unop): If the library address + is to be put in a pseudoreg, do it here, and make the REG_RETVAL + note point after that. + + * expr.c (emit_library_call): Never defer stack-pops. + Deletion of the library call by flow.c loses if they are deferred. + + * cse.c (cse_insn): Handling of 68k's zero-extend was broken: + it made the actual source and the REG_EQUAL source equivalent. + * If dest is a STRICT_LOW_PART, ignore the actual source and use + the REG_EQUAL source in its place. src_eqv's mode may be different + from src's, so use proper mode in lookups or inserts for src_eqv. + * Don't forget to set src_eqv_elt if src_eqv already has an elt. + * On use_related_value for src_eqv, use src_eqv_elt. + + * toplev.c (main_input_filename): Name of file mentioned in first + #-line in the input. + (compile_file): Pass it to dbxout_init as 2nd arg. + * dbxout.c (dbxout_init): Use 2nd arg to make the N_SO symbol. + * parse.y (check_newline): Store main_input_filename. + + * expr.c (move_block_to_reg): New function, copies a MEM:BLK + to consecutive registers. + (use_regs): New function to emit a USE for each reg in a series. + (expand_call): Use the two new functions when a precomputed BLKmode + arg is passed entirely in regs. + (emit_push_insn): Use move_block_to_reg when PARTIAL > 0. + Also, don't subtract USED from SIZE twice. + Use plus_constant to add ARGS_SO_FAR so can use indexing on stack ptr. + + * varasm.c (assemble_integer_zero): Use rtx 0, not tree 0, + to go with prev change in ASM_OUTPUT_INT. + +Sun Mar 13 01:16:17 1988 Richard Stallman (rms at wheaties.ai.mit.edu) + + * varasm.c (const_hash, compare_constant_1, record_constant_1): + Handle NOP_EXPR and CONVERT_EXPR in constant expressions. + + * optabs.c (expand_binop, expand_unop): When widening operands, + those with VOIDmode (like CONST_INT) may be left alone. + +Sat Mar 12 01:09:24 1988 Richard Stallman (rms at wheaties.ai.mit.edu) + + * varasm.c (assemble_variable): When making a .comm or .lcomm, + round size up to multiple of BIGGEST_ALIGNMENT. + + * obstack.c (_obstack_newchunk): Eliminate fencepost causing copying + to access the word past the end of the existing object. + + * tm-vax.h, tm-ns32k.h: Define {INIT_,}CUMULATIVE_ARGS + and upgrade FUNCTION_ARGS for new calling convention. + + * gcc.c: If -O, define __OPTIMIZE__. + (do_spec_1): %c now scans SIGNED_CHAR_SPEC: define __CHAR_UNSIGNED__ + when appropriate whether or not it is the default. + +Fri Mar 11 16:49:25 1988 Richard Stallman (rms at wheaties.ai.mit.edu) + + * parse.y: Define YYDEBUG. + + * rtl.c (rtx_unstable_p): New function, same as old rtx_varies_p. + * explow.c (stabilize): Use rtx_unstable_p. + * rtl.c (rtx_varies_p): Ignore `unchanging' (undoing previous change + in this function) because `unchanging' doesn't enable cse to compare + the value with any particular constant value. + * rtl.c (insn_store_addr_varies_p): Delete, since not used. + + * hard-reg-set.h (COPY_HARD_REG_SET, etc.) non-scalar case: + Rename and rearrange temp variables to avoid name conflicts with args. + + * regclass.c (reg_class_record): Don't smash class to GENERAL_REGS + and don't exit prematurely, when `r' or `g' is seen. Must merge + GENERAL_REGS with previously determined desired class. + + * expr.c (expand_call) [no PUSH_ROUNDING]: When pushing the arg + block, try to reuse some of the pending_stack_adjust. + + * cse.c: qty_const can now hold values (PLUS frame_pointer integer). + Effect is that storing into a structure doesn't invalidate + mem refs to scalar stack variables via addresses in registers. + (insert): Load such values into qty_const, like true constants. + (fold_rtx): Ignore qty_const if it isn't really a constant. + + * expr.c (expand_expr) VAR_DECL: Copy DECL_RTL before calling + change_address, so it isn't permanently clobbered. + + * stmt.c (fixup_var_refs_1): Make sure the stack slot address + is valid by calling fixup_stack_1 each time it is substituted. + + * stmt.c (fixup_stack_1): Return the altered rtx. + If it's a MEM in the stack, return a copy of it. + + * stmt.c (fixup_stack_slots): #if 0. + * stmt.c (expand_finish_function): Don't call fixup_stack_slots + because fixup_stack_1 is called elsewhere when necessary. + + * reload.c (find_reloads_address): New arg is location of the MEM + whose address is being reloaded. So we copy the MEM if it + is one that can be shared. New arg 0 means no need to copy the MEM. + All callers pass the new arg. + + * stmt.c (assign_parms): Determine parm stack-size from + the DECL_ARG_TYPE, not from the TREE_TYPE. + Else loses when parm is declared `float' but passed as `double'. + + * emit-rtl.c (make_safe_from): Constants are already safe. + Use proper machine mode for temp reg when needed. + +Thu Mar 10 14:35:14 1988 Richard Stallman (rms at wheaties.ai.mit.edu) + + * expr.c (emit_push_insn): Don't pass wrong type to plus_constant + (case where there is no PUSH_ROUNDING). + + * expr.c (expand_call): Round partial[i] down to multiple of + PARM_BOUNDARY before subtracting it from arg size on stack. + Compute these sizes just once and keep them in vector `arg_size'. + * expr.c (emit_push_insn): Handle `partial' uniformly, in accord + with this new convention for how it affects the stack size. + * stmt.c (assign_parms): Round NREGS down to PARM_BOUNDARY likewise. + + * obstack.h (obstack_free macro) [Not __GNUC__ but __STDC__]: + Don't cast result of (obstack_free) to (int); just ignore it. + + * reload.c (find_reloads): Initialize operand_reloadnum. + + * optabs.c (emit_unop_insn): New argument CODE, used to make + a REG_EQUAL note from operand OP0 if more than one insn results. + Also a REG_RETVAL note. + * expr.c (convert_move): Pass CODE arg to emit_unop_insn. + * flow.c (propagate_block): Use insn_dead_p to decide whether + to handle a REG_RETVAL note by skipping some insns. + Always pass 1 for STRICT_LOW_OK for an insn that has a REG_RETVAL note. + Handle case where REG_RETVAL points at an insn that's deleted. + * flow.c (insn_dead_p): New operand STRICT_LOW_OK says an insn + that sets STRICT_LOW_PART may be considered dead. + + * expr.c (expand_expr): Once again canonicalize X-C to X+(-C). + Change on March 1 made it stop doing this. + +Wed Mar 9 01:25:35 1988 Richard Stallman (rms at wheaties.ai.mit.edu) + + * loop.c (move_movables): Don't always mark the moved reg + as equivalent to a constant value: not if it is being cleared + to zero-extend something or if it is used outside the loop. + + * expr.c (move_by_pieces_1): Finish last change. + + * stmt.c (assign_parms): Update stack_args_size properly. + Figure FIRST_PARM_OFFSET when making the stack mem refs. + + * cse.c (insert): Build the related_value lists in the opposite order + so that the oldest element in the chain is the one that follows + the most basic element. + + * expr.c (expand_expr): COMPONENT_REF case: criterion for + converting the the result is if MODE1 (its mode of arrival) isn't + a mode we want. + + * toplev.c (rest_of_compilation): Fix typo setting TREE_ASM_WRITTEN. + +Tue Mar 8 13:18:37 1988 Richard Stallman (rms at wheaties.ai.mit.edu) + + * cse'ing of library calls. + + * expr.h: type `optab' is now a ptr to a struct. + The old contents are now the `handlers' element. + The `code' element gives the RTL code for the kind of expression + this optab makes (PLUS for add_optab, etc.) + Every var formerly declared `struct optab *' is now just `optab'. + + * optabs.c (init_optab, init_optabs): New function to init an optab + and set its `code'. Used in init_optabs. + + * optabs.c (expand_binop, expand_unop): Use the `code' field + to add a REG_EQUAL note to the insn that copies a libcall's + value into a pseudo. Also a REG_RETVAL note pointing at the + first insn for setting up args for the call. + + * cse.c (cse_insn): Process REG_EQUIV and REG_EQUAL datum almost like + another set-src; put the actual src into the equivalence class of that. + + * flow.c (propagate_block): If a dead insn has a REG_RETVAL reg-note, + either ignore or delete all the insns back to the insn the REG_ARG + note points to. + + * local-alloc.c (block_alloc): Don't refrain from allocating a + "constant" register if the constant value isn't ok for an immediate op. + + + * dbxout.c (CONTIN): If DBX_CONTIN_LENGTH is <= 0, do nothing. + + * cccp.c: Extra default include dirs for C++. + * cccp.c (main): For -M, strip dirs from object file name. + + * rtl.c (find_reg_note): New function. + + * expmed.c (store_fixed_bit_field): Don't AND with VALUE + if VALUE's original mode had no more bits than we want. + + * expr.c (emit_library_call): Use varargs. + + * integrate.c (copy_and_substitute_rtx): Recognize arg_pointer_rtx + and translate it just like frame_pointer_rtx. + +Mon Mar 7 00:48:33 1988 Richard Stallman (rms at wheaties.ai.mit.edu) + + * expmed.c (extract_fixed_bit_field): + Shift counts were wrong for narrow MODE in signed case. + Do the sign-extending shifts in the narrowest mode possible. + Reduce big-endian case to little-endian case. + Delete SLOW_ZERO_EXTEND conditional. + + * Implement constants in memory for RISC machines + with limited abilities for immediate args and constant addresses. + + * genoutput.c (output_epilogue): Empty predicate-name + is output as 0 in insn_operand_predicate. + + * expr.c (expand_expr): Change 4th arg to an `enum expand_modifier' + Value EXPAND_SUM corresponds to old nonzero 4th arg. + Value EXPAND_CONST_ADDRESS means ok to return an invalid MEM + whose address is a constant. Changes for this case in ADDR_EXPR, + COMPONENT_REF and ..._DECL. + + * varasm.c (output_arith_constant): Function deleted. + * tm-*.h: (ASM_OUTPUT_{INT,SHORT,CHAR}): 2nd arg is now an RTX + and output it using `output_addr_const'. + * varasm.c (output_constant): Change uses of those macros. + + * varasm.c (init_const_rtx_hash_table): Initialize constant pool + for a new function. Called from `expand_function_start'. + * varasm.c (force_const_mem): Turn a constant rtx into a MEM rtx + which refers to the constant pool. Other new subroutines too. + (force_const_double_mem): Use force_const_mem to make the MEM. + (immed_real_const): No longer record the REAL_CST node in the rtx. + + * explow.c (force_reg): If arg is a constant and not legitimate, + put it in the constant pool with force_const_mem. + Mark the register as equivalent to the constant value. + * expr.c (emit_move_insn): Likewise. + * explow.c (break_out_mem_refs): Use force_reg to put into a reg. + * explow.c (memory_address): Likewise. + * expr.c (expand_expr): ADDR_EXPR case: likewise. + + * expr.c (expand_call): Do force_reg on each register-operand + so it will go through a pseudo and can be cse'd. + + * recog.c (immediate_operand, nonmemory_operand, general_operand): + For constant operands, use LEGITIMATE_CONSTANT_P to decide value. + * tm-*.h: Define LEGITIMATE_CONSTANT_P. + + * reload1.c (reload): Invalid constants can't go in reg_equiv_constant. + +Sun Mar 6 22:49:06 1988 Richard Stallman (rms at wheaties.ai.mit.edu) + + * reload.c (push_reloads): If IN occurs within OUT, + don't reuse an existing input-only reload. Otherwise would lose on + (set (mem (plus R C)) (plus R C1)) if R is available in a spill reg. + + * reload1.c (choose_reload_targets): Don't choose an inherited + reload register that's in use for another reload. + Without this, above change doesn't have an effect. + + * Implement the `unchanging' flag in MEM and REG rtx's. + Also simplify code with a new subroutine `change_address'. + + * emit-rtl.c (change_address): Return new memory ref like an old + one but with specified mode and address. + * expmed.c (extract{,_split,_fixed}_bit_field): Use change_address. + (store{,_split,_fixed}_bit_field): Likewise. + * expr.c (store_expr, expand_expr): Likewise. + + * expr.c (move_by_pieces): Args now memrefs, not addresses. + Eliminate the FROM_VOL and TO_VOL args since the memrefs indicate. + Change the structure `struct move_by_pieces' similarly. + (move_by_pieces_1): Same changes; use change_address. + (emit_block_move, emit_push_insn): Calls to move_by_pieces changed. + + * integrate.c (copy_rtx_and_substitute): Use change_address; + handle ->unchanging field. + + * rtl.c (rtx_varies_p): Regs or memrefs with ->unchanging don't vary. + (copy_rtx): Perserve ->unchanging. + (print_rtx): Print ->unchanging as /u. + + * stmt.c (expand_decl): Set ->unchanging on `const' decls. + (fixup_memory_subreg): Use change_address. + (assign_parms): Record in the rtl which parms are volatile or const. + + * varasm.c (assemble_variable): Set ->unchanging on `const' decls. + (output_constant_def): Always set ->unchanging for constant refs. + + * cse.c (canon_hash): Don't treat a MEM as "in memory" + if its ->unchanging bit is set. + + * loop.c (invariant_p): A REG or MEM with ->unchanging is invariant + (for a MEM, the address must be invariant). + +Sat Mar 5 13:22:11 1988 Richard Stallman (rms at wheaties.ai.mit.edu) + + * genconfig.c (walk_insn_part): DO consider MATCH_DUPs + when calculating MAX_RECOG_OPERANDS. + (gen_expand): define_expand is now different from define_insn. + Compute max # SETs or CLOBBERs for any one sub-insn in a define_expand, + instead of summing them all. And don't count the MATCH_DUPs at all. + + * genemit.c (max_operand_1): Record largest opno in a MATCH_DUP + separately from largest in a MATCH_OPERAND. + (gen_expand): An operand # with only MATCH_DUPs gets + a local variable in the gen_ function we output. + + * integrate.c (save_for_inline): Delete vestige of NOTE_INSN_IS_DECL. + + * cse.c (invalidate): Handle subregs. + (cse_ins, invalidate_from_clobbers): Do call `invalidate' for subregs. + (insert_regs): When assigning one subreg from a like one, + make the two regs equivalent. + (cse_insn): Do call insert_regs when dest is a subreg. + + * expr.c (expand_call): Precompute all args going via hard regs + since even arithmetic could require a library call. + +Fri Mar 4 15:48:17 1988 Richard Stallman (rms at wheaties.ai.mit.edu) + + * stor-layout.c (layout_parms): Function deleted. + * stmt.c (expand_function_start): Don't call it. + + * stmt.c (assign_parms): + stack_args_size counts size of args so far passed on stack. + Use PARM_BOUNDARY when counting it; derive stack offsets from it. + Set current_function_args_size from it. + + When an arg is split between regs and stack, make stack space + for the rest of it, and count it. + In a varargs function, push the last arg onto the stack. + When an arg is passed in regs alone, don't remember a stack slot + for it, and if it needs one, use assign_stack_local. + + Set DECL_OFFSET to the stack offset, or -1 if parm came in regs. + + * expr.c (expand_call): Anonymous args of a varargs function + are always passed on the stack. + + * varasm.c (force_const_double_mem): Copy the MEM rtx + if it may need to be smashed by reloading. + + * genemit.c (gen_expand): define_expand must have nonempty pattern + even though, due to `return' statements in the code-to-run, + that pattern may not be used to generate code. + +Thu Mar 3 17:08:43 1988 Richard Stallman (rms at wheaties.ai.mit.edu) + + * expr.c (expand_expr): If supposed to sign-extend an enum + which is never negative, zero-extend instead (unless SLOW_ZERO_EXTEND). + (store_expr): Likewise. + + * reload.c (find_reloads): 'm' for CONST_DOUBLE: clear BADOP, not BAD. + After force_const_double_mem, do find_reloads_toplev on the MEM. + (find_reloads_address): Handle constant addresses (on machines + that don't allow them). + + * final.c (set_current_gdbfile): New fn, get the gdbfile structure + for specified filename. + (output_source_line): Use set_current_gdbfile for the file. + * varasm.c (assemble_variable): Call set_current_gdbfile + for the declaration's source file, so GDB won't ignore the file. + + * varasm.c (force_const_double_mem): Build a new REAL_CST node + and get its data type from the machine mode of the CONST_DOUBLE. + (immed_real_const): Don't save the REAL_CST tree node. + * typecheck.c (get_floating_type): Return float type for given mode. + + * integrate.c (expand_inline_function): Ignore the (USE (REG...)) + (for the return-register) at the end of the inline function. + After a CALL_INSN, imagine the (SET (REG ...) (REG ...)) for + the return-register if the return-register isn't explicitly used. + +Wed Mar 2 22:08:49 1988 Richard Stallman (rms at wheaties.ai.mit.edu) + + * typecheck.c (build_array_ref): Do default_conversion on INDEX. + +Tue Mar 1 15:49:34 1988 Richard Stallman (rms at wheaties.ai.mit.edu) + + * expr.c (expand_call): Always get a SYMBOL_REF for a fixed function. + If may be alloca, set may_call_alloca. + (gen_call_1): Never put a SYMBOL_REF through `memory_address'; + but if function cse is wanted, just copy it to a register. + If NO_FUNCTION_CSE is defined, never do function cse. + + * expr.c (init_expr): New function, does init_queue and inits + other things. + + * stmt.c (expand_function_start): Call init_expr, not init_queue. + + * optabs.c (expand_binop): Don't clobber OP0 and OP1 + if may call delete_insns_since later. + + * expr.c (emit_library_call): PUSH_ARGS_REVERSE test was backwards. + + * cse.c (cse_insn): Do canon_reg on the size and position operands + in a ZERO_EXTEND or SIGN_EXTEND that is a destination. + + * tm-*.h: Define SLOW_BYTE_ACCESS. + * expmed.c ({store,extract}_fixed_bit_field): + If SLOW_BYTE_ACCESS, get/set all bit fields from full words. + + * combine.c (subst): Simplify + (zero_extend:SI (subreg:QI (zero_extract ...))). + * combine.c (simplify_and_const_int): Simplify + (and (zero_extract ...) (const_int ...)). + + * local-alloc.c (qty_compare{,_1}): Test of qty_phys_sugg was reversed. + (combine_regs): If one pseudo gets two suggested hard regs + (one at birth and one at death), prefer the one from birth + unless we see at death that it's no good. + + * expr.c (expand_expr): Ignore sum_ok unless mode is Pmode. + Don't use force_operand unless sum_ok is set. + +Mon Feb 29 19:23:50 1988 Richard Stallman (rms at wheaties.ai.mit.edu) + + * expr.c (emit_move_insn): When a CONST_DOUBLE needs moving + by pieces, force it into memory, unless it is dconst0_rtx, + in which case each piece is const0_rtx. + (emit_push_insn): Likewise. Also, write code for pushing a + non-BLK mode which has no "mov" insn defined, but only + in the case where there is no PUSH_ROUNDING. + + * expr.c (do_tablejump): Put constant term in address last. + + * toplev.c (xrealloc): On error, call fatal instead of abort. + + * optabs.c (emit_cmp_insn): If genning from tst_optab, + make the operand fit its predicate. + + * optabs.c (expand_float): Don't adjust stack between cmp and jump. + + * optabs.c (expand_binop): Recursive calls can return 0; handle + that event by deleting any preparatory insns. Also don't smash + TARGET when this happens. + + * reload.c (push_reload): If IN != *INLOC, set reload_nocombine. + (combine_reloads): Don't combine an input reload with reload_nocombine. + + * jump.c (jump_optimize): Don't delete stack adjusts unless + EXIT_IGNORE_STACK is nonzero. + * expr.c (clear_pending_stack_adjust): Likewise. + * tm-*.h: When EXIT_IGNORE_STACK is defined, give it `1' as defn. + + * expr.c (expand_call): Initialize args_size. + Don't push a block if args_size is 0. + (emit_library_call): Don't include register-args (or reg-parts + of partial ones) in args_size. + Don't push a block if args_size is 0. + + * expr.c (expand_expr): For DECLs in memory, check the address + validity with memory_address_p, and preserve volatility info. + + * stmt.c (expand_function_end): fixup_gotos needs 2 args. + + * jump.c (mark_jump_label): If INSN is 0, don't set its JUMP_LABEL. + Inside an ADDR_VEC or ADDR_DIFF_VEC, recurse with 0 for INSN. + + * varasm.c (force_const_double_mem): Must zero TREE_CST_RTL + before output, or nothing will happen. + +Sun Feb 28 01:08:53 1988 Richard Stallman (rms at wheaties.ai.mit.edu) + + * optabs.c (emit_unop_insn): Generate and emit an insn + given the insn-code and the two operands (one out, one in). + Can move the operands into registers when needed for various + reasons. + * expr.c (convert_move): Use emit_unop_insn for outputting the + conversion insns. + + * expr.c (emit_library_call): Use arg's nominal mode to choose + a reg to pass it in, not actual mode (which can be VOIDmode). + + * insn-emit.c (emit_insn): If arg is empty SEQUENCE, do nothing. + + * genemit.c (gen_expand): Scan the rtl-pattern for predicates + and machine modes of the operands. + + * m68k.d (dbra patterns): Add HPUX_ASM conditionals. + + * rtl.c (reg_mentioned_p): Use "equal", not "eq", when + REG isn't a register. + * reload.c (combine_reloads): Verify not reg_mentioned_p even if + the input reload's value isn't a register. + + * reload.c (operands_match_p): If successful and 2nd arg + has a pre-increment that matches a non-increment, return 2. + + * reload1.c (reload): At end, clobber a pseudoreg to a MEM + even if it's an out-of-range address. It doesn't affect the + assembler code in this case, but it makes the dbx output correct. + + * recog.c (constrain_operands): When operands_match_p returns 2, + in the constraint alternative that is ultimately successful, + copy the output operand from the input that it matched + so that the assembler insn that is output shows the pre-increment. + +Sat Feb 27 15:16:47 1988 Richard Stallman (rms at wheaties.ai.mit.edu) + + * combine.c (subst): When optimizing + (set (zero_extract ...) (and (zero_extract ...) const)) + must arrange to have 1's, not 0's, shifted into low bits of const. + + * decl.c (grokdeclarator): When return-type defaults to int, + don't warn, just set warn_about_return_type. + (start_function): See that variable and warn, after starting function. + + * toplev.c (count_error): No longer print newline if not quiet. + (report_error_function): If not quiet, print a newline if + printing anything, and don't print the function name. + + * reload1.c (choose_reload_targets): + Fix the loop that checks for consecutive available spill regs. + Set `have_groups' nonzero if any reload wants a group. + In that case, for non-group reloads, prefer a reg that can't be in + group, or else one that has only one available neighbor. + + * reload1.c (reload): Find separately the max need for each class + for single registers, groups of registers, and single registers + not in any group. (The last one counts non-group reloads + in insns that have at least one group reload.) + Then make sure enough of each kind are found. + + * expmed.c: Now needs flags.h and recog.h (therefore insn-config.h). + + * expmed.c (store_bit_field): + Delete redundant protect_from_queue. + Force VALUE out of memory if -fforce-mem. + If insv's predicate for VALUE wants a register, put it there. + + * expmed.c (extract_bit_field): + Force TARGET out of memory if -fforce-mem. + If insv's predicate for TARGET wants a register, put it there. + +Fri Feb 26 00:12:48 1988 Richard Stallman (rms at wheaties.ai.mit.edu) + + * reload1.c (eliminate_frame_pointer): Don't check for pushes + unless PUSH_ROUNDING is defined. + + * reload.c: Don't define REG_OK_FOR_{INDEX,BASE}_P + (since the tm file is supposed to do it). + + * expr.c (emit_push_insn, expand_call): + Don't use PUSH_ROUNDING if it's not defined. + + * expr.c (preexpand_calls): Do nothing for constants and decls. + + * expr.c (expand_call, emit_library_call): When PUSH_ROUNDING + is not defined, use ROUND_CALL_BLOCK_SIZE to round the size + of the block of arguments. + + * expr.c (expand_call): Don't count register-args in ARGS_SIZE. + + * rtl.h, emit-rtl.c: Create static_chain_incoming_rtx + and struct_value_incoming_rtx. + * stmt.c (expand_function_start): Use ..._incoming_rtx where needed. + + * expr.c (expand_call): Use new macros INIT_CUMULATIVE_ARGS, + CUMULATIVE_ARGS and FUNCTION_ARG_ADVANCE to update data + on args scanned so far. + (emit_library_call): Likewise. + * stmt.c (assign_parms): Likewise. + * tm-spur.h, tm-m68k.h: Define these macros. + + * rtl.h (NUM_MACHINE_MODES): NUM_MACHINE_MODE renamed. + * rtl.c, genrecog.c: Change places it is used. + + * cccp.c (output_line_command): line_cmd_buf should be chars, not ints. + +Thu Feb 25 13:33:29 1988 Richard Stallman (rms at wheaties.ai.mit.edu) + + * genemit.c (gen_expand): Don't lose if pattern is empty-vector. + + * genconfig.c (gen_insn): Don't lose if pattern is empty-vector. + + * expr.c (expand_expr): For COMPONENT_REF, don't convert to tmode + unless the mode we get is unacceptable. + + * loop.c (scan_loop, move_movables): New field `partial' is 1 for + zero-extending clr insn; don't make the reg invariant when it's moved. + + * optabs.c (expand_unop, expand_binop, emit_cmp_insn): + mode-argument to predicates was missing. + + * optabs.c (expand_binop): If gen-function returns 0, this means + the insn wasn't available. + + * reload.c (find_reloads): Don't make optional reloads for operands + that match other operands. + + * reload.c (combine_reloads): Reject optional output reload. + + * reload.c (find_equiv_reg): Know that CALL_INSNs clobber memory. + + * typecheck.c (build_binary_op_nodefault): + If doing a short shift, leave the shift-count as a fullword. + +Tue Feb 23 14:43:46 1988 Richard Stallman (rms at wheaties.ai.mit.edu) + + * combine.c (subst): Count, in n_occurrences, # times FROM is seen. + (try_combine): Refuse to combine x=*y++ into z = x*x. + + * loop.c (invariant_p): Frame pointer and arg pointer are invariant. + (move_movables): Don't forget to set ->done! + When moving the matching movables, don't forget to set n_times_set. + + * expmed.c (expand_shift): Reorder strategies for logical shift; + if widening, try all ashift strategies before extzv. + + * typecheck.c (build_binary_op_nodefault): + Always return error_mark if either operand is one. + + * recog.c (nonmemory_operand): New predicate. + + * optabs.c (expand_unop, expand_binop, emit_cmp_insn): + Don't treat `register_operand' as special. Apply the predicate + to the rtx; if the predicate fails, use a register instead. + +Mon Feb 22 22:37:32 1988 Richard Stallman (rms at wheaties.ai.mit.edu) + + * expr.c (expand_calls): Preexpand all calls in arguments + that are passed in regs before copying any of them into the regs. + + * expr.c (emit_push_insn): Three more args. + EXTRA for extra space to leave. + ARGS_ADDR and ARGS_SO_FAR for using move-insns on machines + that lack true push insns. + + * expr.c (emit_library_call, expand_call): + Use the new arguments of `emit_push_insn'. + + * expr.c (PUSH_ARGS_REVERSED): defined if handle args last-to-firs. + +Sun Feb 21 12:17:59 1988 Richard Stallman (rms at wheaties.ai.mit.edu) + + * toplev.c (rest_of_compilation): Set TREE_ASM_WRITTEN + when a function is really output as assembler code. + Don't do inlining of a function that is already made inline; + instead, output it as assembler code, because this must be + the second call for that function. + + * decl.c (finish_compilation): Delete it. + * toplev.c (compile_file): Output pending inline functions at the end + in the same way tentative-defined variables are output. + + * emit-rtl.c (restore_reg_data): New fn: given chain of insns, + restore emit-rtl's data on registers from the regs they use. + + * integrate.c (output_inline_function): Use restore_reg_data. + (fill_regno_reg_rtx_as_needed): Now restore_reg_data_1 in emit-rtl.c. + + * tree.c (build_decl): Function moved from decl.c. + No longer set attributes of function decls specially. + + * decl.c (implicitly_declare, builtin_function, grokdeclarator): + Don't expect build_decl to set attributes of FUNCTION_DECL. + + * tree.c (preserve_data): New fn, make all data now on + maybepermanent_obstack last permanently. + + * cse.c (cse_insn): Remove a STRICT_LOW_PART from the dest rtx + before putting it in the hash table. + + * symout.c (symout_block): Fix the args to `symout_block_symbols'. + +Sat Feb 20 00:07:52 1988 Richard Stallman (rms at wheaties.ai.mit.edu) + + Start of changes for inline functions. + Changes received from Tiemann, then slightly rearranged for simplicity. + + * integrate.c: New file (Tiemann's rtl2.c). + * integrate.c (function_cannot_integrate_p): + New fn, only checks whether current fn is safe and good to inline. + Returns an error message string if not. + + * expr.c (current_args_size): Var made static. + (store_expr): Fn no longer static. + (stack_pointer_rtx): Use this var for all refs to the stack pointer. + (struct_value_rtx, static_chain_rtx): Likewise + + * expr.c (expand_call): Detect calls to integrable functions + and integrate them. + **If fn is not named "alloca" then assume it is not `alloca'. ** + + * emit-rtl.c (max_label_num): New fn, returns number for next label. + (get_first_label_num): New fn, returns first label of current fn. + (init_emit): Save first label number of this fn. + + * emit-rtl.c (gen_inline_header_rtx): New fn, make an INLINE_HEADER. + + * emit-rtl.c (emit_declaration): New fn to emit new kind of NOTE. + + * emit-rtl.c (init_emit_once): New fn. + Move inits of unique rtl objects here, from init_emit. + + * decl.c (finish_compilation): New fn to compile separately + any nonglobal inline functions that need to be addressable. + + * decl.c (grokdeclarator): Handle `inline' kwd among the declspecs. + Set TREE_INLINE if it's safe. + + * decl.c (finish_function): If fn was inlined, don't clear + the DECL_ARGUMENTS or DECL_RESULT or DECL_INITIAL. + + * gen*.c: Provide rtl_obstack, not current_obstack. + + * rtl.c (rtl_obstack): Variable: ptr to obstack to use for making rtl. + * rtl.c (rtx_alloc, rtvec_alloc): Use that obstack. + * rtl.c (copy_rtx): Copy the `integrated' flag. + * rtl.c (print_rtx): Print that flag as `/i'. + + * rtl.def: New rtx code INLINE_HEADER. + + * rtl.h (struct rtx_def): Add `integrated' field. + * rtl.h: Define macros for fields in an inline_header rtx. + + * stmt.c (max_parm_reg_num, get_first_function_insn): + New fns, return info on parm regs and the insns that init them. + + * stmt.c (expand_decl): Simplify with new local `type'. + + * stmt.c (stack_pointer_rtx): Replace all refs to stack pointer + with this shared rtx. + * stmt.c (struct_value_rtx): Likewise. + + * stmt.c (expand_start_function): Call init_pending_stack_adjust + instead of clear_pending_stack_adjust. + If not using a return-label, set `return_label' to 0. + + * stmt.c (expand_null_return, expand_end_function): + Call clear_pending_stack_adjust unconditionally. + + * expr.c (clear_pending_stack_adjust): Move the conditionals here. + For now, this fn is a no-op, since it's not safe in an inline fn + and the stack adjusts are deleted by jump.c in if optimizing. + + * expr.c (init_pending_stack_adjust): New fn. + +Fri Feb 19 14:30:13 1988 Richard Stallman (rms at wheaties.ai.mit.edu) + + * toplev.c (main): Decode -finline-functions, -fkeep-inline-functions. + + * toplev.c (rest_of_compilation): + At start, save the rtl if function should be inline. + For inline function, if we don't yet know whether it should be + compiled on its own, don't do so. + + * toplev.c (compile_file): Clear, and later print, `integration_time'. + Call `init_emit_rtl' when starting. + Call `finish_compilation' at the end. + + [Add an extra arg to the error and warning functions?] + + * tree.c ({push,pop,clear}_momentary): + Change momentary_stack from a char ** to a struct momentary_level *. + + * tree.c (build_pointer_type): Put temporary type in `saveable_obstack' + * tree.c (build_type_variant): Likewise. + * tree.c (make_node): Likewise. Also put decls and LET_STMTs there. + * tree.c (type_hash_canon): Free a temporary type in `saveable_obstack' + + * tree.c (perm_tree_cons): Like `tree_cons' but on perm. obstack. + + * tree.c (init_tree, {{end_,}temporary,permanent}_allocation): + Handle `maybepermanent_obstack' and `saveable_obstack' and + `rtl_obstack'. + + * tree.h (TREE_INLINE): New attribute macro. + * tree.h (DECL_SAVED_INSNS, DECL_FRAME_SIZE): + New components in a FUNCTION_DECL. + Delete the `unused` slot in a `struct tree_decl'. + + * typecheck.c (mark_addressable): Set TREE_ADDRESSABLE + even in FUNCTION_DECLs. + + * typecheck.c (build_function_call): + If function is a FUNCTION_DECL, avoid setting TREE_ADDRESSABLE + when taking its address. + + * parse.h: Define RID_INLINE. + * parse.y: Define keyword `inline'; set up ridpointers for it. + (yylex): Don't recognize `inline' of -fno-asm or -ftraditional. + + * flags.h: New vars flag_inline_functions + and flag_keep_inline_functions. + + End of changes for inline functions. + + * tree.c (convert): If EXPR's type is an error_mark, return error_mark. + + * Makefile (install): Don't strip the executables. + + * jump.c (delete_insn): Deleting a label's target + can delete either NEXT and PREV! So must search for a + following nondeleted insn to return. + + * typecheck.c (build_function_call): Typo in validating + data type of function. + + * genoutput.c (gen_expand): Must create a `struct data' even + for a define_expand, so we can output the proper insn_gen_function + and leave zeros in the other tables. + + * loop.c (scan_loop): Replace the code for handling zero-extends + with unconditional code that checks for a pair of insns. + + * m68k.md: Do zero-extend using define_expand to generate + a pair of insns, to set all to zero and then copy the low part. + +Thu Feb 18 15:54:00 1988 Richard Stallman (rms at wheaties.ai.mit.edu) + + * emit-rtl.c (emit_insn): If arg is a SEQUENCE, emit several insns. + * emit-rtl.c (classify_insn): Given an RTX, return the rtx-code for + an insn containing it: CODE_LABEL, INSN, JUMP_INSN or CALL_INSN. + + * rtl.def: New RTX types DEFINE_EXPAND and SEQUENCE. + * gen*.c: Handle DEFINE_EXPAND. Only genemit.c does real work. + + * make.com, make-cc1.com, make-cccp.com: New, VMS command files. + + * tm-vms.h: New file, used as tm.h to generate VMS code. + + * tm-vax.h (FUNCTION_PROLOGUE): Turn off no bits in the mask; + let call_used_registers alone control this. + Call MAYBE_VMS_FUNCTION_PROLOGUE, and define that as no-op. + + * tm-vax.h (TARGET_VAXC_ALIGNMENT): New target-flag bit. + BIGGEST_ALIGNMENT, EMPTY_FIELD_BOUNDARY and POINTER_BOUNDARY use it. + + * varasm.c (assemble_function): Use ASM_DECLARE_FUNCTION_NAME + if it is defined. + + * varasm.c (assemble_variable): On an external, + use ASM_OUTPUT_EXTERNAL if defined. Default is do nothing, as before. + + * toplev.c: + Use FATAL_EXIT_CODE and SUCCESS_EXIT_CODE. + Don't include time.h and resource.h on VMS. + (main) Define __VERSION__ if not already defined. + Conditionalize setrlimit on RLIMIT_STACK. + Test __GNUC__, not __GNU__. + Don't do `ps v' on VMS. + (gettime): Conditional code for VMS. + + * gcc.c: Define __GNUC__ as well as __GNU__. + __GNU__ will be deleted in a future version. + + * symout.c (symout_finish) [VMS]: Don't refer to `getwd' on VMS. + * symout.c (symout_init) [VMS]: Fatal error; GDB syms not supported. + + * parse.y (yylex): Handle DOLLARS_IN_IDENTIFIERS. + + * genoutput.c (gen_insn): Workaround for VMS printf %s bug. + + * gen*.c: Include config.h. Whenever exiting, use + SUCCESS_EXIT_CODE or FATAL_EXIT_CODE. + + * config-*.h: Define SUCCESS_EXIT_CODE and FATAL_EXIT_CODE. + * config-vms.h: New file, mostly like config-vax.h. + +Wed Feb 17 13:35:34 1988 Richard Stallman (rms at wheaties.ai.mit.edu) + + * cccp.c: VMS support from Kashtan. + Some #include files are conditional. + Use file_size_and_mode instead of fstat. + When reading file contents, the size we get from that + is just an upper bound; don't assume it must match. + Replacement definitions of read and write for VMS. + Different default include directories. + Conditionalize the setrlimit code on RLIMIT_STACK. + Use SUCCESS_EXIT_CODE when exiting if no errors; + both that and FATAL_EXIT_CODE are not #defined if already defined. + + Treat $ as an identifier-character if DOLLARS_IN_IDENTIFIERS. + Rename the `delete' function as `delete_macro' + to avoid VMS name conflict. + + * cexp.y: Treat $ as an identifier-character if DOLLARS_IN_IDENTIFIERS. + + * stmt.c (fixup_memory_offset): Do big-endian compensation + only within a word, not for DImode vs SImode. + + * stmt.c (fixup_var_refs): Don't fix up the insn to load the var + from its own stack slot; delete it instead. + + * tm-ns32k.h (MODES_TIEABLE_P): DImode is like DFmode. + + * tree.c (MAX_HASH_TABLE): 1009 (more prime) instead of 1008. + + * decl.c (duplicate_decls): If merged type is OLD's type, + keep OLD's DECL_SIZE and DECL_SIZE_UNIT. + + * gen*.c (xmalloc, xrealloc): Call `fatal' if memory is full. + + * reload1.c (choose_reload_targets): If a mode doesn't fit the + reload register, and the insn is an ASM_OPERANDS, ignore the reload. + Otherwise, final would crash. + + * expmed.c (expand_shift): Two new strategies for lshr on short/char: + widen and do ashr, or widen and do extzv. + + * vax.md (peepholes): Use dead_or_set_p to check for eliminable + intermediate result, rather than requiring a match with final result. + + * local-alloc.c (block_alloc): Testing frame_pointer_needed is + enough; no need to test FRAME_POINTER_REQUIRED, etc. + * global-alloc.c (find_reg): Likewise. + * reload1.c (reload): Likewise for flag_omit_frame_pointer + + * jump.c (delete_insn): If not `optimize', don't complain + about finding an already-deleted insn in the chain. + +Tue Feb 16 17:14:54 1988 Richard Stallman (rms at wheaties.ai.mit.edu) + + * final.c: Don't define N_SOL and N_SLINE if already defined. + + * final.c (output_source_line): + Typo calling ASM_OUTPUT_SOURCE_FILENAME. + + * flow.c (INSN_VOLATILE): fix a typo. + +Fri Feb 12 16:48:16 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu) + + * final.c (final): for `asm' without operands, output literally. + +Thu Feb 11 12:44:41 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu) + + * symout.c (symout_record_fields): Handle nameless fields. + * symout.c (symout_record_field_names): Likewise. + + * typecheck.c (require_complete_type): `void' is a complete type. + * typecheck.c (build_function_call): Don't complain if result is void. + + * tm-hp9k320.h: Change definition of ASM_SPEC to +X, not -X. + + * cccp.c (main): Expected object file name for foo.cc is foo.o. + +Wed Feb 10 16:04:58 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu) + + * reload1.c (reload): Initialize `regmask' to zero. + Class number is in I, not in CLASS, when setting its elements. + Don't let J+K be too large. + + * reload1.c (potential_reload_regs): Make it a `short' + since that can't be unsigned. + + * cccp.c (warning): New function, called like `error'. + * cccp.c (do_define): Make redefinition just a warning. + +Tue Feb 9 13:28:00 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu) + + * decl.c (grokdeclarator): Don't be fooled by ERROR_MARK as a declspec. + + * toplev.c (compile_file): Strip final .c or .co from .sym file name. + + * gcc.c: When running `as', specify the .sym file if -gg. + +Mon Feb 8 11:26:26 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu) + + * expmed.c (store_fixed_bit_field): Don't try gen_lowpart on VALUE + if it's a subreg since it might lose; use convert_to_mode instead. + + * tm-hp9k320.h: Define TARGET_MEM_FUNCTIONS. + * expr.c (emit_block_move, emit_push_insn, clear_storage): + If TARGET_MEM_FUNCTIONS, generate calls to memcpy and memset + instead of bcopy and bzero. + * optabs.c (emit_cmp_insn): Likewise for memcmp vs bcmp. + + * stmt.c (expand_goto): New temp var to avoid RT/PC compiler bug. + +Sun Feb 7 12:20:23 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu) + + * flow.c (mark_used_regs, mark_set_regs): + Handle hard regs in multiword modes: set the bits for each + distinct register-number that makes up the multiword mode. + Necessary because function arg registers can inevitably + live across basic blocks. + + * cse.c (canon_hash): Function arg and value registers no longer + considered volatile, because flow should now handle the code that + can result from cse'ing them. + + * cse.c (make_regs_eqv): Abort if OLD is invalid. + * cse.c (reg_invalidate): Abort if reg already invalid has eqvs. + +Sat Feb 6 16:25:32 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu) + + * gcc.c (main): Specific error msg if no input files. + +Fri Feb 5 17:56:00 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu) + + * stmt.c (expand_decl, put_var_into_stack, assign_parms): + Set in_struct on a MEM if the variable is an aggregate or union. + * varasm.c (assemble_variable): Set in_struct on aggregate vars. + +Thu Feb 4 11:52:30 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu) + + * m68k.md (movsf): Correct two fmove.x to fmove.s. + + * expmed.c (extract_fixed_bit_field): + Must always generate an `and' to mask the bitfield + unless its width is the same as the output machine mode. + + * version 1.18 released. + +Wed Feb 3 08:41:20 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu) + + * fold-const.c (fold): Convert EXPR's operands before returning them. + +Tue Feb 2 15:35:18 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu) + + * reload.c (find_reloads_address_1): + + * typecheck.c (default_conversion): Handle COMPOUND_EXPR arrays. + +Mon Feb 1 18:53:05 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu) + + * ns32k.md: operand 0 of all unsigned divide/modulus insns + is now register_operand. + + * stdarg.h: Make va_list be char *, not char *[1]. + Latest draft doesn't say it must be an array type. + +Sun Jan 31 11:14:07 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu) + + * flow.c (find_basic_blocks): Add temp var to avoid Sequent + compiler bug. + + * tm-ns32k.h (GO_IF_LEGITIMATE_ADDRESS): Don't allow pushes or pops + since there are special insn patterns for them. + Resubroutinize and add temp vars to make expressions smaller. + * ns32k.md: Add a few more special stack insns; now there are enough. + + * tm-sequent.h: Definitions of DBX_NO_XREFS and DBX_CONTIN_LENGTH. + + * reload1.c (choose_reload_targets): Handling of reload_strict_low + is needed for input reloads as well as output, since a strict_low_part + operand is normally a read-write operand. + + * reload1.c (reload): The mode a reload needs is the wider of + the input and output modes--just as it is in choose_reload_targets. + + * reload.c (find_dummy_reload): If IN and OUT have different widths + and one of them exceeds a word, don't find any dummy reload. + + * toplev.c (compile_file): Allocate enough space for .jump2 filename. + +Sat Jan 30 10:35:46 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu) + + * output-ns32k.c (print_operand_address): + Print addresses of the form C1+(N*REG+C2) which currently + are accepted as legitimate memory addresses. + + * tm-sequent.h: Simple bugs in PRINT_OPERAND, TARGET_DEFAULT + and SEQUENT_ADDRESS_BUG. + + * gen*.c: Must explicitly exit; returning from `main' fails + to indicate nonzero status due to bug in Unix. + + * parse.y (check_line_number): Ignore entire line of unrecognized + #-directive; no error if it is `pragma'. + +Fri Jan 29 06:46:01 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu) + + * genrecog.c, genextract.c, genoutput.c: Define bcopy and/or bzero. + + * cccp.c (do_define): Make defn->argnames long enough in no-args case. + + * reload1.c (reload): Make basic_block_needs 0 until after the + frame pointer reg is spilled, so that ALL pseudos in it are spilled. + + * typecheck.c (truthvalue_conversion): + Strip a NOP_EXPR only if it extends, not if it truncates. + (build_unary_op): For TRUTH_NOT_EXPR, call invert_truthvalue + to simplify. + + * Fixes for HPUX support from cph: + * tm-hp9k320.h: Correct names of floating-point registers. + Fix typos in ASM_OUTPUT_OPCODE; also convert `fmove' to `fmov'. + * Makefile (comments for HPUX): + cph says -Wd,-X isn't needed in CFLAGS, nor -lBSD in CLIB. + Also that -g can't be used in CFLAGS with HP's pcc. + * conf-hp9k320.h: New file, like config-m68k.h but with + #defines for the bstring functions. + * m68k.md: Add else-clauses to the HPUX_ASM conditionals on cmp insns. + Reinsert mistakenly-deleted MOTOROLA conditionals around + some OUTPUT_JUMPs. + +Thu Jan 28 09:51:41 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu) + + * jump.c (jump_back_p): If TARGET is unconditional, return 0. + +Wed Jan 27 04:18:29 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu) + + * combine.c (subst): Simplify (plus (plus x c1) c2). + + * expr.c (emit_push_insn): Don't use small-block push-insns for BLKmode + when one of them would be affected by PUSH_ROUNDING. + Instead, make all the space and then copy. + * expr.c (expand_call): Don't apply PUSH_ROUNDING if BLKmode. + + * Allow `asm' with operands to be marked volatile. + * cse.c (canon_hash): Don't record ASM_OPERANDS that has `volatil'. + * loop.c (invariant_p): ASM_OPERANDS with `volatil' can't be invariant. + * flow.c (volatile_refs_p): Note ASM_OPERANDS that are volatile. + * stmt.c (expand_asm_operands): New arg VOL; mark ASM_OPERANDS as vol. + * typecheck.c (c_expand_asm_operands): New arg VOL. + * parse.y: allow a TYPE_QUAL after ASM. + + * Make cse handle `asm' with operands: + * cse.c (canon_hash): Hash string operands by contents, not address. + * cse.c (exp_equiv_p): Compare string operands with strcmp. + * rtl.c (rtx_equal_p): Compare string operands with strcmp. + + * decl.c (init_decl_processing): Once sizetype is set, + correct the type of the sizes of types already made. + + * cccp.c (do_defines): Don't reject #define foo{a}. + +Tue Jan 26 04:53:16 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu) + + * reload.c (find_reloads): Now that `asm' is limited to + MAX_RECOG_OPERANDS, eliminate dynamic allocation of `constraints' + and `constraints1', and go back to `recog_operand' instead of + `operands'. + + * typecheck.c (c_expand_asm_operands): New fn to handle `asm' for C. + Calls expand_asm_operands, and handles output operands that + the other function cannot handle. + + * parse.y: Call that function. + + * stmt.c (expand_asm_operands): Error if too many operands. + #include insn-config.h to get MAX_RECOG_OPERANDS. + + * expr.c (expand_assignment): Use store_field to handle + structure fields and array elements. + + * output-m68k.c (output_move_double): PUSHOP and POPOP were swapped. + Handle insns that push an sp-relative address onto sp; + these can arise with -fomit-frame-pointer. + BUG? Do unoffsetable mem refs using sp and fp lose? + + * m68k.md (movdi,movdf): Allow unoffsetable mem refs + only if the other operand is a register. + + * m68k.md (zero_extendqisi2): SGS conditionals deleted. + Supposedly the MOTOROLA syntax works for those addresses. + + * typecheck.c (default_conversion): + If flag_traditional, preserve unsignedness when promoting ints, + and promote float to double. + + * typecheck.c (build_binary_op_nodefault): + Allow comparisons between pointers and ints. + If not -traditional, warn about them. + +Mon Jan 25 02:11:18 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu) + + * expmed.c ({extract,store}_split_bit_field): + Functions {extract,store}_split_reg_bit_field now work for memory + also, and therefore are renamed. + * ({extract,store}_fixed_bit_field): Call those fns when a field + is split across two words. + Also, preserve the `volatil' bit on memory refs. + + * output-m68k.c (output_move_double): Handle nonoffsetable mem refs. + * m68k.md: Relax constraints on movdi, movdf. + + * decl.c (init_decl_processing): Define `int' and `char' first. + Set `sizetype' explicitly. + + * stmt.c (fixup_var_refs_1): May not just return when a SET + doesn't have VAR as its src or dest. + + * varasm.c: Don't include c-tree.h. + + * decl.c (build_struct): Split this function into three: + `xref_tag', `start_struct' and `finish_struct'. + `xref_tag' subsumes `xref_enum'. + + * parse.y (structsp): When parsing `struct foo {...}', define the tag + as a cross-ref before parsing the components. Use the three new fns. + + * regclass.c (regclass): Recognize new-format ASM_OPERANDS insns + with `asm_noperands', and scan their operands as usual. + + * cse.c: In numerous functions such as canon_hash, rtx_cost, etc. + that do tree-walk on rtx, handle vectors of subexpressions. + + * loop.c (invariant_p): Likewise. + + * jump.c (delete_insn): Two bugs: + If insn already deleted, return the first following nondeleted. + Deleting a jump's label can delete NEXT. Make sure return value + is always the first insn following INSN and not yet deleted. + +Sun Jan 24 02:27:49 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu) + + * rtl.def (ASM_OPERANDS): Change the rtl expression of an + `asm' with operands so it looks like this for one output operand: + (set OUTPUT (asm_operands:OUTPUTMODE INSNSTRING OUTPUTCONSTRAINT + 0 INPUTS INPUTCONSTRAINTS)). + and like this for multiple outputs: + (PARALLEL [ + (set OUTPUT0 (asm_operands:OUTPUTMODE INSNSTRING OUTPUTCONSTRAINT + 0 INPUTS INPUTCONSTRAINTS)). + (set OUTPUT1 (asm_operands:OUTPUTMODE1 INSNSTRING OUTPUTCONSTRAINT1 + 1 INPUTS INPUTCONSTRAINTS))]) + + * parse.y: Change parsing of `asm' to distinguish input and output + operands. Separate them with colon; separate the string with colon. + + * stmt.c (expand_asm_operands): Receive inputs and outputs separately. + Generate the new rtl format. + + * recog.c (asm_noperands, decode_asm_operands): New fns + for extracting the operands and constraints from these insns. + + * final.c (final): Recognize and output the new rtl format + using those new functions. + + * reload.c (find_reloads): Recognize and get constraints + from the new rtl format using those new functions. + New variable `operand_modes' holds the machine modes of the + operands, obtained one way for ASM_OPERANDS insns and another + for other insns. + + * rtl.c (note_stores): Calling convention + is changed: the first arg FUNCTION now receives as its 2nd arg + 1 if clobbering, 0 if setting. Used to be the CLOBBER or SET rtx. + + * local-alloc.c (reg_is_set): This fn is called from note_stores; + change its arguments. + + * tm-m68k.h (FIXUP_FRAME_POINTER_ADDRESSES): + Use frame_pointer_rtx to recognize intended frame-pointer refs + and not recognize pseudo-regs that were allocated to the frame + pointer register. + + * emit-rtl.c: All refs to frame pointer use a single rtx, in + frame_pointer_rtx. Likewise arg_pointer_rtx for the arg pointer. + If they are the same register, these are the same rtx. + Initialize them in init_emit. + * rtl.h: Declare these vars. + + * stmt.c (assign_parms, assign_stack_local): Use those rtx's. + +Sat Jan 23 00:32:10 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu) + + * reload.c (find_reloads): Don't combine_reloads if `&' constraint + was used. + + * parse.y: Parse `asm' with operands. + * stmt.c (expand_asm_params): New fn: generate an ASM_OPERANDS for + `asm' with operands. + * final.c (final): Output an ASM_OPERANDS insn-body. + * regclass.c (regclass): Ignore ASM_OPERANDS, like ASM_INPUT. + + * reload.c (find_reloads): Handle reloading of ASM_OPERANDS. + The number of operands can no longer be bounded. + For example we can't always put the operands in recog_operands. + + New locals OPERANDS and OPERAND_LOCS point to alloca'd vectors of + operands and their locations. New locals CONSTRAINTS and CONSTRAINTS1 + hold alloca'd vectors of constraints. + + Unfortunately this isn't enough; every vector with length + MAX_RECOG_OPERANDS needs to be dynamically allocated. + Would this be too slow? For now, a cheap "solution" is to delete + any insn that has too many operands. + + * rtl.def: Delete VOLATILE, UNCHANGING and UNDESCRIBED. + Add ASM_OPERANDS. + + * regclass.c (reg_class_record): Delete ref to UNCHANGING. + * loop.c (invariant_p): + * rtl.c (rtx_varies_p): + + * cccp.c: Define __VERSION__. + + * decl.c (shadow_tag): TYPE_NAME doesn't work to get the tag-name + of a struct, so use new function lookup_tag_reverse. + * decl.c (lookup_tag_reverse): Given a type, return its tag name. + + * symout.c (symout_source_file): Output one `struct source'. + * symout.c (symout_lines): Output all of them, and the sourcevector. + * gdbfiles.h: New file for communication between final.c and symout.c. + + * final.c (output_source_line): New arg WRITE_SYMBOLS says write + new GDB-format linenumber info. Assigns a filenum to each source + file name and keeps track of the correspondence. + + * cccp.c (do_include): Output the -M info after searching the dirs; + include the actual dir name. Don't generate "./" for current dir. + +Fri Jan 22 04:10:10 1988 Richard Stallman (rms at frosted-flakes) + + * tm-news800.h: Delete override of INDIRECTABLE_1_ADDRESS. + Output is faster if it doesn't use 32-bit displacements. + + * reload.c (combine_reloads): New function. + If possible, find an input reload + and an output reload that can be turned into one input-output reload. + The old output-reload is marked as inoperative: reload_out + and reload_in both zero. This is called from find_reloads. + + * reload1.c (reload, choose_reload_targets): Ignore inoperative + reloads. + + * Print warnings for variables that could be clobbered by `longjmp'. + * expr.c (expand_call): Generate a NOTE_INSN_SETJMP whenever + `setjmp' or `_setjmp' is called. + * flow.c (propagate_block): When NOTE_INSN_SETJMP is seen, + record the live regs in `regs_live_at_setjmp'. + * stmt.c (uninitialized_vars_warning): Warn about vars that have regs + that are set more than once and are marked in `regs_live_at_setjmp'. + Works through function `regno_clobbered_by_longjmp'. + * rtl.h: Define NOTE_INSN_SETJMP. + + * genrecog.c (try_merge_2): When enforce_modes, keep all the + alternatives segregated by modes and keep the modes in numerical order. + * genrecog.c (write_tree): Make conditions for switch-on-modes + know what difference enforce_mode makes. + +Thu Jan 21 00:12:35 1988 Richard Stallman (rms at frosted-flakes) + + * tm-ns32k.h: Use Stein's definitions of PRINT_OPERAND{,_ADDRESS}; + move the Sequent definitions info tm-sequent.h. + Handle %$ in both old and new PRINT_OPERAND. + Define CPP_PREDEFINES. + + * ns32k.md: Merge some features from Jan Stein's port: + strict_low_part insns, smart output of booleans with small + constant args, acbd insns generalized for other increments. + Use %$ wherever there is an explicit immediate. + Fix shortcomings of adjsp insns: use adjspd in general, + and use adjspb in all the cases that allow it. + Don't bother explicitly clearing CC_REVERSED. + For tstsf/tstdf, output the floating-zero constants + using {f,d}const0_rtx. + + A problem still remains, which is that the Sequent and the + other ns32k assembler syntax require different + + * typecheck.c (unary_complex_value): Use correct datatype for + compound-exprs. + + * gen*.c (main): Use obstack_init instead of obstack_begin. + + * vax.md: define_peephole for andl3 x,y,z; extzv z,....,z + + * m68k.md (tstsi): Use cmpw instead of cmpl to test addr reg. + + * tm-m68k.h: Bugs for 68000 when frame size is over 64k. + For FUNCTION_PROLOGUE, just subtract from sp instead of fp. + For FUNCTION_EPILOGUE, must put the size into a0 and then + all insns must be indexed by a0. And do this even on 68020. + + * tm-isi68.h: Similar changes. + * tm-news800.h, tm-hp9k320.h: Similar changes. + +Wed Jan 20 04:38:21 1988 Richard Stallman (rms at frosted-flakes) + + * cccp.c (error_with_line): New function. + Use it to report the "unterminated whatever" errors. + + * typecheck.c (build_unary_op): Recursive call had missing arg. + + * m68k.md (movhi): If MOTOROLA, the insn that fetches from a + case-dispatch table now defines the LI label as .+2. + * tm-news800.el, tm-hp9k320.h (PRINT_OPERAND_ADDRESS): + Don't subtract 2 when outputting the address in that insn. + +Tue Jan 19 00:02:33 1988 Richard Stallman (rms at frosted-flakes) + + * cse.c (cse_basic_block): Abort if more qtys were used than allocated. + +Mon Jan 18 04:44:28 1988 Richard Stallman (rms at frosted-flakes) + + * cccp.c (special_symbol): tm_mon is origin-0, not origin-1. + + * final.c (output_asm_insn): If %LETTER with no digits, + pass null pointer as the operand. + + * output-m68k.c (singlemove_string): Get rid of %e. + + * stmt.c (fixup_memory_subreg): Convert (SUBREG (MEM a)) to (MEM a'). + * stmt.c (fixup_var_ref_1): Use that fn for operands of + SIGN_EXTRACT and ZERO_EXTRACT, since (SUBREG:SI (REG:QI...)) + could have turned into (SUBREG:SI (MEM:QI...)), which is unsafe. + + * rtl.c (debug_rtx): Print an rtx on stderr, for debugging. + +Sun Jan 17 04:37:20 1988 Richard Stallman (rms at frosted-flakes) + + * gcc.c: options -M* treated like -M. + + * stmt.c (pushcase): Do nothing if the case index has error_mark type. + + * expr.c (expand_increment): Don't use queue for post-inc on memory + if the add insn requires register args. (Better code for RISCs.) + +Sat Jan 16 02:10:22 1988 Richard Stallman (rms at frosted-flakes) + + * ns32k.md: Change register_operand to general_operand. + * ns32k.md (udivmoddisi4): Use match_dup where required. + Comment it out because it can't accept two independent output args. + +Fri Jan 15 00:02:35 1988 Richard Stallman (rms at frosted-flakes) + + * toplev.c: Include sys/time.h only for BSD. For USG, use time.h. + This is correct for HPUX; don't know about others. + + * gcc.c (execute): Eliminate `union wait'. Make `status' an int. + * gcc.c (execute) [USG]: Use fork instead of vfork. + + * final.c (output_source_line): Use ASM_OUTPUT_SOURCE_{FILENAME,LINE} + if they are defined. + + * tm-hp9k320.h: New name for tm-hpux.h. + * tm-hp9k320.h (ASM_OUTPUT_LOCAL): Add 3rd arg to `lcomm' statements. + * tm-hp9k320.h (ASM_OUTPUT_{DOUBLE,FLOAT}): Use `double' and `float'. + * tm-hp9k320.h (CALL_USED_REGISTERS): Don't save any 68881 regs. + * tm-hp9k320.h (CPP_PREDEFINES): different names defined. + * tm-hp9k320.h (HPUX_ASM, NO_DBX_FORMAT, ASM_SPEC): define these. + * tm-hp9k320.h (ASM_OUTPUT_OPCODE): Convert `ftst' to `ftest'. + * tm-hp9k320.h: Define ASM_OUTPUT_SOURCE_{FILENAME,LINE}. + + * m68k.md: Rename `hpux' conditionals to `HPUX_ASM'. + * m68k.md: Reverse `fcmp' args if HPUX_ASM. + + * cccp.c (print_deps): 2 means give all files, 1 means only user files. + * cccp.c (do_include): Support that. + * cccp.c (main): -MM sets 1, -M alone sets 2. + * cccp.c (main): Give fatal error if I/O error in writing. + + * toplev.c (fatal_io_error): Report I/O error on given filename, + and exit. + + * toplev.c (compile_file): Detect error writing asm_out_file. + Always put asm file's name in asm_file_name for err msg. + * symout.c (symout_finish): Detect error writing symfile. + * symout.c (symout_init): Save filename in symfile_name for err msg. + + * gen*.c: Return 1 if ferror (stdout)--in case disk is full. + + * local-alloc.c (block_alloc): Don't crash if 1st rtx + in a PARALLEL is not a SET. + + * tm-m68k.h, tm-news800.h (PRINT_OPERAND). Eliminate code `%e'. + * m68k.md: Change `%e' to `e' everywhere. + * tm-hpux.h (ASM_OUTPUT_OPCODE): Output `move' as `mov'. + + * tm-m68k.h, tm-news800.h, tm-hpux.h (PRINT_OPERAND): + New code `%!' is output as the name for the cc register. + * m68k.md (insns that use andi to ccr): Use `%!' to avoid + conditionals. + + * cse.c: Record in qty_const_insn the insn that stored the + constant value of a qty. When making a REG_WAS_0 note, + store in it the insn that established the value 0. + + * vax.md (movsi): When checking a REG_WAS_0 note, + verify that the insn it points to hasn't been deleted or made a NOTE. + +Thu Jan 14 00:01:35 1988 Richard Stallman (rms at frosted-flakes) + + * toplev.c: Eliminate error_with_line and warning_with_line. + * parse.y, decl.c: Change remaining calls to those two. + + * tree.c (get_unwidened, get_narrower): To see if a COMPONENT_REF + is unsigned, look at the FIELD_DECL, not at the COMPONENT_REF. + + * rtl.c (print_rtx): Print /v for the `volatil' bit. + * expr.c (expand_assignment expand_expr): If handling a COMPONENT_REF, + note whether it is volatile. + + * fold-const.c (fold): a call to split_tree missed an argument. + + * flow.c (volatile_refs_p): Scan an rtx for volatile mem refs. + * flow.c (life_analysis): Record in INSN_VOLATILE which insns + have any volatile mem refs. + * flow.c (mark_used_regs): Always mark an insn with volatile mem refs. + Always pass INSN as an arg. New arg FINAL now says whether + this is the last time scanning. + * flow.c (propagate_block): Don't delete insns with volatile mem refs. + + * flow.c: Remove all refs to `obey_regdecls'. + Calling this with -noreg just doesn't help -W. + +Wed Jan 13 01:13:07 1988 Richard Stallman (rms at frosted-flakes) + + * decl.c (finish_decl): Error if auto var's size isn't known. + Change type to error_mark_node to avoid crash if the var + is used in an expression, since it has no DECL_RTL. + + * output-m68k.c (output_move_const_single): % -> %% for sprintf. + + * parse.y (yylex): Store token_buffer properly after ellipsis. + + * decl.c (duplicate_decls): Don't call layout_decl + for FUNCTION_DECL or TYPE_DECL. + + * toplev.c (warning_with_decl): New warning function with decl as arg. + * (error_with_decl): similar. + + * decl.c: Replace most `yylinerror' calls with `error_with_decl'. + + * decl.c (build_struct): Reform code to detect erroneous bit-fields. + All such errors are now detected here. + Promote bit-fields to int if appropriate. + If traditional, make all int bit-fields unsigned. + Set DECL_ALIGN for members that are not bit-fields. + + * decl.c (grokfield): Don't set DECL_ALIGN here. + + * stor-layout.c (layout_decl): Don't promote the type of a bit-field. + Use TREE_PACKED to distinguish a bit-field. + Don't check the width because build_struct did that. + + * m68k.md (cmpm): Reject if either operand (address) is a constant. + +Tue Jan 12 15:11:20 1988 Richard Stallman (rms at frosted-flakes) + + * cse.c (canon_reg): Never replace ANY hard reg from reg_rtx + because that could alter the machine mode. + + * tm-news800.h: Redefine INDIRECTABLE_1_ADDRESS only if MOTOROLA. + +Mon Jan 11 13:15:45 1988 Richard Stallman (rms at frosted-flakes) + + * jump.c (follow_jumps): If we find a cycle, make it a jump to self. + + * cse.c (predecide_loop_entry): Give up if chase more than 10 jumps. + +Sun Jan 10 14:52:42 1988 Richard Stallman (rms at frosted-flakes) + + * reload1.c (reload): basic_block_needs (new vector) gets 1 + for each basic block that needs a reload. + * reload1.c (spill_hard_reg): Don't spill pseudos that are + confined to a basic block which has no need for any reloads. + * reload1.c (reload): Each cycle that any element of basic_block_needs + changes from 0 to 1, must re-spill all previously spilled regs. + + * regclass.c (record_address_regs): + Skip the charging of ICOST if it is 0. + + * flags.h, toplev.c: New flag -fvolatile. + * typecheck.c (build_indirect_ref): If flag_volatile, + every INDIRECT_REF is marked with TREE_THIS_VOLATILE. + + * fold-const.c (fold): Test in TRUTH_NOT_EXPR case was backward. + Also result type is always `int'. + +Sat Jan 9 04:16:11 1988 Richard Stallman (rms at rice-krispies) + + * flags.h (flag_traditional): New flag. + * toplev.c: recognize -ftraditional and -traditional. + * parse.y (yylex): If flag_traditional, don't recognize + `signed', `const' or `volatile'. + + * decl.c (pushdecl): If flag_traditional, any extern decl + takes effect at top level. + + * tree.c (lvalue_or_else): New 2nd arg for use in error message. + * typecheck.c: All callers pass 2nd arg. + + * global-alloc.c: allocno_preferred_reg can specify a preferred + hard reg for each allocno. If so, try it first (new call to find_reg). + + * global-alloc.c (find_reg): New arg PREFREG specifies reg to try + first. + + * decl.c (build_struct): if :0 bit field at the end, round the + structure size to multiple of EMPTY_FIELD_BOUNDARY. + + * cse.c (make_regs_eqv): Was testing for reg_next_eqv[lastr] == 0 + and should be == -1. + + * reload1.c (reload_as_needed): Fix invalid optimization deleting + the previous store into a pseudo-reg that feeds an input-reload. + It is not safe because a later insn may look in the pseudo's stack + slot for the value. Delete the store only if we can eliminate the + pseudo entirely or if the current insn stores a new value there. + Also verify that reload_in[j] is a REG. + + * reload1.c (reload_as_needed): When doing an input reload from a + pseudo that was stored by the previous insn (not as a reload), + redirect the previous insn into the reload register, if this lets + us eliminate the pseudo entirely. + + * reload1.c (reload_as_needed): In both of the above cases, it's + impossible to prevent a stack slot since one was already assigned, + so don't alter reg_n_refs. Instead, set reg_renumber to record + that this pseudo did get a hard reg. + + * stmt.c: Set `volatil' in pseudo-regs for the user's variables. + + * jump.c (delete_insn): Do nothing if insn already deleted. + + * tm-sun{2,3}.h: #define STRUCTURE_SIZE_BOUNDARY 2 + for compatibility with Sun PCC. Note that 4.3 vax PCC + does not want this. + + * fold-const.c: Replace truncate_unsigned with force_fit_type + which truncates unsigned types and sign-extends signed types. + + * expr.c (do_jump): emit_queue before outputting the jump insns + that use the comparison. + + * stmt.c: Error message for any goto that jumps into a + binding contour that restores a stack level. + + TREE_PACKED (label) means label was defined inside + such a binding contour that is now exited. Using such a label + is an error. + + TREE_ADDRESSABLE (label) means label was used from a place + outside all such binding contours. If this is 1 when + TREE_PACKED is set to 1, it is an error. + + Any other invalid goto must have a fixup. fixup_gotos detects + such invalid gotos. fixup_gotos takes a second arg, which + is the first insn of the contour now being exited. + + * GNU C version 1.17. + +Local Variables: +mode: indented-text +left-margin: 8 +fill-column: 76 +version-control: never +End: diff --git a/gcc-1.40/PROBLEMS b/gcc-1.40/PROBLEMS new file mode 100644 index 0000000..7477de0 --- /dev/null +++ b/gcc-1.40/PROBLEMS @@ -0,0 +1,128 @@ +3. When find_reloads is used to count number of spills needed +it does not take into account the fact that a reload may +turn out to be a dummy. + +I'm not sure this really happens any more. Doesn't it find +all the dummies on both passes? + +10. movl a3@,a0 + movl a3@(16),a1 + clrb a0@(a1:l) +is generated and may be worse than + movl a3@,a0 + addl a3@(16),a0 + clrb a0@ +If ordering of operands is improved, many more +such cases will be generated from typical array accesses. + +23. (memory >> 24) and (memory >> 24) == CONST optimizations +ought to be done machine independently. + +38. Hack expand_mult so that if there is no same-modes multiply +it will use a widening multiply and then truncate rather than +calling the library. + +39. Hack expanding of division to notice cases for +long -> short division. + +40. Represent divide insns as (DIV:SI ...) followed by +a separate lowpart extract. Represent remainder insns as DIV:SI +followed by a separate highpart extract. Then cse can work on +the DIV:SI part. Problem is, this may not be desirable on machines +where computing the quotient alone does not necessarily give +a remainder--such as the 68020 for long operands. + +42. In subst in combine.c at line 704 or so, a reg that really +wants an areg gets a dreg. It is i*4, for indexing. Why? + +52. Reloading can look at how reload_contents got set up. +If it was copied from a register, just reload from that register. +Otherwise, perhaps can change the previous insn to move the +data via the reload reg, thus avoiding one memory ref. + +53. Know that certain library routines do not clobber memory. + +63. Potential problem in cc_status.value2, if it ever activates itself +after a two-address subtraction (which currently cannot happen). +It is supposed to compare the current value of the destination +but eliminating it would use the results of the subtraction, equivalent +to comparing the previous value of the destination. + +65. Should loops that neither start nor end with a break +be rearranged to end with the last break? + +69. Define the floating point converting arithmetic instructions +for the 68881. + +74. Combine loop opt with cse opt in one pass. Do cse on each loop, +then loop opt on that loop, and go from innermost loops outward. +Make loop invariants available for cse at end of loop. + +85. pea can force a value to be reloaded into an areg +which can make it worse than separate adding and pushing. +This can only happen for adding something within addql range +and it only loses if the qty becomes dead at that point +so it can be added to with no copying. + +93. If a pseudo doesn't get a hard reg everywhere, +can it get one during a loop? + +95. Can simplify shift of result of a bfextu. See testunsfld.c. +Likewise and of result of a bfextu. See hyph.c. + +96. Can do SImode bitfield insns without reloading, but must +alter the operands in special ways. + +99. final could check loop-entry branches to see if they +screw up deletion of a test instruction. If they do, +can put another test instruction before the branch and +make it conditional and redirect it. + +106. Aliasing may be impossible if data types of refs differ +and data type of containing objects also differ. +(But check this wrt unions.) + +108. Can speed up flow analysis by making a table saying which +register is set and which registers are used by each instruction that +only sets one register and only uses two. This way avoid the tree +walk for such instructions (most instructions). + +109. It is desirable to avoid converting INDEX to SImode if a +narrower mode suffices, as HImode does on the 68000. +How can this be done? + +110. Possible special combination pattern: +If the two operands to a comparison die there and both come from insns +that are identical except for replacing one operand with the other, +throw away those insns. Ok if insns being discarded are known 1 to 1. +An andl #1 after a seq is 1 to 1, but how should compiler know that? + +112. Can convert float to unsigned int by subtracting a constant, +converting to signed int, and changing the sign bit. + +117. Any number of slow zero-extensions in one loop, that have +their clr insns moved out of the loop, can share one register +if their original life spans are disjoint. +But it may be hard to be sure of this since +the life span data that regscan produces may be hard to interpret +validly or may be incorrect after cse. + +118. In cse, when a bfext insn refers to a register, if the field +corresponds to a halfword or a byte and the register is equivalent +to a memory location, it would be possible to detect this and +replace it with a simple memory reference. + +121. Insns that store two values cannot be moved out of loops. +The code in scan_loop doesn't even try to deal with them. + +122. When insn-output.c turns a bit-test into a sign-test, +it should see whether the cc is already set up with that sign. + +123. When a conditional expression is used as a function arg, it would +be faster (and in some cases shorter) to push each alternative rather +than compute in a register and push that. This would require +being able to specify "push this" as a target for expand_expr. + +124. On the 386, bad code results from foo (bar ()) when bar +returns a double, because the pseudo used fails to get preferenced +into an fp reg because of the distinction between regs 8 and 9. diff --git a/gcc-1.40/PROJECTS b/gcc-1.40/PROJECTS new file mode 100644 index 0000000..162e3eb --- /dev/null +++ b/gcc-1.40/PROJECTS @@ -0,0 +1,364 @@ +0. Improved efficiency. + +* 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. + +1. Better optimization. + +* Constants in unused inline functions + +It would be nice to delay output of string constants so that string +constants mentioned in unused inline functions are never generated. +Perhaps this would also take care of string constants in dead code. + +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. + +* Support more general tail-recursion among different functions. + +This might be possible under certain circumstances, such as when +the argument lists of the functions have the same lengths. +Perhaps it could be done with a special declaration. + +You would need to verify in the calling function that it does not +use the addresses of any local variables and does not use setjmp. + +* Put short statics vars at low addresses and use short addressing mode? + +Useful on the 68000/68020 and perhaps on the 32000 series, +provided one has a linker that works with the feature. +This is said to make a 15% speedup on the 68000. + +* Keep global variables in registers. + +Here is a scheme for doing this. A global variable, or a local variable +whose address is taken, can be kept in a register for an entire function +if it does not use non-constant memory addresses and (for globals only) +does not call other functions. If the entire function does not meet +this criterion, a loop may. + +The VAR_DECL for such a variable would have to have two RTL expressions: +the true home in memory, and the pseudo-register used temporarily. +It is necessary to emit insns to copy the memory location into the +pseudo-register at the beginning of the function or loop, and perhaps +back out at the end. These insns should have REG_EQUIV notes so that, +if the pseudo-register does not get a hard register, it is spilled into +the memory location which exists in any case. + +The easiest way to set up these insns is to modify the routine +put_var_into_stack so that it does not apply to the entire function +(sparing any loops which contain nothing dangerous) and to call it at +the end of the function regardless of where in the function the +address of a local variable is taken. It would be called +unconditionally at the end of the function for all relevant global +variables. + +For debugger output, the thing to do is to invent a new binding level +around the appropriate loop and define the variable name as a register +variable with that scope. + +* Live-range splitting. + +Currently a variable is allocated a hard register either for the full +extent of its use or not at all. Sometimes it would be good to +allocate a variable a hard register for just part of a function; for +example, through a particular loop where the variable is mostly used, +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-alloc.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. + +* Detect dead stores into memory? + +A store into memory is dead if it is followed by another store into +the same location; and, in between, there is no reference to anything +that might be that location (including no reference to a variable +address). + +* Loop optimization. + +Strength reduction and iteration variable elimination could be +smarter. They should know how to decide which iteration variables are +not worth making explicit because they can be computed as part of an +address calculation. Based on this information, they should decide +when it is desirable to eliminate one iteration variable and create +another in its place. + +It should be possible to compute what the value of an iteration +variable will be at the end of the loop, and eliminate the variable +within the loop by computing that value at the loop end. + +When a loop has a simple increment that adds 1, +instead of jumping in after the increment, +decrement the loop count and jump to the increment. +This allows aob insns to be used. + +* Using constraints on values. + +Many operations could be simplified based on knowledge of the +minimum and maximum possible values of a register at any particular time. +These limits could come from the data types in the tree, via rtl generation, +or they can be deduced from operations that are performed. For example, +the result of an `and' operation one of whose operands is 7 must be in +the range 0 to 7. Compare instructions also tell something about the +possible values of the operand, in the code beyond the test. + +Value constraints can be used to determine the results of a further +comparison. They can also indicate that certain `and' operations are +redundant. Constraints might permit a decrement and branch +instruction that checks zeroness to be used when the user has +specified to exit if negative. + +* Smarter reload pass. + +The reload pass as currently written can reload values only into registers +that are reserved for reloading. This means that in order to use a +register for reloading it must spill everything out of that register. + +It would be straightforward, though complicated, for reload1.c to keep +track, during its scan, of which hard registers were available at each +point in the function, and use for reloading even registers that were +free only at the point they were needed. This would avoid much spilling +and make better code. + +* Change the type of a variable. + +Sometimes a variable is declared as `int', it is assigned only once +from a value of type `char', and then it is used only by comparison +against constants. On many machines, better code would result if +the variable had type `char'. If the compiler could detect this +case, it could change the declaration of the variable and change +all the places that use it. + +* Order of subexpressions. + +It might be possible to make better code by paying attention +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. + +* Trace scheduling. + +This technique is said to be able to figure out which way a jump +will usually go, and rearrange the code to make that path the +faster one. + +* Distributive law. + +The C expression *(X + 4 * (Y + C)) compiles better on certain +machines if rewritten as *(X + 4*C + 4*Y) because of known addressing +modes. It may be tricky to determine when, and for which machines, to +use each alternative. + +Some work has been done on this, in combine.c. + +* Can optimize by changing if (x) y; else z; into z; if (x) y; +if z and x do not interfere and z has no effects not undone by y. +This is desirable if z is faster than jumping. + +* For a two-insn loop on the 68020, such as + foo: movb a2@+,a3@+ + jne foo +it is better to insert dbeq d0,foo before the jne. +d0 can be a junk register. The challenge is to fit this into +a portable framework: when can you detect this situation and +still be able to allocate a junk register? + +2. Simpler porting. + +Right now, describing the target machine's instructions is done +cleanly, but describing its addressing mode is done with several +ad-hoc macro definitions. Porting would be much easier if there were +an RTL description for addressing modes like that for instructions. +Tools analogous to genflags and genrecog would generate macros from +this description. + +There would be one pattern in the address-description file for each +kind of addressing, and this pattern would have: + + * the RTL expression for the address + * C code to verify its validity (since that may depend on + the exact data). + * C code to print the address in assembler language. + * C code to convert the address into a valid one, if it is not valid. + (This would replace LEGITIMIZE_ADDRESS). + * Register constraints for all indeterminates that appear + in the RTL expression. + +3. Other languages. + +Front ends for Pascal, Fortran, Algol, Cobol, Modula-2 and Ada are +desirable. + +Pascal, Modula-2 and Ada require the implementation of functions +within functions. Some of the mechanisms for this already exist. + +4. More extensions. + +* Label-addresses as expressions. + +It would be nice to have access to the addresses of labels; to be able to +store them in variables, or initialize vectors of them. + +Alas, `&label0' is the address of the variable named label0, which is +unrelated to the label with that name. Some other syntax is needed. +Perhaps colon as a unary operator? That is ambiguous with `?:' with +the middle operand omitted. Perhaps ^ as a unary operator? Perhaps +`__label__ label0' could mean the value of label0? Its type could be +`void *'. `goto *EXP' could be used to go to a value of type `void +*'--no ambiguity there. + +Jump optimization and flow analysis must know about computed jumps, +but that is not hard. Each basic block headed by a possible target of +computed jumps must be considered a successor of each basic block +ending in a computed jump. Aside from this, I believe no other +optimizer changes are needed. + +Next question: stack levels. In most functions, there is no problem, +but it would be a shame to make a feature that doesn't work together +with other features. Here is an idea: + +For each label that might need stack level restoration, construct a +shadow-label which will restore the stack and jump to the user-label. +Then use the address of the shadow label for label0 when someone asks +for that of label0. Jump optimization will delete all the shadow labels +if the function has no computed gotos. + +* Generated unique labels. Have some way of generating distinct labels +for use in extended asm statements. I don't know what a good syntax would +be. + +5. Generalize the machine model. + +* Some new compiler features may be needed to do a good job on machines +where static data needs to be addressed using base registers. + +* Some machines have two stacks in different areas of memory, one used +for scalars and another for large objects. The compiler does not +now have a way to understand this. + +6. Better documentation of how GCC works and how to port it. + +Here is an outline proposed by Allan Adler. + +I. Overview of this document +II. The machines on which GCC is implemented + A. Prose description of those characteristics of target machines and + their operating systems which are pertinent to the implementation + of GCC. + i. target machine characteristics + ii. comparison of this system of machine characteristics with + other systems of machine specification currently in use + B. Tables of the characteristics of the target machines on which + GCC is implemented. + C. A priori restrictions on the values of characteristics of target + machines, with special reference to those parts of the source code + which entail those restrictions + i. restrictions on individual characteristics + ii. restrictions involving relations between various characteristics + D. The use of GCC as a cross-compiler + i. cross-compilation to existing machines + ii. cross-compilation to non-existent machines + E. Assumptions which are made regarding the target machine + i. assumptions regarding the architecture of the target machine + ii. assumptions regarding the operating system of the target machine + iii. assumptions regarding software resident on the target machine + iv. where in the source code these assumptions are in effect made +III. A systematic approach to writing the files tm.h and xm.h + A. Macros which require special care or skill + B. Examples, with special reference to the underlying reasoning +IV. A systematic approach to writing the machine description file md + A. Minimal viable sets of insn descriptions + B. Examples, with special reference to the underlying reasoning +V. Uses of the file aux-output.c +VI. Specification of what constitutes correct performance of an + implementation of GCC + A. The components of GCC + B. The itinerary of a C program through GCC + C. A system of benchmark programs + D. What your RTL and assembler should look like with these benchmarks + E. Fine tuning for speed and size of compiled code +VII. A systematic procedure for debugging an implementation of GCC + A. Use of GDB + i. the macros in the file .gdbinit for GCC + ii. obstacles to the use of GDB + a. functions implemented as macros can't be called in GDB + B. Debugging without GDB + i. How to turn off the normal operation of GCC and access specific + parts of GCC + C. Debugging tools + D. Debugging the parser + i. how machine macros and insn definitions affect the parser + E. Debugging the recognizer + i. how machine macros and insn definitions affect the recognizer + +ditto for other components + +VIII. Data types used by GCC, with special reference to restrictions not + specified in the formal definition of the data type +IX. References to the literature for the algorithms used in GCC + diff --git a/gcc-1.40/README b/gcc-1.40/README new file mode 100644 index 0000000..9570f7a --- /dev/null +++ b/gcc-1.40/README @@ -0,0 +1,15 @@ +This directory contains the version 1.40 release of the GNU C compiler. +All bugs reported for previous test releases have been fixed. +This version probably does not have very many bugs, and we no longer +consider it a test version. + +See the file gcc.texinfo for installation and porting information. +The file INSTALL contains a copy of the installation information. + +The GNU C compiler is free software. See the file COPYING for copying +permission. + +The files print-self.c and print-self1.c are not part of GCC. +They are programs that print themselves on standard output. +They were written by Dario Dariol and Giovanni Cozzi, and are +included for your hacking pleasure. diff --git a/gcc-1.40/README-ALTOS b/gcc-1.40/README-ALTOS new file mode 100644 index 0000000..df13e4b --- /dev/null +++ b/gcc-1.40/README-ALTOS @@ -0,0 +1,53 @@ +Return-Path: +Date: Mon, 10 Apr 89 10:13:45 +0300 +From: Jyrki Kuoppala +Sender: jkp@sauna.hut.fi +To: info-gcc@prep.ai.mit.edu +Subject: Kernel fix needed for Altos 3068 to get coff-encapsulation working right +Organization: Helsinki University of Technology, Finland. + +Here's a description how to fix a kernel bug in Altos 3068 and get +gcc-compiled programs working. + +Author: Jyrki Kuoppala (jkp@cs.hut.fi) +Last modified: Mon Apr 10 09:28:40 1989 + +There's a bug in the Altos 3068 kernel that causes gcc-compiled +programs to fail in certain situations when the machine has a heavy +load and also in some other situations. The bug exists at least in +SVR 2.2 1.0gT1 and SVR 2.2 1.0e. + +If you have source code to your system, apply the following change to +os/exec.c (function gethead): + +Change the lines containing + + u.u_exdata.ux_tstart = sizeof(struct naout) + + sizeof(struct filhd) + (ep->ef.nscns * sizeof(struct scnhdr)); + +to + + u.u_exdata.ux_tstart = u.u_exdata.ux_txtorg; + +If you only have binary, use sdb to find out the address of the +previous lines (on our system it's gethead+0x140) and use your +favourite binary editor to change the bytes '3036 0162 fffc 0002 0280 +0000' to '23f9 01fb f4ca 01fb f4c2 6016'. This may or may not work in +your case, depending on the version of the operating system and the +phase of the moon. + +Here's what is just before gethead+0x140 to ease finding out the right place: + +0x9224 (gethead+0x122): 23f9 01fb f4ca 01fb f4ce mov.l &0x1fbf4ca.L,&0 +x1fbf4ce.L [] +0x922e (gethead+0x12c): 23f9 01fb f4c6 01fb f4ca mov.l &0x1fbf4c6.L,&0 +x1fbf4ca.L [] +0x9238 (gethead+0x136): 23f9 01fb f4c2 01fb f4c6 mov.l &0x1fbf4c2.L,&0 +x1fbf4c6.L [] + +Good luck ! + +//Jyrki + +jkp@cs.hut.fi + diff --git a/gcc-1.40/README-NS32K b/gcc-1.40/README-NS32K new file mode 100644 index 0000000..b0c28f0 --- /dev/null +++ b/gcc-1.40/README-NS32K @@ -0,0 +1,150 @@ +Copyright (C) 1987 Free Software Foundation, Inc. +Contributed by Michael Tiemann (tiemann@mcc.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 1, 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 describes the implementation notes of the GNU C Compiler for +the National Semiconductor 32032 chip (and 32000 family). + +The 32032 machine description and configuration file for this compiler +is, for NS32000 family machine, primarily machine independent. +However, since this release still depends on vendor-supplied +assemblers and linkers, the compiler must obey the existing +conventions of the actual machine to which this compiler is targeted. +In this case, the actual machine which this compiler was targeted to +is a Sequent Balance 8000, running DYNIX 2.1. + +The assembler for DYNIX 2.1 (and DYNIX 3.0, alas) does not cope with +the full generality of the addressing mode REGISTER RELATIVE. +Specifically, it generates incorrect code for operands of the +following form: + + sym(rn) + +Where `rn' is one of the general registers. Correct code is generated +for operands of the form + + sym(pn) + +where `pn' is one of the special processor registers (sb, fp, or sp). + +An equivalent operand can be generated by the form + + sym[rn:b] + +although this addressing mode is about twice as slow on the 32032. + +The more efficient addressing mode is controlled by defining the +constant SEQUENT_ADDRESS_BUG to 0. It is currently defined to be 1. + +Another bug in the assembler makes it impossible to compute with +explicit addresses. In order to compute with a symbolic address, it +is necessary to load that address into a register using the "addr" +instruction. For example, it is not possible to say + + cmpd _p,@_x + +Rather one must say + + addr _x,rn + cmpd _p,rn + + +The ns32032 chip has a number of known bugs. Any attempt to make the +compiler unaware of these deficiencies will surely bring disaster. +The current list of know bugs are as follows (list provided by Richard +Stallman): + +1) instructions with two overlapping operands in memory +(unlikely in C code, perhaps impossible). + +2) floating point conversion instructions with constant +operands (these may never happen, but I'm not certain). + +3) operands crossing a page boundary. These can be prevented +by setting the flag in tm.h that requires strict alignment. + +4) Scaled indexing in an insn following an insn that has a read-write +operand in memory. This can be prevented by placing a no-op in +between. I, Michael Tiemann, do not understand what exactly is meant +by `read-write operand in memory'. If this is refering to the special +TOS mode, for example "addd 5,tos" then one need not fear, since this +will never be generated. However, is this includes "addd 5,-4(fp)" +then there is room for disaster. The Sequent compiler does not insert +a no-op for code involving the latter, and I have been informed that +Sequent is aware of this list of bugs, so I must assume that it is not +a problem. + +5) The 32032 cannot shift by 32 bits. It shifts modulo the word size +of the operand. Therefore, for 32-bit operations, 32-bit shifts are +interpreted as zero bit shifts. 32-bit shifts have been removed from +the compiler, but future hackers must be careful not to reintroduce +them. + +6) The ns32032 is a very slow chip; however, some instructions are +still very much slower than one might expect. For example, it is +almost always faster to double a quantity by adding it to itself than +by shifting it by one, even if that quantity is deep in memory. The +MOVM instruction has a 20-cycle setup time, after which it moves data +at about the speed that normal moves would. It is also faster to use +address generation instructions than shift instructions for left +shifts less than 4. I do not claim that I generate optimal code for all +given patterns, but where I did escape from National's "clean +architecture", I did so because the timing specification from the data +book says that I will win if I do. I suppose this is called the +"performance gap". + + +Signed bitfield extraction has not been implemented. It is not +provided by the NS32032, and while it is most certainly possible to do +better than the standard shift-left/shift-right sequence, it is also +quite hairy. Also, since signed bitfields do not yet exist in C, this +omission seems relatively harmless. + + +Zero extractions could be better implemented if it were possible in +GCC to provide sized zero extractions: i.e. a byte zero extraction +would be allowed to yield a byte result. The current implementation +of GCC manifests 68000-ist thinking, where bitfields are extracted +into a register, and automatically sign/zero extended to fill the +register. See comments in ns32k.md around the "extzv" insn for more +details. + + +It should be noted that while the NS32000 family was designed to +provide odd-aligned addressing capability for multi-byte data (also +provided by the 68020, but not by the 68000 or 68010), many machines +do not opt to take advantage of this. For example, on the sequent, +although there is no advantage to long-word aligning word data, shorts +must be int-aligned in structs. This is an example of another +machine-specific machine dependency. + + +Because the ns32032 is has a coherent byte-order/bit-order +architecture, many instructions which would be different for +68000-style machines, fold into the same instruction for the 32032. +The classic case is push effective address, where it does not matter +whether one is pushing a long, word, or byte address. They all will +push the same address. + + +The macro FUNCTION_VALUE_REGNO_P is probably not sufficient, what is +needed is FUNCTION_VALUE_P, which also takes a MODE parameter. In +this way it will be possible to determine more exactly whether a +register is really a function value register, or just one that happens +to look right. diff --git a/gcc-1.40/README-VMS b/gcc-1.40/README-VMS new file mode 100644 index 0000000..abe763d --- /dev/null +++ b/gcc-1.40/README-VMS @@ -0,0 +1,447 @@ +Return-Path: +Date: 11 Sep 90 14:07:21 GMT +From: news@operations.dccs.upenn.edu (USENET News System) +Organization: University of Pennsylvania +Subject: Building gcc 1.37.1 with Vax C +References: <9009102236.AA15872@wubios.wustl.edu> +Sender: info-gcc-request@prep.ai.mit.edu +To: info-gcc@prep.ai.mit.edu + +during it; hopefully they'll come in handy. + + To build the new gcc-cpp and gcc-cc1 that come with Gnu C +version 1.37.1 with Vax C and NOT a previous version of gcc, +do the following: + +I - Building gcc-cpp + + A - Modify cccp.c + + 1 - Replace + + #include + #include + + with + + #ifndef VMS + #include + #include + #else + #include + #include + #endif + +[It is claimed that + $ define sys sys$library + will solve the same problem without source changes.] + + 2 - In the VMS-specific section (has perror.h etc in it), +add the following: + + #include /* for dsc$descriptor_s */ + #include /* for strchr & strrchr */ + #define index strchr + #define rindex strrchr + + 3 - You have to replace all occurences of: + + extern char *index(), *rindex(); + + as well as any where they're separated (e.g. extern char *index() + by itself or extern char *rindex() by itself), with the following: + + #ifndef VMS + extern char *index(); /* or whatever was here */ + #endif + + There's a total of three: one in main(), one in do_include(), and + one in hack_vms_include_specification(). + + B - You have to have alloca.mar for cccp.c; it was distributed + with vmsgcc1.34; it's also in the bison distribution. (both 1.03 + and 1.06) + + C - After you've compiled alloca.mar (MACRO ALLOCA.MAR), follow + the instructions at the top of MAKE-CC1.COM (namely, change the + CC := line to say cc/noopt instead of gcc, take the + cc1_options="-mpcc-alignment" part out of the CFLAGS line, and change + the LIBS line to say: + + $ LIBS := alloca,sys$share:vaxcrtl/libr + + D - Since it doesn't come with the distribution, you have + to generate cexp_tab.c yourself, either with bison on either + a Vax or a Unix box, or yacc in Unix. (@make below will die if you + don't have bison on your Vax or don't have this file) + + E - Type: + + @make + + and watch it hum. It should go through okay; it'll die on the LINK +line, but don't worry about it. + + F - Now link the whole thing with: + + link /nomap/exe=gcc-cpp cccp,cexp,version,alloca,- + sys$share:vaxcrtl/libr + + G - You should be screaming for joy right now; if you're not, then +give up on life. + + +II - Building gcc-cc1 + + A - Change MAKE-CC1.COM to contain the line: + + $ libs :== sys$share:vaxcrtl/libr,alloca + +Yep, you have to have alloca.obj here too. + + B - Modify toplev.c: + + 1 - Replace + + #include + #include + + with + + #ifndef VMS + #include + #include + #else + #include + #include + #endif + +(You'll see this again.) + + 2 - Do: + +Repl: rtx_equal_function_value_matters +With: rtx_equ_func_value_matters +Num: once + + This is cuz you can't have a name over 31 chars with the +Vax C compiler; and yep you guessed it this is over that +limit. You're gonna be doing this a few more times. + + C - Modify gcc.c: + + 1 - This is optional, since you never compile it (I'm +working on that): + + Replace + + #include + #include + #include + #include + + with + + #include + #include + #ifdef VMS + #include + #include + #else + #include + #include + #endif + + D - Modify c-parse_tab.c (if this isn't there, you'll have +to create it with bison or yacc): + +Repl: expand_start_loop_continue_elsewhere +With: expand_startloop_cont_elsewhere +Num: twice + + E - Modify tree.h: + +Repl: expand_start_loop_continue_elsewhere +With: expand_startloop_cont_elsewhere +Num: once + + F - Modify stmt.c: + +Repl: expand_start_loop_continue_elsewhere +With: expand_startloop_cont_elsewhere +Num: twice + +Repl: current_function_returns_pcc_struct +With: cur_func_ret_pcc_struct +Num: nine + +Repl: current_function_returns_pointer +With: cur_func_ret_ptr +Num: 2 + +Repl: current_function_pretend_args_size +With: cur_func_pretend_args_size +Num: 3 + + G - Modify rtanal.c: + +Repl: rtx_equal_function_value_matters +With: rtx_equ_func_values_matters +Num: twice + + H - Modify output.h: + +Repl: current_function_returns_pcc_struct +With: cur_func_ret_pcc_struct +Num: once + +Repl: current_function_returns_pointer +With: cur_func_ret_ptr +Num: once + +Repl: current_function_pretend_args_size +With: cur_func_pretend_args_size +Num: once + + I - Modify tree.def: + + Change the line that reads: + + DEFTREECODE (FILE_TYPE, "file_type", "t", 0) + + to: + + #ifdef VMS + DEFTREECODE (FILE_TYPE_GNU, "file_type", "t", 0) + #else + DEFTREECODE (FILE_TYPE, "file_type", "t", 0) + #endif + + This is cuz FILE_TYPE is defined in stdio.h as being +struct _iobuf *, which totally screws everything up. + + J - Modify expr.c: + + Change the line that reads: + + if (code == FILE_TYPE) + + to: + + #ifdef VMS + if (code == FILE_TYPE_GNU) + #else + if (code == FILE_TYPE) + #endif + + K - Modify expmed.c: + + Change the line that reads: + + trymode && GET_MODE_SIZE (trymode) <= maxsize; + + to: + + (trymode != 0) && (GET_MODE_SIZE (trymode) <= maxsize); + + Enclosing the second half of the and in parenthesis may be +overkill. By the time I thought of it it was too late to +change it (read: I didn't feel like going back), but you +may want to give it a try. + + L - Modify symout.c: + + Change the line that has #include on it to: + + #ifndef VMS + #include + #else + #define NULL (void *) 0 + #endif + + M - Modify insn-emit.c: + + Line #1011 (in mine) is a 376-character long line that's +one HUGE return (it calls a function a few zillion times +embedded upon each other). This is a tad too big for Vax C +to chew; try cutting it down to a few lines. I made it look +like this: + +rtx +gen_casesi (operand0, operand1, operand2, operand3) + rtx operand0; + rtx operand1; + rtx operand2; + rtx operand3; +{ + return gen_rtx (SET, VOIDmode, pc_rtx, + gen_rtx (IF_THEN_ELSE, VOIDmode, + gen_rtx (LE, VOIDmode, + gen_rtx (MINUS, SImode, operand0, operand1), + operand2), + gen_rtx (PLUS, SImode, + gen_rtx (SIGN_EXTEND, SImode, + gen_rtx (MEM, HImode, + gen_rtx (PLUS, SImode, pc_rtx, + gen_rtx (MINUS, SImode, operand0, operand1)))), + gen_rtx (LABEL_REF, SImode, operand3)), + pc_rtx)); +} + + Kinda smacks of lisp, no? + + N - Modify final.c: + + Change the line that reads: + + rtx final_sequence; + + to: + + #ifndef VMS + rtx final_sequence; + #endif + + This is cuz rtx final_sequence already appears in +output.h, and Vax C screams when it sees this. + + O - You have to have alloca(), bcopy(), bcmp(), and +bzero(); all are in the VMS Gcc 1.34 distribution; only +bcopy() is in the bison distribution. Since they're pretty +short, I'm gonna include 'em here. These were sent under the +Gnu public license. + + alloca.mar: + + .PSECT $CODE,LONG,PIC,REL,SHR,EXE,RD,NOWRT + .ENTRY ALLOCA,^M<> + SUBL2 4(AP),SP + MOVL 16(FP),R1 + MOVQ 8(FP),AP + BICL2 #3,SP + ADDL2 #28,SP + MOVL SP,R0 + JMP (R1) + + .END + + bcopy.mar: + + .PSECT $CODE,LONG,PIC,REL,SHR,EXE,RD,NOWRT + ; bcopy(from, to, size) + .ENTRY BCOPY,^M + MOVL 4(AP),R1 + MOVL 8(AP),R3 + MOVL 12(AP),R6 + CMPL R1,R3 + BGTR 2$ ; NORMAL FORWARD CASE + BLSS 3$ ; OVERLAPPING, MUST DO BACKWARDS + RET ; EQUAL, NOTHING TO DO +1$: SUBL2 R0,R6 + MOVC3 R0,(R1),(R3) +2$: MOVZWL #65535,R0 + CMPL R6,R0 + BGTR 1$ + MOVC3 R6,(R1),(R3) + RET +3$: ADDL2 R6,R1 + ADDL2 R6,R3 + MOVZWL #65535,R0 + BRW 5$ +4$: SUBL2 R0,R6 + SUBL2 R0,R1 + SUBL2 R0,R3 + MOVC3 R0,(R1),(R3) + MOVZWL #65535,R0 + SUBL2 R0,R1 + SUBL2 R0,R3 +5$: CMPL R6,R0 + BGTR 4$ + SUBL2 R6,R1 + SUBL2 R6,R3 + MOVC3 R6,(R1),(R3) + + RET + + .END + + bcmp.mar: + + .PSECT $CODE,LONG,PIC,REL,SHR,EXE,RD,NOWRT + ; bcmp(s1, s2, n) + .ENTRY BCMP,^M + MOVL 4(AP),R1 + MOVL 8(AP),R3 + MOVL 12(AP),R4 +1$: MOVZWL #65535,R0 + CMPL R4,R0 + BLEQ 2$ + SUBL2 R0,R4 + CMPC3 R0,(R1),(R3) + BEQL 1$ + ADDL2 R4,R0 + RET +2$: CMPC3 R4,(R1),(R3) + RET + + .END + + + bzero.mar: + + .PSECT $CODE,LONG,PIC,REL,SHR,EXE,RD,NOWRT + ; bzero(ptr, size) + .ENTRY BZERO,^M + MOVL 4(AP),R3 + BRB 2$ +1$: SUBL2 R0,8(AP) + MOVC5 #0,(R3),#0,R0,(R3) +2$: MOVZWL #65535,R0 + CMPL 8(AP),R0 + BGTR 1$ + MOVC5 #0,(R3),#0,8(AP),(R3) + RET + + .END + + P - On the last lines (where it's got all of the link shit), +change it so it reads: + + ...blahblahblah... + ...blahblah,insn-extract,insn-output,obstack,- + integrate,caller-save,- + bcopy,bcmp,bzero + $! + + So now it'll link the bcopy, bcmp, and bzero routines in. + + Q - You should be screaming for joy right now; if you're +not, then give up on life again. Hey, I don't get paid for my humor. + + R - Finally, you have to use old versions of: + + GCC.EXE GCC-AS.EXE + GCC.COM GCC.CLD + GCCLIB.OLB + + to make the package work properly. I've only been able to make the + new preprocessors make properly; since it wasn't even in the make + files that came with it, I don't think gcc.exe 1.37.1 was intended + to be built for the Vax .. we'll see. + + In case you're wondering, I could never get vmsgcc134 to work properly; +that's why I did this with Vax C. + + Good luck! This only worked under 5.3-1 (and the latest version of +Vax C...3.0? 3.1?), and isn't guaranteed in any way shape or form. If +you have stumbling blocks and think I may have come upon it during all +of this, feel free to mail me at kehoe@scotty.dccs.upenn.edu. + +-- +Brendan Kehoe | Soon: brendan@cs.widener.edu +For now: kehoe@scotty.dccs.upenn.edu | Or: bkehoe@widener.bitnet + Last resort: brendan.kehoe@cyber.widener.edu +Brendan Kehoe | Soon: brendan@cs.widener.edu +For now: kehoe@scotty.dccs.upenn.edu | Or: bkehoe@widener.bitnet +Last resort: brendan.kehoe@cyber.widener.edu + diff --git a/gcc-1.40/README-X11 b/gcc-1.40/README-X11 new file mode 100644 index 0000000..e4c6ff0 --- /dev/null +++ b/gcc-1.40/README-X11 @@ -0,0 +1,111 @@ +Our setup: + + Sun 3/60 with cgfour + SunOS 4.0 (plus what Sun calls their "general hygiene" patch tape) + XV11R3 + MIT fixes 1 through 8 + "Purdue enhancements" + one local + "ANSIfication" fix (previously reported to MIT, + and attached below) + +I installed gcc 1.34 (plus the expr.c fix) and also ran the "fixincludes" +script. + +I built the X stuff with with the "CC" line in the "Sun.macros" file set to: + + CC = gcc -fcombine-regs -fstrength-reduce -finline-functions -fpcc-struct-return -DPURDUE -Dinline=INLINE -DNOSTDHDRS + +where -fcombine-regs, -fstrength-reduce, and -finline-functions +specify desired optimizations, -fpcc-struct-return makes things +compatible with the dbm library, -DPURDUE buys the Purdue speedups, +-Dinline=INLINE avoids a problem with a variable named "inline" in the +X file "fonts/bdftosnf/fontutil.c", and -DNOSTDHDRS avoids a problem +with multiple (and conflicting) typedef'ing of "size_t" in the +gcc-provided STDDEF_H and Sun's "sys/types.h". + +Some clients may need -fwritable-strings. twm is said to need it. + +The ANSIfication fix: + +> From ado Mon Dec 26 10:55:28 1988 +> To: xbugs@expo.lcs.mit.edu +> Subject: Xlibint and __STDC__ don't mix +> +> +> X Window System Bug Report +> xbugs@expo.lcs.mit.edu +> +> +> +> +> VERSION: +> R3 +> +> CLIENT MACHINE and OPERATING SYSTEM: +> Sun 3/60 running SunOS 4.0 +> +> DISPLAY: +> Sun CG4 +> +> WINDOW MANAGER: +> uwm +> +> AREA: +> Xlib +> +> SYNOPSIS: +> Xlibint.h and __STDC__ don't mix +> +> DESCRIPTION: +> If __STDC__ is defined (and UNIXCPP is not defined), +> code that uses the GetReqExtra macro defined in Xlibint.h +> is uncompilable. +> +> REPEAT BY: +> Script started on Mon Dec 26 10:52:58 1988 +> elsie$ cd lib/X +> elsie$ rm Xbackgnd.o +> rm: Xbackgnd.o: No such file or directory +> elsie$ rm XBackgnd.o +> elsie$ make XBackgnd.o CC=/usr/local/bin/gcc +> rm -f XBackgnd.o +> /usr/local/bin/gcc -c -O -I. -I../../. -I../.././X11 -DTCPCONN -DUNIXCONN XBackgnd.c +> XBackgnd.c: In function XSetWindowBackground: +> XBackgnd.c:16: undeclared variable `sz_' (first use here) +> *** Error code 1 +> make: Fatal error: Command failed for target `XBackgnd.o' +> elsie$ exit +> +> script done on Mon Dec 26 10:53:51 1988 +> +> SAMPLE FIX: +> *** 1.1/Xlibint.h Mon Dec 26 10:39:37 1988 +> --- 1.2/Xlibint.h Mon Dec 26 10:39:37 1988 +> *************** +> *** 122,133 **** +> #if defined(__STDC__) && !defined(UNIXCPP) +> #define GetReqExtra(name, n, req) \ +> WORD64ALIGN\ +> ! if ((dpy->bufptr + SIZEOF(*req) + n) > dpy->bufmax)\ +> _XFlush(dpy);\ +> req = (x##name##Req *)(dpy->last_req = dpy->bufptr);\ +> req->reqType = X_##name;\ +> ! req->length = (SIZEOF(*req) + n)>>2;\ +> ! dpy->bufptr += SIZEOF(*req) + n;\ +> dpy->request++ +> #else +> #define GetReqExtra(name, n, req) \ +> --- 122,133 ---- +> #if defined(__STDC__) && !defined(UNIXCPP) +> #define GetReqExtra(name, n, req) \ +> WORD64ALIGN\ +> ! if ((dpy->bufptr + SIZEOF(x##name##Req) + n) > dpy->bufmax)\ +> _XFlush(dpy);\ +> req = (x##name##Req *)(dpy->last_req = dpy->bufptr);\ +> req->reqType = X_##name;\ +> ! req->length = (SIZEOF(x##name##Req) + n)>>2;\ +> ! dpy->bufptr += SIZEOF(x##name##Req) + n;\ +> dpy->request++ +> #else +> #define GetReqExtra(name, n, req) \ +> -- +> Arthur David Olson ado@ncifcrf.gov ADO is a trademark of Ampex. + diff --git a/gcc-1.40/SERVICE b/gcc-1.40/SERVICE new file mode 100644 index 0000000..680768f --- /dev/null +++ b/gcc-1.40/SERVICE @@ -0,0 +1,1154 @@ +GNU Service Directory + +This is a list of people who have asked to be listed as offering +support services for GNU software, including GNU Emacs, for a fee +or in some cases at no charge. + +The information comes from the people who asked to be listed; +we do not include any information we know to be false, but we +cannot check out any of the information; we are transmitting it to +you as it was given to us and do not promise it is correct. +Also, this is not an endorsement of the people listed here. +We have no opinions and usually no information about the abilities of +any specific person. We provide this list to enable you to contact +service providers and decide for yourself whether to hire one. + +Before FSF will list your name in the GNU Service Directory, we ask +that you agree informally to the following terms: + +1. You will not restrict (except by copyleft) the use or distribution +of any software, documentation, or other information you supply anyone +in the course of modifying, extending, or supporting GNU software. +This includes any information specifically designed to ameliorate the +use of GNU software. + +2. You will not take advantage of contact made through the Service +Directory to advertise an unrelated business (e.g., sales of +non-GNU-related proprietary information). You may spontaneously +mention your availability for general consulting, but you should not +promote a specific unrelated business unless the client asks. + +For a current copy of this directory, or to have yourself listed, ask: + gnu@prep.ai.mit.edu + +** Please keep this file alphabetical ** + + +Giuseppe Attardi +Dipartimento di Informatica +Corso Italia 40 +I-56100 Pisa, ITALY ++39 (50) 510111 +Emacs: installation aid, question answering + +Revised: 3/24/89 + +Andrea Baldi + + ...!sun!delphi!abaldi + +DELPHI S.p.A. +Via della Vetraia 11 +I-55049 Viareggio, Italy +Tel: +39 (584) 395225 +Gnuemacs: installation and upgrading aid, answering, customization, + gnuemacs-X11 relationship. +Gcc: installation and upgrading aid. + +Rates: Free + +Entered: 3/1/89 + +Ian G Batten + <...!uunet!mcvax!ukc!fulcrum!igb> +One, Ditton Grove, Home: +44 21 476 3782 +Birmingham, Work: +44 21 771 2001 x5759 +B31 4RY, +England. + +Emacs: I will assist in porting, customising, extending, teaching and +trouble-shooting Emacs. I've recently been teaching it at new-user +level and am happy to do so for other people. + +Rates: 200 pounds/day, or less for non-profits. + +I had a large hand in the Sun "Emacstool" facility, and have been +involved in maintaining Emacs on Unix and VMS for three years now. +Prior to that I wrote a lot of extensions for Multics' Emacs. + +Revised: 3/1/89 + +Bard Bloom +NE43-301, 545 Technology Square, +Cambridge, Mass, 02139 +(617) 253-6097 + +Emacs: Installation, customization, answering questions, troubleshooting, + writing large programs and major modes. + +X11R3: Quick questions + +Experience: I have maintained GNU Emacs on the Theory Group computers + at MIT for several years, and done a good deal of GNU Emacs lisp + programming, including several major modes, and two database + interfaces. (I have written some 15,000 lines of GNU Emacs code.) + I am currently a Ph.D. student in Computer Science at MIT. + +Rates: $50/hr, less for non-profits. + +Revised: 5/29/90 + +C2V +38, rue Mauconseil +75001 Paris +France +Renaud Dumeur +Jean-Daniel Fekete +Jean-Michel Casaubon +(1) 42 47 19 28 +Fax: (1) 40 22 06 10 +Emacs: questions answered, installation, teaching (all levels), elisp + and C extensions and customization, porting, troubleshooting +gcc: installation, extensions, porting +gdb: installation, debugging, porting +X11R3: installation, debugging, internationalization + +Experience: yes (ask for details) + +Rates: 500ff/hr, negotiable. + +Entered: 2/21/89 + +Mr. David J. Camp +6103 Charlotte Avenue +Saint Louis, MO 63120-1201 + +Background: Bachelor of Science in Computer Science, Washington University + Master of Science in Computer Science, Washington University + Over 12 years experience in the computer industry. + Author of the future GNU uu/xxen/decoder program. + Skilled in many languages, including C and Unix scripts. + +Tasks: I can do on-site service in the St. Louis area. + I prefer short-term projects. + I can handle long projects given time. + I reserve the right to refuse work. + +Rates: $50 per hour, including travel time + +Entered: 1/1/91 + +Rajeev Chandrasekhar +2625, Walsh Avenue MSC SC4-59 +Santa Clara, CA 95052 +h (408) 733-1535 +w (408) 765-4632 + +GCC : Anything concerning i386 ports. + Ports, Installation, Teaching and extensions. + Expert on Intel processors. + +Rates : $75/hr; free for non-profit orgs. + +Entered: 9 Oct 89 + +Stuart Cracraft +UUCP: +3021-B Harbor Blvd. +Costa Mesa, Ca. 92626 +(714) 751-8744 + +Emacs: questions answered, teaching, customization, troubleshooting, + but not porting. + +GNU Chess (developer): questions answered, porting, etc. + +Rates: $40/hr short term, $30/hr long term. + +EXPERIENCE: software researcher, systems programmer, Unix analyst + formerly with Stanford Research Institute, now + with Computer Consoles, Inc. +DEGREE: B.A. Behavioral Sciences, National University + +Entered: 5/17/86 + +Cygnus Support +814 University Avenue +Palo Alto, CA 94301 ++1 415 322 3811 +info@cygnus.com ...uunet!hoptoad!cygint!info + +Cygnus Support offers warranty protection (service contracts) for a +number of free software tools. For a fixed annual fee, our customers +receive binary and source distributions, mail and phone support, +documentation and customization assistance on a variety of platforms. + +At the time of this writing we offer support for a development package +including (among other things) gcc, g++, gdb, and of course, GNU +Emacs. However the set of supported tools and platforms increases +frequently so contact us for the latest catalog. + +Rates: $150.00/hour. +Annual Support: $25,000.00/year and up. + +Entered: 7/31/90 + +Dario Dariol +DELPHI SpA +via della Vetraia 11 +I-55049 Viareggio +Italy ++39 (584) 395161 + +Rates and range of services not received. + +Entered: 3/25/86 + +Bradley N. Davis + +3242 South 540 West +Bountiful, UT 84010 +(801) 581-6076, (801) 292-4362 + +Will work on most GNU software. Especially GNU Emacs, GCC and a +little X11 and G++. Experienced with PCs and 386s. + +Services offered: Installation, porting, customizing, troubleshooting. + +Fee: $20 to $50 / hour depending on job + +Updated: 1/1/91 + +Mauro DePalma + +DePalma SoftCraft +2923 Cohansey Drive +San Jose, CA 95132 + +Tel: (408) 259-4789 +Fax: (408) 259-6935 + + +DePalma SoftCraft provides support and service for GNU and X11 software +specifically for UNIX System V/386 and and SunOS 4.x; on other platforms +customers need to provide the hardware and a fair amount of motivation. + +Presently we can provide the bulk of development utilities including +bison (System V/386 only), emacs, flex (System V/386 only), gas, gcc, +gdb, g++, libg++, make, tar (System V/386 only) and other BSD style +utilities for System V/386. + +In the works is the X Window System, Version 11 Release 4 for System +V/386 with VGA and super-VGA servers as well as COFF specific version +of GNU as and GNU ld. + +LaTeX (System V/386 only) TeX (System V/386 only) documentation systems +available with a limited set of viewers and converters. + + +Rates: $90.00/hour median. +Annual Support: $25,000.00/year and up. + +Entered: 9/19/90 + +Alexander Dupuy + +280 Riverside Drive #10G +New York, NY 10025 +(212) 678-0130 +(212) 854-4290 (work) + +Gnu Compiler utilities: GNU Make, Bison, GAS, GCC, G++, libg++, etc.: + + Installation, porting, support for VAX, Sun-[234], Sun386i, some others + +Rates: $75/hr commercial orgs., free for worthy nonprofit orgs. + + I am currently a research programmer at the Columbia C.S. Dept., and + maintain and support the GNU compiler tools on 4 different machine + architectures. I can provide current, working versions of the compiler + tools for the VAX and all Sun architectures. + +Entered: 6/1/89 + +Dynamyx Coporation. +P.O. Box 1481 +King of Prussia, PA 19406 +(215) 265-6833 + +Services: Porting of all GNU software, Installation, Customization, and + Troubleshooting. (Unix, VMS, etc.) + +Rates: $50-$100/hr + +Experience: 5 years Unix application and systems programming. + 5 years compiler front-ends, interpreters, and + compiler-construction tools. + 3 years VMS applications. + X, C, and Ada experience. + +Entered: 2/21/89 + +Stephen Gildea +278 Beacon Street +Somerville, MA 02143 +work: +1 617 873-8240 +Emacs: general help, question answering, library writing, etc. + +Degree: B.S. in Computer Science `87, MIT + +Rates: $75/hr. + +Updated: 11/06/90 + +Ron Guilmette +Work: ICS Dept., University of Calif., Irvine +Home: 550 Paularino Ave. #B-108 + Costa Mesa, CA 92626 + 714-434-7666 +Categories: GCC, G++, Bison, GAS, LD, LD++ + +Entered: 12/13/89 + +Mike Haertel +St. Olaf College +Northfield, MN 55057 + +Experience: Unix Systems programmer at St. Olaf for several years. +Spent summer of 1988 at FSF writing and modifying various programs. + +Rates: $35/hr. + +Entered: 12 Aug 88 + +Sanjay Hiranandani +263 Conklin Ave. +Binghamton, NY 13903 +(607) 773-1430 + +Can help with installation, customization, and porting of most GNU +software. and General Unix/VMS Hacking. If you've got a PC with a hardware +problem, can probably fix that too. + +Rates: $30/hour or less, depending on the problem. + will probably work free or at a very low cost for non-profit + organizations, and poor students who're committed users of GNU + software. + Phone consultations free. + +Entered: 15 May 90 + +Paul Hudson <..!mcvax!ukc!acorn!moncam!paul> + +40 Dovehouse Close, +Ely, +Cambs, +CB7 4BY, +England. +(0353) 663381 ++44 (353) 663381 + +Installation of all GNU software. Support & changes to gcc, g++. Emacs +extensions. + +Degree in mathematics from Cambridge (UK!). + +Experience: I've written complete compilers & code +generators and a PostScript interpreter, and various graphics +programs. + +Rates: 25 pounds per hour, less for installation or non-profits. + +Entered: 2/21/89 + +Scott D. Kalter + +970 Palm Ave. #218 +West Hollywood, CA 90069 +(213)657-9174 + +Emacs: training for general use and customization + user support + e-lisp and C customization/extension + installation + troubleshooting + +Rates: $50/hr + +Qualifications: + BS Math/CS 1985: Carnegie Mellon University + MS CS 1988: UCLA + + Modified Emacs in C and e-lisp for large local extensions at + several sites. Taught Emacs use and customization in + universities and industry. Extensive troubleshooting and + user support experience. + +Entered: 24 Oct 1990 + +Jim Kingdon +East Wind +Route 3, box 6B2 +Tecumseh, Missouri 65760 +(417)679-4682 + +Willing to take on any gnu software; particularly knowledgeable about +the debugger (GDB) although I also have (varying amounts of) +experience with emacs, GCC, binutils, and others. I am familiar with +both VMS and Unix. I am particularly interested in porting GDB or GCC +to new machines, but am also interested in other programming tasks, +installation, user support, etc. + +Qualifications: Minor in computer science from Oberlin College, 2 +years experience in programming, helping users, system management. +Maintained GDB for the Free Software Foundation for a year. + +Rates: Negotiable, but as a ballpark figure $30/hr. Free or cheap to +Good Causes. + +Revised: 29 Nov 1990 + +Scott J. Kramer +2995 Woodside Road, Suite 400 +Woodside CA 94062 +(415) 961-0684 +Emacs: Tutoring, installations/upgrades, Lisp customizations, + general troubleshooting/support. Prefer that work I do + becomes part of the official Free Software Foundation + distribution. + +Rate: Task- and time-dependent; non-monetary offers considered. + +Entered: 11/05/86 + +Fen Labalme +Metaview Corp. +40 Carl St. #4 +San Francisco CA 94117 +(415) 731-1174 + +EMACS: Anything including teaching beginners / advanced users +UNIX: BSD 4.2 is what I have used most and best understand +I GROK: Mailers, network stuff, acronyms like RPC, NFS & IPC +X11.3: By the time you see this, I may understand X Windows +RATES: Free phone consultation; $100/hour plus; "Talk to me!" + Non-profits get lower rates or free; Barter considered +ETHICS: I require that (most) all software I create be available + for re-distribution as per the guidelines set by the + Free Software Foundation's General Public License. + +Revised: 3/13/89 + +Daniel LaLiberte + + +University of Illinois, Urbana-Champaign +Department of Computer Science +1304 W Springfield +Urbana, IL 61801 +217-333-2518 + +Emacs: Installation, some porting, troubleshooting. + Will do elisp extensions. + +Experience: I have extensive elisp programming experience. + I edited the GNU Emacs Lisp Reference Manual. + I've maintained Emacs for the UIUC CS Department + for three years. + +Rates: $30/hr + +Entered: 2/21/89 + +Dave Lawrence +76 1/2 13th St +Troy NY 12180 +(518) 273-5385 + +Services offered: GNU Emacs installation, lisp programming and + teaching for BSD and SYSV systems, particularly SUN. Programming + for GNUS newsreader and other outside processes are my specialty. + Installation of GNU C. + +Rates: free to non-profit organizations. + $30-40 hour for projects less than 8 hours projects. + $20 hour for longer projects. + Course fees negotiable with level of subject being taught. + Short queries answered free of charge. + +Qualifications: I'm "just a student", but don't let it disuade you. I + live in the GNU Emacs environment at least 6 hours of the average + day. While still learning the C code, I am proficient with the lisp + and can help customize as desired. + +Entered: 2/21/89 + +Jacob Levy +Dept of Computer Science +Weizmann Institute +Rehovot 76100 Israel +(+972)-8-482856 + +Services - + +Electronic, snail-mail and phone help with installation of GNU Emacs. +Will hand out on request source and local mods for GNU Emacs, as they +become available. Willing to help to maintain compatibility with +other/previous versions of Emacs, such as Gosling, CCA and MicroEmacs. +Preferable contact - through elec- tronic mail via BITNET. + +Rates - + +Free. Will only help as much as possible, not conflicting +with my main occupation in life, that of obtaining a Ph.D. + +Niall Mansfield +Vedelitz Systems +65 Oak Tree Avenue +Cambridge CB4 1AZ +England + +Emacs: installation, troubleshooting, customisation, extension + +Entered: 8/1/90 + +Roland McGrath +(617) 253-8568 +545 Tech Sq rm 426 +Cambridge, MA 02139 + +Co-author of GNU Make (with Richard Stallman). +Author of the GNU C Library. +Present maintainer of GNU Make and the GNU C Library. + +GNU volunteer May 1987 to the present. +FSF employee summer 1989, fall 1990 to the present. + +Installation, maintenance, porting, enhancement of all GNU software. + +Fees negotiable. I can work anywhere in the Boston or SF Bay Area, or +anywhere on the Internet. + +Revised: 12/15/90 + +Lee McLoughlin +Department of Computing, Imperial College, +180 Queens Gate, London. SW7 2BZ +01-589-5111 X 5028 + +EXPERIENCE: +I am responsible for putting GNU Emacs up under 4.1 BSD and for the +ports to the HLH Orion (and Orion 1/05) and the WhiteChapel MG-1. I +also developed and support the UK-UUCP and UK news distribution. +Ported X 10 to both the WhiteChapel MG-1 and HLH Orion. Ported X 11 +to the HLH Orion 1/05. I have been an invited speaker at several +recent UKUUG meetings. Helped, on the software side, in the setting +up of UKnet. Run a large Public Domain software archive. + +I am also an experienced Unix systems programmer. I've ported Unix to +a new machine (including porting PCC). Considerable compilers, +communications, mail and graphics experience. Hope to have enough +time in 89 to get all the UK-UUCP goodies into a gnu-uucp and to work +on porting gcc to the Clipper. + +SERVICES: +Porting gnuemacs and X. Installation and troubleshooting of any Gnu +and X software. + +RATES: +200-300 pounds a day, negotiable. General hand-holding free. + +NOTE: +Software archive contains all the current Gnu and X software. This is +available via Janet (the UK academic network), via uucp and I can be +talked into writing a tape, sun cartridge or exabyte. + +Revised: 2/26/89 + +Eric P. Meyer + +UUCP: {apple,uunet}!oracle!emeyer +Oracle Corp. +20 Davis Dr. +Belmont, CA 94002 +Work Phone: (415) 598 0000 +Home Phone: (415) 324 0944 + +I am very familliar in installing GNU Emacs, GNU GCC, GNU G++, libg++, +flex, bison, gawk, GNU grep, bin_utils... on UNIX and VMS systems. Also, +can deal with GNU X-related problems like Purdue Speedups for X servers +on SUNs. + +Rates: Free for Non-Profit Assoc. + $70/hr for companies. + +Entered: 2/21/89 + +Gary E. Miller +RELLIM +Mail Stop 202 +2680 Bayshore Parkway +Mountain View, CA 94043 +Tel: (415)964-1186 + +Services: Support for all GNU program development software. + 680x0, 80x86, 340x0 processors. + +Rates: $70/hr. or fixed price quotation + +Education: EE 1975 Brown U, E 1975 Brown U. + +Experience: 15 years systems software development + 8 years C/UNIX. 9 years DOS, also VMS. + +Entered: 10/31/89 + +T. S. Mohan UUNET: mohan%vidya@shakti.uu.net +KBCS (shakti!turing!vidya!mohan) +Supercomputer Education and Research Centre +Indian Institute of Science +Bangalore 560 012, India + +Offer: Willing to share my experience in installing and running GNU +software (more specifically Emacs and gcc) on VAXstations, (running +Ultrix) and other Unix machines free of cost to all academic +bretherens.....more so in India. All such efforts will be more +forthcoming when I have time to spare off other projects. + +Entered 1/03/90 + +Karl A. Nyberg +Grebyn Corporation +P. O. Box 497 {decuac,haven}!grebyn!karl +Vienna, VA 22183-0497 +703-281-2194 + +Emacs: installation aid, questions & answers, handholding, etc. + +Rates: negotiable. + +Can make TK50 cartridges for VAX/Ultrix. Timesharing also available for +those wishing to do development. + +Revised: 2/24/89 + +Optimal Solutions, Inc. +P.O. Box 45818 +Seattle, WA 98145 +(206) 682-1773 +Dennis Gentry +Tom May +Todd Cromwell + +Emacs: questions answered, teaching, customization, +troubleshooting, porting. Can install, port, and support VMS +Gnu Emacs, VMS gcc, Unix gcc and g++, and X Windows. + +Rates: $40-60/hr, 20 minute free initial consultation. +Non-profit/Educational discounts. + +Experience: Compiler, editor, and OS hacking, bit-twiddling, and +consulting at: the University of Washington, the Fred Hutchinson +Cancer Research Center, the National Science Foundation's Center +for Process Analytical Chemistry, Global Technology +International, others. + +Degrees: Honors B.S. Comp Sci, University of Washington; Summa +Cum Laude B.S. E.E., University of Washington. + +Revised: 2/26/89 + +The Pharos Group, Inc +Box 3546 +Las Cruces, NM 88003-3546 +(505) 525-2600 + +The pharos group offers consulting on the installation and +customization of gnu software, including gnu emacs, gnu cc and c++ and +the unix replacement utilities, on machines running unix. We have +members who are experienced in system administration, graphics, image +processing and networking. + +All modifications and extensions that we make to gnu software are +available freely. + +The best contacts for the pharos group are: + Ted Dunning (ted@pharos.com) + or + Jeff Harris (jeff@pharos.com) + +Entered: 2/21/89 + +Eric Raible +Nasa Ames Researh Center +Moffet Field, Ca +(415) 694-4320 + +Gnu emacs c and lisp programming; porting. General +unix/graphics/emacs hacking, especially on Silicon Graphics +workstations. + +Rates: free -> $30/hr depending on problem and how busy I am. + +Degree: MIT CS BS 1983. + +Entered 18 Dec 1987 + +Hedley K.J. Rainnie +UUCP: {uunet|ihnp4|allegra|harvard}!cmcl2!alaya!hedley + +545 West End Ave Apt 11E +NY NY 10024 +212-947-5711 (Work). + +Emacs: + +Rates: $12/hr. + + I am able to help in all aspects of GNU emacs, even porting. + My credentials are: + + MS in Computer Science from NYU. BS same same. + I have used many versions of Emacs since 1980. + I ask for $12hr. + +Entered: 5/29/90 + +Adam J. Richter <...!ucbvax!monet!adamj> +2600 Ridge Road +Berkeley, CA 94709 (415)549-6356 + +Difficult X-windows ports. Freeware preferred. Also looking for +someone to sponsor server improvements, including reorganization and +optimizations for the GNU C Compiler's extensions. Experienced. + +Entered: 3/13/89 + +Bruce Robertson + +Hundred Acre Software +1280 Terminal Way #26 +Reno, NV 89502 +(702) 329-9333 + +Rates: $70/hr long term, $50/hr short term + Non-profits are lower still, and negotiable + +Services: Anything to do with GNU software. My specialties include +porting Emacs, GCC and GDB to new environments. I also provide general +consulting services, in such areas as embedded systems, UNIX kernel porting, +and MS-DOS applications. + +Experience: Many different areas. Unix internals (all flavors), +SCSI (target and initiator), embedded systems, X11, TCP/IP, compilers, +device driver tuning, hardware debugging. + + +Revised: 10/31/90 + +Mike Rowan + mit-eddie!prep.ai.mit.edu!mtr +545 Technology Square room 426 +Cambridge, MA 02139 +(617) 253-8568 +Home: (508) 745-7554 + +FSF programmer since 1/90; Unix Systems programmer and all X11 work +from porting to admin and installation, Purdue University Computing +Center, 9/87 - 12/89 + +Rates: $50/hr as a base, depending on job, time, project length etc etc... + +Extensive X11 work. GNU libc, emacs, login, most anything. +Extensions, new projects, porting, fixes, installation, system +adminstration; just about anything. Systems programming experience +with all major flavors of Unix including 4.3, Dynix, SunOS and Ultrix. + +Entered: 4/7/90 +^_ +Wolfgang S. Rupprecht +PO Box 6524 +Alexandria, VA 22306 +(703) 768-2640 +Emacs: anything, (lisp, C, customization, porting, installing) +Rates: $75/hr. + +I have written thousands of lines of GNU Emacs C and Lisp code. +Original author of the floating point additions to appear in Emacs 19. + +Entered: 9/18/90 + +Isaac J. Salzman +The RAND Corporation - ISD/1 +1700 Main St. PO Box 2138 +Santa Monica, CA 90406-2138 ++1 213-393-0411 x6421 + +(UNIX ONLY!) +Emacs: Installation, customization, windows systems support (X10, X11, + SunView, NeWS), almost anything else. +GCC/G++: Installation, support. +X11: Installation, customization, support, some training, etc. All + available window managers, Andrew, InterViews. +Other: Consulting on - most GNUware, BSD UNIX IPC programming, most anything + that's BSD UNIX related. +Experience: 3.5+ years BSD UNIX systems programming (VAXen, Sun's) including + support of GNU Emacs. About 1.5+ years supporting X11, X10, gcc, + g++. Resume on request. +Rates: Negotiable on a per job basis. Probably $40/hr as a ballpark average. + +Entered: 2/21/89 + +Douglas C. Schmidt + +Department of Information and Computer Science +University of California, Irvine +Irvine, CA 92717 + +office: (714) 856-4043 +email: schmidt@ics.uci.edu + +GCC and G++: Installation and porting, question answering, customizing, etc. + +Experience: Wrote the GNU GPERF perfect hashing program, available from + the libg++ distribution , wrote the perfect hash functions that + recognize reserved words for G++ and GCC, contributed *many* bug + reports for GCC and G++ and also contributed bug fixes for + G++. In addition, I am actively building and maintaining a G++ + and GCC regression test suite (available on request). + +Rate: Negotiable + +Entered: 2/26/89 + +Randal L. Schwartz / Stonehenge Consulting Services / +1 503 777 0095 +Located in Beaverton, Oregon, USA (The Silicon RainForest...) +Electronic address variable (for now) ... call for the current one. +(I read and post to comp.emacs and gnu.emacs on USENET...) + +GNU Emacs: questions about general use, teaching, customization, + documentation, troubleshooting, porting, cute hacks (:-). + +Other GNU software: cross-trained on UN*X... proceed with caution... + +Experience: 17 years software development (one year with GNU Emacs), + 11 years technical communication (concurrent :-). + Also a C hacker and UN*X Guru... + +Rates: Free for short projects. Long projects may require money if + the project consumes significant billable time. + +Entered: 2/21/89 + +John Sechrest (hplabs!hp-pcd!orstcs!sechrest) +30606 Petersen Road +Corvallis, Oregon 97333 +(H) (503) 929-6278 +(W) (503) 754-3273 + +Emacs; User Support ; Tutorials/Training; System Consulting + +Rates: $50/hr, negotiable. + +I am willing to help people install and use both Gnu and Emacs. +I am particulary interested in installing Gnu on the National +ICM- 3216. + +As a consultant my normal fees are $50/hour. This is mostly +a guideline that varies on a case by case basis. + +I worked at Hewlett-Packard for four years. 2 years working +on the HP 41C extended I/O Rom. 2 years working on systems +support. For the last year and a half I have worked as the +Lab Coordinator for Oregon State University Computer Science +coordinating the use and maintenance of several machines. +I am most familiar with 4.2BSD on the vax 11/750 and +HP-UX on the HP series 200. + +Entered: 1/31/86 + +Steven C. Simmons +9353 Hidden Lake Circle +Dexter, MI. 48130 +313-426-8981 home +313-769-4086 office +Internet: scs@lokkur.dexter.mi.us +UUCP: ...!sharkey!lokkur!scs + +Gnu software: bison, flex, gcc, etc. Experience porting to BSD4.3 + Vaxes, Suns, Gould, some System V hosts. No MS-DOS. + +Rates: If all you need is a piece of source will gladly supply it + gratis if local call, at cost for long distance or tape (bring me a + blank). Can make std tar magtape or Sun cartridges. Advice is + free to a point. Compiling, porting, customizing: $65.00/hr plus + phone charges for offsite work, onsite rates negotiable. + +Professional Data: Currently administrator of a large UNIX shop in + Ann Arbor, MI. Maintain and support a variety of PD and + freely redistributable software on a variety of hosts. + +Entered: 5 June 1989 + +Lynn R. Slater +4433 Inyo Ct +Fremont Ca 94528. (415) 796-4149 +Emacs: Ada, X11, Lisp, interfaces to subordinate shell processes. + Prefer that work I do becomes part of the official Free + Software Foundation distribution. + +Rate: Free for good cause, otherwise task- and time-dependent. + +Entered: 2/21/89 + +Small Business Systems, Inc. +Box 17220, Route 104 +Smithfield, RI 02917 +(401) 273-4669 + +Principal Contact: mpd@anomaly.sbs.com (Michael P. Deignan, President) +Secondary Contact: ccc@anomaly.sbs.com (Cole C. Calistra, *NIX Systems Manager) + +Packages: All GNU Packages + +Services: training (singular or classroom environments) + Offered: user support (varied levels, including on-site & 24 hour "on call") + customization + installation + troubleshooting + you-name-it + + Rates: up to $75/hr. + + Notes: Services limited to Southeastern New England area (Route 128/93 in + MA and points south & east.) Will provide support into CT, only + as far west as Groton/New London area. (Anything beyond these + boundaries strains the acceptable level of user support we attempt + to maintain.) +Entered: 9/19/90 + +Richard M. Stallman +UUCP: {mit-eddie,ucbvax,uunet,harvard,uw-beaver}!ai.mit.edu!rms +545 Tech Sq, Rm 430 +Cambridge, MA 02139 + +Emacs: anything whatever + +Rates: $6/min or $250/hr. + +Is anyone interested in courses in using or extending GNU Emacs? + +Original inventor of Emacs and main author of GNU Emacs and GCC. + +Entered: 5/24/90 + +Jonathan Stone (uunet!vuwcomp!jonathan) + +Experience: + GNU Emacs:5 years on both Unix and VMS, in academic + and commercial environments: porting, user handholding, elisp programming, + termcap hacking, troubleshooting, VMS debugging. +GCC: 18 month gcc installation,use,bugfixing, porting + (gcc/gdb/almost gas port to Pyramid CPU; bootstrapped 1.22 on + vms, but not as nicely as Kashtan.) + +Fee: $NZ 130/hr + expenses; negotiable. + +Entered: 4 July 1989 + +Earl Stutes +223 Drakes Bay Ave. +Los Gatos, CA 95032 ++1 (408) 356 6841 + +Rate $3.00/min. or $90.00/hr. + +Installation and debug of all GNU software. +GNU emacs installation / troubleshooting. +emacs lisp programming. +20 years of programming experience. Working with UNIX for the +last 10 years. + +Entered: 31 May 1989 + +Bob Sutterfield + +work: home: +Ohio State University CIS Dept +2036 Neil Avenue 3542 Norwood Street +Columbus, Ohio 43210-1277 Columbus, Ohio 43224-3424 +(614)292-7348 (614)267-7611 + +Rates: $50/hr (negotiable) plus travel expenses + +Services: Installation, troubleshooting, and mild customization of + most GNU production and beta-test products; tutorials, + training, and handholding; general UNIX system and network + consulting. + +Entered: 2/21/89 + +Kayvan Sylvan + +Transact Software, Inc. +2672 Bayshore Parkway, Suite 700 +Mountain View, CA 94043 +Work: (415) 961-6112 +Home: (408) 733-2650 + +I will help you port, install and customize GNU Emacs, GCC, G++, bison, +and other GNU tools on almost any architecture and operating system. +Questions answered. GNU C and lisp hacking available. + +Rates: $30-$60/hour sliding scale. This is basically a flexible guideline. + +Experience: Many different Unix'es (2.9BSD to 4.3BSD, as well as AT&T System V +and Xenix) on many different machines. Systems programming and administration +on almost all these brands of Unix. Machines I've worked on include various +PDP's, VAXen, SUN workstations, Altos 386, Plexus P60, among others. +I can port anything to anything (within reason). + +Entered: 2/21/89 + +James W. Thompson +jthomp@sun.com +uunet!sun.com!jthomp +17601 Preson Road, #274 +Dallas, Tx. 75252 USA ++1 214-788-1951 + +EMACS/GDB: installation, porting, troubleshooting, hand holding. +Emacs elisp & C extensions and customization. + +GCC: porting, debugging, installation + +MIT X11R3: installation, porting + +SPECIALITIES: Convex, Vaxes and Suns. Can do VMS, not locally. +Network setup and troubleshooting. + +EXPERIENCE: Have hacked many (10+) different architectures in C, lisp, +& Fortran. Thurough understanding of BSD networking/NFS/RPC. +Responsible for Convex port of GNU emacs, gdb, gcc. 8 years system +'mothering' experiance. Resume available on request. + +Rates: 30.00/hour + travel expenses. Free for non-profits. + +Revised: 5/29/90 + +Leonard H. Tower Jr. +36 Porter Street +Somerville, MA 02143, USA ++1 (617) 623-7739 + +Will work on most GNU software. +Installation, handholding, trouble shooting, extensions, teaching. + +Rates: 50.00/hour + travel expenses. 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: 07/19/88 + +Jason Venner + +545 Pierce St. #2306 +Albany CA 94706 1046 +USA +415-525 2989 + +The only gnu software I do not work on are the compilers and the debuggers. +I have extensive experience with emacs (lisp and C) and C++ (via g++). +I have some experience with X, primarily V11R3 at the C level. +I have minimal experience with VMS. + +Rates: $100/hour for jobs < 8 hours (1 day), $70/hour for jobs +< 5 days, $60 for long term jobs, for all rate schedules expenses extra +Revised: 2/26/89 + +Watchmaker Computing +P.O.Box 163, Kendall Square +Cambridge, MA 02142 +email: support@watch.com + +Emacs: We'll do GNUEmacs support, porting, bug fixing, and customizing. +We also have specific expertise in: + packages: GCC, G++, X11, Xt, InterViews, PERL, TeX, Epoch + languages: C, C++, Lisp, most others; we learn quickly! +Extensive experience coding for portability under UNIX. +Typical rates $35-$150/hour; will telecommute (Internet or phone) + +Entered: 1/16/91 + +Scott Weikart (hplabs!cdp!scott) +EMACS: user handholding, elisp programming and troubleshooting, porting +1944c University +East Palo Alto, CA 94303 +(415) 322-9069 +I used ITS EMACS for 5 years and Gosling EMACS for 2 years +I've written thousands of lines of TECO and thousands of lines of mlisp +I've ported many programs to SysIII/SysV Unix +Sliding scale rates, barter possible, lower rates for non-profits + +Entered: 1/30/86 + +Chris Welty +RPI Computer Science Dept +Troy, NY 12180 +518-276-2816 + +Services: questions, installation, etc for all GNU programs, +especially emacs customization. Maintainer of the NYSERNet GNU src +distribution site, containing all GNU programs. Primarily knowledge of +Berkeley UNIX systems, especially Sun, but some limited expertise for +other systems. + +Rates: Free to NYSERNet members, others by arrangement (generally not +money but `Stingray' type barter...:) + +EMail correspondance preferred. + +Entered: 2/27/89 + +Pace Willisson + uunet!blitz!pace +Blitz Product Development Corporation +6 Hudson Street +Somerville, MA 02143, USA +(617) 625-3452 + +Will work on any GNU software. + +Rates: $80.00/hour + +Experience: BS in Computer Science from MIT. 11 years working with C, +Unix and Lisp Machines including compilation systems, networks, device +drivers, demand paging systems, boot programs and window systems. +Ported GDB to 80386. Designed COFF encapsulation scheme to run GNU +linker output on System 5 kernels. Author of Unix "ispell". + +Updated: 10/27/90 + +Name: Patrick Wood +Company: Pipeline Associates, Inc. +E-mail: {sun,motown,amdcad}!pipeline!phw +Will help with: installing gcc, using gcc as cross-compiler and embedded + system development, ditto for gnu binutils, help with 680x0 systems, + unix security, unix internals, graphics, embedded systems programming. +Fees: free for email (1-2 day turnaround); too busy for phone or direct + consultation. +Qualificatios: BS CS Purdue, MS CICE Michigan, 6 years Bell Labs (security, + performance measurement/tuning, graphics, device drivers, embedded + OS development), 5 years VP R&D Pipeline Associates, Inc. (graphics, + PostScript, training, security auditing software, embedded systems + programming, color print drivers, color separation, writing, editing). + Used gcc and binutils for about two years now (starting with gcc 1.31) + on VAX/Ultrix, Sony News, 386/ix, and embedded systems (Intel 960 and + 68000). Modified gcc and binutils for cross development on 386 to + 68000 embedded system. Wrote general-purpose peephole optimizer for + assembly output of gcc. +Entered: 9/19/90 + +** Please keep this file alphabetical ** diff --git a/gcc-1.40/TAGS b/gcc-1.40/TAGS new file mode 100644 index 0000000..08c67a2 --- /dev/null +++ b/gcc-1.40/TAGS @@ -0,0 +1,1948 @@ + +c-parse.y,401 +1129,32578 +check_newline 1767,50903 +combine_strings 1325,38158 +extend_token_buffer 1750,50444 +hash 1464,42306 +init_lex 1620,47567 +is_reserved_word 1517,44137 +#define isalnum(1965,55601 +#define isdigit(1966,55718 +make_pointer_declarator 1314,37880 +readescape 1971,55842 +reinit_parse_for_function 1651,48897 +skip_white_space 1659,49051 +%token 97,3096 +yyerror 2070,57799 +yylex 2098,58556 + +cexp.y,216 +error 638,14446 +initialize_random_junk 608,13790 +lookup 649,14564 +main 575,13006 +parse_c_expression 548,12280 +parse_escape 437,10143 +parse_number 217,5686 +warning 643,14494 +yyerror 533,11933 +yylex 312,7415 + +assert.h,118 +#define __assert(17,345 +#define __assert(26,643 +#define assert(7,136 +#define assert(14,239 +#define assert(23,538 + +basic-block.h,0 + +c-parse.h,0 + +c-tree.h,243 +#define C_TYPE_FIELDS_READONLY(46,1679 +#define IDENTIFIER_ERROR_LOCUS(39,1420 +#define IDENTIFIER_GLOBAL_VALUE(31,1050 +#define IDENTIFIER_IMPLICIT_DECL(37,1325 +#define IDENTIFIER_LABEL_VALUE(35,1234 +#define IDENTIFIER_LOCAL_VALUE(33,1143 + +conditions.h,0 + +expr.h,376 +#define ADD_PARM_SIZE(85,3281 +#define ARGS_SIZE_RTX(104,3921 +#define FUNCTION_ARG_PADDING(116,4371 +#define FUNCTION_ARG_PADDING(123,4631 +#define GEN_FCN(165,5924 +#define QUEUED_BODY(35,1454 +#define QUEUED_COPY(32,1317 +#define QUEUED_INSN(29,1159 +#define QUEUED_NEXT(37,1522 +#define QUEUED_VAR(26,993 +#define RETURN_IN_MEMORY(132,4878 +#define SUB_PARM_SIZE(94,3548 + +flags.h,0 + +gdbfiles.h,0 + +gstab.h,28 +#define __define_stab(7,87 + +gstdarg.h,154 +#define __va_rounded_size(18,495 +#define va_arg(34,908 +#define va_arg(38,1073 +#define va_end(31,872 +#define va_start(22,620 +#define va_start(25,705 + +gvarargs.h,97 +#define va_arg(58,1120 +#define va_end(53,993 +#define va_start(47,827 +#define va_start(51,932 + +hard-reg-set.h,877 +#define AND_COMPL_HARD_REG_SET(93,3217 +#define AND_COMPL_HARD_REG_SET(135,4751 +#define AND_HARD_REG_SET(92,3165 +#define AND_HARD_REG_SET(129,4528 +#define CLEAR_HARD_REG_BIT(79,2732 +#define CLEAR_HARD_REG_BIT(100,3466 +#define CLEAR_HARD_REG_SET(84,2862 +#define CLEAR_HARD_REG_SET(105,3698 +#define COMPL_HARD_REG_SET(88,2998 +#define COMPL_HARD_REG_SET(123,4302 +#define COPY_HARD_REG_SET(87,2946 +#define COPY_HARD_REG_SET(117,4079 +#define GO_IF_HARD_REG_SUBSET(95,3278 +#define GO_IF_HARD_REG_SUBSET(153,5436 +#define IOR_COMPL_HARD_REG_SET(91,3105 +#define IOR_COMPL_HARD_REG_SET(147,5205 +#define IOR_HARD_REG_SET(90,3053 +#define IOR_HARD_REG_SET(141,4982 +#define SET_HARD_REG_BIT(77,2671 +#define SET_HARD_REG_BIT(98,3354 +#define SET_HARD_REG_SET(85,2904 +#define SET_HARD_REG_SET(111,3889 +#define TEST_HARD_REG_BIT(81,2798 +#define TEST_HARD_REG_BIT(102,3583 + +input.h,0 + +limits.h,0 + +math-68881.h,1255 +__inline static const double acos 89,2200 +__inline static const double asin 79,2060 +__inline static const double atan 99,2340 +__inline static const double atan2 109,2480 +__inline static const double atanh 195,3860 +__inline static const double ceil 323,5804 +__inline static const double cos 59,1784 +__inline static const double cosh 175,3580 +__inline static const double drem 398,7450 +__inline static const double exp 205,4002 +__inline static const double expm1 215,4141 +__inline static const double fabs 313,5665 +__inline static const double floor 344,6287 +__inline static const double fmod 387,7288 +__inline static double frexp 441,8085 +__inline static const double ldexp 430,7921 +__inline static const double log 225,4284 +__inline static const double log10 245,4566 +__inline static const double log1p 235,4423 +__inline static double logb 420,7776 +__inline static double modf 465,8636 +__inline static const double pow 265,4848 +__inline static const double rint 366,6789 +__inline static const double scalb 409,7612 +__inline static const double sin 49,1646 +__inline static const double sinh 165,3440 +__inline static const double sqrt 255,4708 +__inline static const double tan 69,1922 +__inline static const double tanh 185,3720 + +obstack.h,1411 +#define __INT_TO_PTR(121,5180 +#define __PTR_TO_INT(117,5109 +#define obstack_1grow(249,9791 +#define obstack_1grow(347,13379 +#define obstack_1grow_fast(211,8451 +#define obstack_alignment_mask(203,8188 +#define obstack_alloc(285,11184 +#define obstack_alloc(371,14320 +#define obstack_base(191,7859 +#define obstack_begin(208,8342 +#define obstack_blank(277,10913 +#define obstack_blank(365,14111 +#define obstack_blank_fast(213,8518 +#define obstack_chunk_size(195,7948 +#define obstack_copy(290,11339 +#define obstack_copy(374,14415 +#define obstack_copy0(295,11505 +#define obstack_copy0(377,14522 +#define obstack_finish(300,11673 +#define obstack_finish(380,14631 +#define obstack_free(312,12151 +#define obstack_free(392,15092 +#define obstack_free(399,15425 +#define obstack_grow(230,9106 +#define obstack_grow(332,12812 +#define obstack_grow0(239,9427 +#define obstack_grow0(339,13074 +#define obstack_init(205,8245 +#define obstack_int_grow(267,10480 +#define obstack_int_grow(357,13750 +#define obstack_int_grow_fast(275,10833 +#define obstack_int_grow_fast(363,14031 +#define obstack_next_free(199,8062 +#define obstack_object_size(222,8824 +#define obstack_object_size(326,12622 +#define obstack_ptr_grow(260,10202 +#define obstack_ptr_grow(352,13543 +#define obstack_ptr_grow_fast(274,10749 +#define obstack_ptr_grow_fast(362,13947 +#define obstack_room(226,8968 +#define obstack_room(329,12720 + +output.h,0 + +proto.h,22 +#define _PROTO(4,113 + +real.h,347 +#define CONST_DOUBLE_CHAIN(84,2619 +#define CONST_DOUBLE_HIGH(81,2506 +#define CONST_DOUBLE_LOW(80,2466 +#define CONST_DOUBLE_MEM(88,2824 +#define REAL_VALUES_EQUAL(34,1187 +#define REAL_VALUES_LESS(39,1320 +#define REAL_VALUE_ATOF(50,1582 +#define REAL_VALUE_LDEXP(44,1428 +#define REAL_VALUE_NEGATE(56,1717 +#define REAL_VALUE_TRUNCATE(61,1854 + +recog.h,0 + +regs.h,236 +#define CALLER_SAVE_PROFITABLE(145,5167 +#define PSEUDO_REGNO_BYTES(66,2302 +#define PSEUDO_REGNO_MODE(71,2421 +#define PSEUDO_REGNO_SIZE(60,2119 +#define REGNO_POINTER_FLAG(128,4621 +#define REG_BYTES(22,809 +#define REG_SIZE(28,1076 + +reload.h,0 + +rtl.h,2731 +#define ASM_OPERANDS_INPUT(405,14931 +#define ASM_OPERANDS_INPUT_CONSTRAINT(406,14990 +#define ASM_OPERANDS_INPUT_CONSTRAINT_VEC(404,14868 +#define ASM_OPERANDS_INPUT_MODE(407,15070 +#define ASM_OPERANDS_INPUT_VEC(403,14816 +#define ASM_OPERANDS_OUTPUT_CONSTRAINT(401,14703 +#define ASM_OPERANDS_OUTPUT_IDX(402,14763 +#define ASM_OPERANDS_SOURCE_FILE(408,15145 +#define ASM_OPERANDS_SOURCE_LINE(409,15199 +#define ASM_OPERANDS_TEMPLATE(400,14652 +#define CODE_LABEL_NUMBER(300,10845 +#define CONST0_RTX(529,19332 +#define CONSTANT_P(205,6353 +#define CONSTANT_POOL_ADDRESS_P(424,15762 +#define CONTAINING_INSN(374,13847 +#define DEF_MACHMODE(53,1680 +#define EXTERNAL_SYMBOL_P(426,15885 +#define FIRST_FUNCTION_INSN(442,16695 +#define FIRST_LABELNO(444,16797 +#define FIRST_PARM_INSN(443,16748 +#define FUNCTION_ARGS_SIZE(448,16987 +#define GET_CODE(172,5414 +#define GET_CODE(175,5536 +#define GET_MODE(179,5632 +#define GET_MODE_BITSIZE(95,2777 +#define GET_MODE_CLASS(81,2359 +#define GET_MODE_MASK(100,2939 +#define GET_MODE_NAME(72,2051 +#define GET_MODE_SIZE(86,2497 +#define GET_MODE_UNIT_SIZE(91,2657 +#define GET_MODE_WIDER_MODE(107,3192 +#define GET_NOTE_INSN_NAME(348,12757 +#define GET_NUM_ELEM(196,6113 +#define GET_REG_NOTE_NAME(295,10614 +#define GET_RTX_FORMAT(46,1545 +#define GET_RTX_LENGTH(40,1383 +#define GET_RTX_NAME(43,1465 +#define INSN_CODE(234,7390 +#define INSN_DELETED_P(244,7829 +#define INSN_UID(223,7017 +#define INTVAL(390,14341 +#define JUMP_LABEL(357,13207 +#define LABEL_NEXTREF(369,13680 +#define LABEL_NUSES(352,12955 +#define LABEL_REFS(363,13469 +#define LAST_LABELNO(445,16846 +#define LOG_LINKS(241,7747 +#define MAX_PARMREG(446,16894 +#define MAX_REGNUM(447,16941 +#define MEM_IN_STRUCT_P(416,15458 +#define MEM_VOLATILE_P(413,15340 +#define NEXT_INSN(227,7150 +#define NOTE_DECL_CODE(340,12459 +#define NOTE_DECL_IDENTIFIER(342,12560 +#define NOTE_DECL_NAME(339,12407 +#define NOTE_DECL_RTL(341,12511 +#define NOTE_DECL_TYPE(343,12618 +#define NOTE_LINE_NUMBER(311,11213 +#define NOTE_SOURCE_FILE(307,11027 +#define PATTERN(230,7224 +#define PREV_INSN(226,7105 +#define PUT_CODE(173,5469 +#define PUT_CODE(176,5573 +#define PUT_MODE(180,5669 +#define PUT_NUM_ELEM(197,6162 +#define REGNO(378,13956 +#define REG_FUNCTION_VALUE_P(383,14107 +#define REG_NOTES(282,10160 +#define REG_NOTE_KIND(290,10471 +#define REG_P(201,6258 +#define REG_USERVAR_P(386,14238 +#define RTX_INTEGRATED_P(182,5721 +#define RTX_UNCHANGING_P(183,5771 +#define SET_DEST(420,15605 +#define SET_SRC(421,15647 +#define SUBREG_REG(395,14502 +#define SUBREG_WORD(396,14546 +#define XEXP(212,6578 +#define XINT(213,6619 +#define XSTR(214,6662 +#define XVEC(215,6705 +#define XVECEXP(217,6804 +#define XVECLEN(216,6748 + +stddef.h,26 +#define offsetof(56,1179 + +symseg.h,0 + +tree.h,3791 +#define CALL_EXPR_RTL(394,13643 +#define CONSTRUCTOR_ELTS(397,13750 +#define DECL_ALIGN(488,17492 +#define DECL_ARGUMENTS(480,17031 +#define DECL_ARG_TYPE(481,17111 +#define DECL_ASSEMBLER_NAME(477,16861 +#define DECL_BLOCK_SYMTAB_ADDRESS(491,17624 +#define DECL_CONTEXT(478,16925 +#define DECL_FIELD_CONTEXT(479,16975 +#define DECL_FRAME_SIZE(494,17826 +#define DECL_FUNCTION_CODE(473,16604 +#define DECL_INITIAL(483,17235 +#define DECL_LANG_SPECIFIC(495,17882 +#define DECL_MODE(489,17538 +#define DECL_NAME(475,16761 +#define DECL_OFFSET(472,16556 +#define DECL_PRINT_NAME(476,16805 +#define DECL_RESULT(482,17187 +#define DECL_RESULT_TYPE(470,16416 +#define DECL_RTL(490,17582 +#define DECL_SAVED_INSNS(493,17768 +#define DECL_SET_FUNCTION_CODE(474,16684 +#define DECL_SIZE(486,17394 +#define DECL_SIZE_UNIT(487,17438 +#define DECL_SOURCE_FILE(484,17285 +#define DECL_SOURCE_LINE(485,17340 +#define DECL_SYMTAB_INDEX(492,17700 +#define DECL_VOFFSET(469,16321 +#define DECL_VOFFSET_UNIT(471,16496 +#define DEFTREECODE(23,809 +#define DEF_MACHMODE(51,1551 +#define IDENTIFIER_LENGTH(363,12775 +#define IDENTIFIER_POINTER(364,12835 +#define INT_CST_LT(295,10757 +#define INT_CST_LT_UNSIGNED(300,10970 +#define RTL_EXPR_RTL(391,13539 +#define RTL_EXPR_SEQUENCE(390,13459 +#define SAVE_EXPR_RTL(387,13355 +#define STMT_BIND_SIZE(570,20192 +#define STMT_BODY(537,19373 +#define STMT_CASE_INDEX(585,20599 +#define STMT_CASE_LIST(586,20655 +#define STMT_COND(551,19638 +#define STMT_ELSE(553,19736 +#define STMT_SOURCE_FILE(536,19318 +#define STMT_SOURCE_LINE(535,19264 +#define STMT_SUBBLOCKS(572,20310 +#define STMT_SUPERCONTEXT(569,20127 +#define STMT_THEN(552,19685 +#define STMT_TYPE_TAGS(571,20251 +#define STMT_VARS(568,20078 +#define TREE_ADDRESSABLE(212,6765 +#define TREE_ASM_WRITTEN(272,9712 +#define TREE_CHAIN(184,5438 +#define TREE_CODE(167,4622 +#define TREE_COMPLEXITY(401,13903 +#define TREE_CST_RTL(316,11525 +#define TREE_EXTERNAL(191,5690 +#define TREE_IMAGPART(350,12439 +#define TREE_INLINE(276,9874 +#define TREE_INT_CST_HIGH(293,10693 +#define TREE_INT_CST_LOW(292,10632 +#define TREE_LANG_FLAG_1(281,10042 +#define TREE_LANG_FLAG_2(282,10102 +#define TREE_LANG_FLAG_3(283,10162 +#define TREE_LANG_FLAG_4(284,10222 +#define TREE_LITERAL(248,8579 +#define TREE_NONLOCAL(257,9007 +#define TREE_OPERAND(400,13847 +#define TREE_PACKED(242,8336 +#define TREE_PERMANENT(262,9225 +#define TREE_PUBLIC(199,6045 +#define TREE_PURPOSE(374,13030 +#define TREE_READONLY(235,7955 +#define TREE_REALPART(349,12388 +#define TREE_REAL_CST(323,11764 +#define TREE_REGDECL(217,7030 +#define TREE_SET_CODE(168,4685 +#define TREE_STATIC(195,5882 +#define TREE_STRING_LENGTH(336,12051 +#define TREE_STRING_POINTER(337,12108 +#define TREE_THIS_VOLATILE(230,7698 +#define TREE_TYPE(173,4971 +#define TREE_UID(163,4492 +#define TREE_UNSIGNED(266,9411 +#define TREE_USED(279,9990 +#define TREE_VALUE(375,13080 +#define TREE_VOLATILE(225,7471 +#define TYPE_ALIGN(418,14424 +#define TYPE_ARG_TYPES(422,14614 +#define TYPE_BASETYPES(437,15416 +#define TYPE_DOMAIN(420,14518 +#define TYPE_FIELDS(421,14566 +#define TYPE_LANG_SPECIFIC(439,15536 +#define TYPE_MAIN_VARIANT(436,15356 +#define TYPE_MAX_VALUE(430,15031 +#define TYPE_METHOD_BASETYPE(423,14665 +#define TYPE_MIN_VALUE(429,14983 +#define TYPE_MODE(417,14380 +#define TYPE_NAME(434,15252 +#define TYPE_NEXT_VARIANT(435,15296 +#define TYPE_NONCOPIED_PARTS(438,15470 +#define TYPE_OFFSET_BASETYPE(424,14719 +#define TYPE_PARSE_INFO(432,15132 +#define TYPE_POINTER_TO(427,14867 +#define TYPE_PRECISION(431,15079 +#define TYPE_REFERENCE_TO(428,14923 +#define TYPE_SEP(425,14773 +#define TYPE_SEP_UNIT(426,14815 +#define TYPE_SIZE(415,14282 +#define TYPE_SIZE_UNIT(416,14326 +#define TYPE_SYMTAB_ADDRESS(433,15188 +#define TYPE_VALUES(419,14470 + +typeclass.h,0 + +va-i860.h,48 +#define va_end(19,353 +#define va_start(17,261 + +va-mips.h,94 +#define va_arg(24,697 +#define va_arg(27,781 +#define va_end(21,611 +#define va_start(20,555 + +va-pyr.h,75 +#define va_arg(86,2624 +#define va_end(100,3117 +#define va_start(77,2402 + +va-sparc.h,71 +#define va_arg(26,874 +#define va_end(19,615 +#define va_start(16,494 + +va-spur.h,48 +#define va_end(22,468 +#define va_start(19,338 + +alloca.c,47 +alloca 139,3910 +find_stack_direction 83,2467 + +c-convert.c,101 +convert 365,11693 +convert_to_integer 113,3457 +convert_to_pointer 49,1887 +convert_to_real 83,2663 + +c-decl.c,1354 +#define MAX(46,1633 +#define MIN(45,1592 +build_enumerator 3618,112971 +builtin_function 1731,54717 +c_build_type_variant 2937,92546 +complete_array_type 2121,66839 +declare_parm_level 484,13952 +define_label 1335,41551 +duplicate_decls 746,21850 +finish_decl 1941,61146 +finish_enum 3536,110852 +finish_function 4046,126943 +finish_struct 3248,102314 +get_parm_info 3061,96701 +getdecls 1361,42207 +gettags 1369,42346 +global_bindings_p 459,13482 +grokdeclarator 2213,69720 +grokfield 3231,101884 +grokparms 2968,93804 +groktypename 1805,56643 +implicitly_declare 1201,37261 +in_parm_level_p 491,14074 +init_decl_processing 1504,45885 +keep_next_level 465,13569 +kept_level_p 473,13693 +lang_decode_option 374,10971 +layout_array_type 3473,108986 +lookup_label 1309,40965 +lookup_name 1463,44899 +lookup_name_current_level 1480,45318 +lookup_tag 1405,43362 +lookup_tag_reverse 1440,44309 +make_binding_level 450,13294 +parmlist_tags_warning 3119,98492 +poplevel 557,15942 +print_lang_identifier 434,12742 +push_parm_decl 2106,66384 +pushdecl 975,29770 +pushlevel 501,14284 +pushtag 717,21113 +redeclaration_error_message 1255,38976 +shadow_tag 1753,55471 +start_decl 1835,57696 +start_enum 3488,109412 +start_function 3675,114746 +start_struct 3194,100807 +store_parm_decls 3773,118279 +storedecls 1379,42616 +storetags 1388,42773 +xref_tag 3145,99193 + +c-typeck.c,1439 +actualparameterlist 1037,30359 +binary_op_error 1753,53801 +build_array_ref 860,24661 +build_binary_op 1132,33189 +build_binary_op_nodefault 1159,34304 +build_c_cast 2865,85589 +build_component_ref 756,21658 +build_compound_expr 2834,84780 +build_conditional_expr 2645,78728 +build_function_call 945,27324 +build_indirect_ref 815,23267 +build_modify_expr 2940,87847 +build_unary_op 2091,63615 +c_alignof 615,17266 +c_expand_asm_operands 3685,109774 +c_expand_return 3740,111662 +c_expand_start_case 3777,112832 +c_sizeof 573,16279 +c_sizeof_nowarn 597,16828 +commontype 177,4958 +comp_target_types 401,11439 +compparms 417,11912 +compparms1 449,12662 +comptypes 324,9157 +convert_for_assignment 3109,93097 +convert_sequence 2375,71351 +datatype 61,2013 +decl_constant_value 632,17628 +default_conversion 660,18695 +digest_init 3319,99498 +get_floating_type 560,15976 +incomplete_type_error 95,2881 +initializer_constant_valid_p 3208,96408 +invert_truthvalue 2529,75970 +language_lvalue_valid 3094,92680 +mark_addressable 2602,77848 +pointer_diff 1716,52727 +pointer_int_sum 1646,50532 +process_init_constructor 3519,105493 +qualify_type 158,4350 +readonly_warning 2432,72767 +require_complete_type 76,2406 +shorten_compare 1820,55611 +signed_or_unsigned_type 512,14214 +signed_type 492,13665 +store_init_value 3266,97932 +truthvalue_conversion 2470,73844 +type_for_size 536,15234 +unary_complex_lvalue 2404,72046 +unsigned_type 473,13141 + +caller-save.c,223 +choose_hard_reg_mode 644,20496 +clear_reg_live 171,4779 +emit_mult_restore 407,12646 +emit_mult_save 241,7003 +grow_save_block 595,19012 +insert_call_saves 198,5527 +save_call_clobbered_regs 53,1652 +set_reg_live 129,3703 + +cccp.c,2123 +#define CHECK_DEPTH(236,6117 +#define HASHSTEP(427,13278 +#define MAKE_POS(428,13320 +#define SKIP_ALL_WHITE_SPACE(481,15077 +#define SKIP_WHITE_SPACE(480,15002 +#define S_ISREG(93,2459 +bcmp 5457,141995 +bcopy 5435,141611 +bzero 5414,141231 +#define check_expand(259,6838 +DEFINITION *collect_expansion 499,15621 +collect_expansion 3063,82239 +comp_def_part 3014,80505 +compare_defs 2972,79128 +conditional_skip 3670,97953 +delete_macro 5072,133462 +deps_output 5384,140557 +discard_comments 4711,125069 +do_define 2827,75236 +do_elif 3567,95193 +do_else 3860,102532 +do_endif 3898,103488 +do_error 3454,92286 +do_if 3550,94832 +do_include 2495,66550 +do_line 3319,88959 +do_once 3471,92719 +do_pragma 3496,93263 +do_pragma 3513,93680 +do_sccs 3531,94206 +do_undef 3430,91676 +do_xifdef 3632,96891 +dump_all_macros 5122,134429 +dump_arg_n 5209,136369 +dump_defn_1 5185,135776 +error 4810,127148 +error_from_errno 4832,127560 +error_with_line 4883,128537 +eval_if_expression 3608,96300 +expand_to_temp_buffer 2010,55264 +fancy_abort 5491,142774 +fatal 5478,142470 +file_size_and_mode 5597,144647 +finclude 2708,72296 +grow_outbuf 4938,129887 +hack_vms_include_specification 5616,145131 +handle_directive 2088,57094 +hashf 5106,134157 +initialize_builtins 5267,137618 +initialize_char_syntax 5227,136694 +install 4979,131180 +line_for_error 4912,129349 +lookup 5033,132411 +macarg 4476,118794 +macarg1 4614,123072 +macroexpand 4199,111304 +main 541,16646 +make_definition 5289,138449 +make_undef 5356,139920 +#define max(90,2401 +memory_full 5525,143296 +name_newline_fix 1198,32913 +newline_fix 1163,32079 +output_line_command 4124,109153 +perror_with_name 5497,142832 +pfatal_with_name 5512,143145 +pipe_closed 535,16581 +#define read(79,2132 +read 5747,149851 +rescan 1266,35470 +savestring 5584,144374 +skip_if_group 3700,98606 +skip_quoted_string 4051,107343 +skip_to_end_of_comment 3967,105320 +special_symbol 2361,63695 +struct 337,9921 +trigraph_pcp 1094,30511 +validate_else 3923,104201 +warning 4860,128111 +#define write(80,2184 +write 5774,150365 +xcalloc 5555,143726 +xmalloc 5532,143355 +xrealloc 5543,143526 + +combine.c,682 +#define INSN_CUID(116,4586 +add_incs 2323,76198 +add_links 2265,74861 +adjacent_insns_p 2217,73715 +check_asm_operands 2233,74104 +combine_instructions 208,6948 +copy_substitutions 804,27353 +dump_combine_stats 2769,88296 +dump_combine_total_stats 2784,88751 +gen_lowpart_for_combine 1910,65642 +#define max(73,3194 +#define min(74,3235 +move_deaths 2366,77267 +move_deaths_2 2412,78428 +record_dead_and_set_regs 2092,70506 +regno_dead_p 2197,73279 +remove_death 2337,76529 +remove_links 2299,75731 +simplify_and_const_int 1745,59136 +simplify_set_cc0_and 1955,67118 +subst 830,28266 +try_combine 362,12038 +try_distrib 2494,80828 +undo_all 787,26905 +use_crosses_set_p 2152,72243 + +cse.c,1103 +#define CHEAPER(918,29015 +#define FIXED_BASE_PLUS_P(409,15901 +#define HASH(366,14369 +#define HASHREG(1299,39942 +#define INSN_CUID(289,11628 +canon_hash 1303,40033 +canon_reg 1711,49568 +cse_basic_block 3850,111876 +cse_end_of_basic_block 3692,107286 +cse_insn 2829,78805 +cse_main 3752,109171 +cse_rtx_addr_varies_p 1696,49224 +equiv_constant 2506,69550 +exp_equiv_p 1472,44188 +fold_cc0 2549,71006 +fold_rtx 1782,51518 +free_element 729,24088 +get_element 739,24286 +get_integer_term 1180,36744 +get_related_value 1199,37159 +insert 928,29464 +insert_regs 672,22396 +invalidate 1060,33657 +invalidate_from_clobbers 3650,106172 +invalidate_memory 1153,36055 +lookup 827,26451 +lookup_as_function 876,27630 +lookup_for_remove 845,26891 +make_new_qty 519,18473 +make_regs_eqv 533,18711 +mention_regs 628,21248 +new_basic_block 477,17571 +note_mem_written 3607,104689 +predecide_loop_entry 2685,74245 +refers_to_mem_p 1615,47341 +refers_to_p 1553,45961 +reg_invalidate 582,20223 +remove 757,24754 +remove_invalid_refs 1133,35594 +rtx_cost 435,16723 +safe_hash 1450,43457 +use_related_value 1225,37821 + +dbranch.c,240 +dbr_dblock_sched 352,11248 +dbr_schedule 416,13167 +emit_delay_sequence 320,10431 +enote 194,7349 +in_dep_list_p 222,7920 +init_flags 175,6853 +insn_eligible_p 241,8469 +pnote 146,6219 +prepend_to_dep_list 289,9639 +update_flags 307,10096 + +dbxout.c,507 +#define CHARS(149,5536 +dbxout_args 1014,31421 +dbxout_block 1091,33524 +dbxout_continue 214,7353 +dbxout_finish_symbol 814,24531 +dbxout_function 1160,35459 +dbxout_function 1197,36081 +dbxout_init 178,6260 +dbxout_init 1175,35814 +dbxout_parms 850,25560 +dbxout_reg_parms 958,29404 +dbxout_symbol 581,17358 +dbxout_symbol 1181,35912 +dbxout_syms 827,24835 +dbxout_tags 1050,32288 +dbxout_tags 1192,36037 +dbxout_type 237,8027 +dbxout_type_name 554,16690 +dbxout_types 1031,31761 +dbxout_types 1187,35981 + +emit-rtl.c,1567 +add_insn 827,21860 +add_insn_after 846,22192 +change_address 483,14080 +classify_insn 1253,31047 +copy_rtx_if_shared 580,16748 +delete_insns_since 872,22784 +emit 1291,31979 +emit_barrier 1165,29245 +emit_barrier_after 1025,26341 +emit_call_insn 1130,28508 +emit_call_insn_before 973,25200 +emit_insn 1074,27437 +emit_insn_after 985,25470 +emit_insn_before 919,23979 +emit_insns 1098,27893 +emit_jump_insn 1113,28151 +emit_jump_insn_after 1012,26081 +emit_jump_insn_before 952,24736 +emit_label 1147,28848 +emit_label_after 1039,26582 +emit_line_note 1179,29588 +emit_line_note_force 1232,30574 +emit_note 1200,29993 +emit_note_after 1055,26969 +end_sequence 1349,33385 +force_next_line_note 1244,30848 +gen_highpart 418,12355 +gen_inline_header_rtx 520,14959 +gen_label_rtx 507,14648 +gen_lowpart 360,10434 +gen_reg_rtx 290,8739 +gen_rtvec 246,7932 +gen_rtvec_v 268,8289 +gen_rtx 175,6316 +gen_sequence 1364,33776 +get_first_label_num 348,10059 +get_insns 732,20218 +get_last_insn 740,20339 +get_max_uid 759,20623 +init_emit 1537,37593 +init_emit_once 1567,38372 +make_insn_raw 785,21025 +make_jump_insn_raw 805,21391 +make_safe_from 693,19363 +mark_reg_pointer 323,9671 +#define max(44,1567 +max_label_num 340,9937 +max_reg_num 332,9835 +#define min(45,1608 +next_insn 765,20670 +previous_insn 773,20760 +push_to_sequence 1329,32852 +reorder_insns 887,23116 +restore_reg_data 1408,34879 +restore_reg_data_1 1445,35583 +set_last_insn 748,20439 +set_new_first_and_last_insn 540,15577 +start_sequence 1314,32511 +subreg_lowpart_p 459,13443 +unshare_all_rtl 556,15980 + +explow.c,536 +adjust_stack 495,13888 +anti_adjust_stack 511,14287 +break_out_memory_refs 184,4971 +copy_addr_to_reg 406,11729 +copy_all_regs 219,6194 +copy_to_mode_reg 416,11905 +copy_to_reg 386,11310 +copy_to_suggested_reg 479,13509 +eliminate_constant_term 119,3377 +expr_size 156,4235 +force_not_mem 464,13203 +force_reg 443,12671 +hard_function_value 560,15543 +hard_libcall_value 571,15803 +lookup_static_chain 165,4402 +memory_address 245,6920 +memory_address_noforce 341,10196 +plus_constant 30,961 +round_push 527,14689 +stabilize 360,10707 + +expmed.c,410 +expand_bit_and 1507,49728 +expand_dec 1331,44164 +expand_divmod 1611,53005 +expand_inc 1318,43900 +expand_mult 1529,50406 +expand_mult_add 1878,60478 +expand_shift 1354,44921 +extract_bit_field 653,21607 +extract_fixed_bit_field 1117,36571 +extract_split_bit_field 1265,42008 +make_tree 1849,59846 +negate_rtx 42,1346 +store_bit_field 71,2256 +store_fixed_bit_field 384,12574 +store_split_bit_field 559,18219 + +expr.c,1384 +#define DEFTREECODE(120,3972 +clear_pending_stack_adjust 3828,118811 +clear_storage 1028,27980 +compare 5362,167602 +compare1 5416,169287 +compare_constants 5293,166109 +convert_move 288,8704 +convert_to_mode 632,17485 +do_jump 5106,160969 +do_pending_stack_adjust 3841,119121 +do_store_flag 5459,170432 +do_tablejump 5593,174399 +emit_block_move 884,24466 +emit_call_1 3767,117111 +emit_library_call 1533,42930 +emit_move_insn 1058,28763 +emit_push_insn 1207,33207 +emit_queue 265,8214 +enqueue_insn 163,5013 +expand_assignment 1722,48236 +expand_builtin 3325,102048 +expand_call 3889,120716 +expand_expr 2216,63961 +expand_increment 3514,108467 +force_operand 2099,60111 +gen_push_operand 1170,31984 +init_comparisons 130,4145 +init_expr 143,4461 +init_pending_stack_adjust 3819,118627 +init_queue 276,8395 +integer_mode_p 651,17976 +jumpif 5090,160549 +jumpifnot 5080,160377 +move_block_from_reg 992,27159 +move_block_to_reg 963,26366 +move_by_pieces 682,18659 +move_by_pieces_1 826,22757 +move_by_pieces_ninsns 787,21642 +preexpand_calls 3631,112708 +prepare_call_address 3696,114577 +protect_from_queue 187,5940 +push_block 1129,30984 +queued_subexp_p 243,7822 +save_noncopied_parts 2176,62895 +store_constructor 1927,54611 +store_expr 1839,51699 +store_field 2043,58390 +store_one_arg 4879,153836 +target_for_arg 4844,152623 +use_regs 1015,27693 +validate_subtarget 2203,63707 + +final.c,589 +alter_cond 1243,34917 +alter_subreg 1178,33306 +app_disable 326,10250 +app_enable 313,10033 +dbr_sequence_length 340,10474 +end_final 230,7223 +final 548,16222 +final_end_function 501,14864 +final_scan_insn 578,16915 +final_start_function 367,11384 +init_final 213,6851 +#define min(77,2678 +output_addr_const 1578,42458 +output_address 1566,42189 +output_asm_insn 1413,38101 +output_asm_label 1526,41027 +output_operand 1552,41852 +output_operand_lossage 1385,37141 +output_source_line 1102,31238 +profile_function 433,13249 +set_current_gdbfile 1077,30667 +walk_alter_subreg 1211,34151 + +flow.c,577 +#define BLOCK_NUM(108,3935 +#define INSN_VOLATILE(118,4260 +allocate_for_life_analysis 874,28752 +dump_flow_info 2020,63653 +find_basic_blocks 336,11085 +find_use_as_address 1958,62222 +flow_analysis 278,9354 +init_regset_vector 919,30428 +insn_dead_p 1230,40383 +libcall_dead_p 1298,42611 +life_analysis 568,17911 +mark_label_ref 513,16293 +mark_set_1 1382,44686 +mark_set_regs 1356,44092 +mark_used_regs 1542,49929 +propagate_block 955,31574 +regno_clobbered_at_setjmp 1336,43477 +regno_uninitialized 1322,43130 +try_pre_increment 1873,59800 +try_pre_increment_1 1834,58479 + +fold-const.c,383 +add_double 149,4510 +combine 775,19733 +decode 79,2662 +div_and_round_double 429,10070 +encode 60,2170 +fold 1225,30815 +fold_convert 1100,26928 +force_fit_type 92,3044 +lrotate_double 353,8530 +lshift_double 277,7046 +mul_double 200,5567 +neg_double 177,5105 +operand_equal_p 1178,29166 +real_zerop 1204,30058 +rrotate_double 392,9246 +rshift_double 318,7860 +split_tree 695,17265 + +gcc.c,839 +#define SWITCH_TAKES_ARG(223,8637 +#define WORD_SWITCH_TAKES_ARG(233,8998 +choose_temp_base 543,18411 +clear_args 371,14053 +clear_failure_queue 534,18248 +concat 1878,49343 +delete_failure_queue 510,17789 +delete_temp_files 476,17100 +do_spec 1068,31124 +do_spec_1 1108,32159 +error 1976,51113 +error 2001,51496 +execute 775,23633 +fancy_abort 1951,50766 +fatal 1961,50886 +fatal 1993,51373 +fatal_error 1692,44633 +find_exec_file 579,19237 +find_file 1518,40963 +give_switch 1499,40468 +handle_braces 1385,37915 +main 1704,44880 +perror_exec 1932,50330 +perror_with_name 1918,50087 +pexecute 698,21849 +pfatal_with_name 1904,49844 +process_command 936,27544 +record_temp_file 437,16042 +save_string 1893,49673 +store_arg 384,14430 +validate_all_switches 2013,51697 +validate_switches 2097,53454 +xmalloc 1857,48937 +xrealloc 1866,49084 + +gencodes.c,103 +fancy_abort 88,2087 +fatal 75,1793 +gen_insn 43,1206 +main 94,2145 +xmalloc 54,1492 +xrealloc 64,1623 + +genconfig.c,177 +fancy_abort 205,4810 +fatal 192,4515 +gen_expand 133,3331 +gen_insn 112,2758 +gen_peephole 158,3977 +main 211,4868 +walk_insn_part 49,1369 +xmalloc 170,4213 +xrealloc 181,4345 + +genemit.c,238 +fancy_abort 403,9989 +fatal 390,9696 +gen_exp 115,2558 +gen_expand 260,5661 +gen_insn 210,4305 +main 409,10047 +#define max(42,1178 +max_operand_1 45,1226 +max_operand_vec 81,1959 +print_code 98,2223 +xmalloc 368,9394 +xrealloc 379,9526 + +genextract.c,170 +fancy_abort 251,5761 +fatal 238,5465 +gen_insn 62,1731 +gen_peephole 96,2555 +main 257,5819 +print_path 197,4810 +walk_rtx 112,3059 +xmalloc 217,5164 +xrealloc 227,5295 + +genflags.c,103 +fancy_abort 90,2150 +fatal 77,1856 +gen_insn 41,1173 +main 96,2208 +xmalloc 55,1554 +xrealloc 66,1686 + +genoutput.c,318 +error 717,20357 +fancy_abort 711,20299 +fatal 698,20004 +gen_expand 609,18206 +gen_insn 463,13905 +gen_peephole 542,16269 +main 726,20491 +mybcopy 688,19853 +mybzero 679,19737 +n_occurrences 778,21406 +output_epilogue 192,6904 +output_prologue 163,6053 +scan_operands 371,11682 +xmalloc 658,19436 +xrealloc 668,19567 + +genpeep.c,174 +fancy_abort 356,8467 +fatal 343,8174 +gen_peephole 67,1820 +main 362,8525 +match_rtx 148,4070 +print_code 308,7657 +print_path 288,7303 +xmalloc 322,7873 +xrealloc 332,8004 + +genrecog.c,518 +add_to_sequence 170,3811 +break_out_subroutines 523,12666 +change_state 899,21717 +clear_codes 871,21310 +clear_modes 891,21611 +concat 954,22723 +copystr 930,22435 +fancy_abort 1009,23659 +fatal 994,23287 +main 1015,23717 +make_insn_sequence 142,3340 +merge_trees 382,8728 +mybzero 945,22605 +no_same_mode 505,12235 +print_code 845,20922 +same_codes 859,21137 +same_modes 879,21417 +try_merge_1 402,9188 +try_merge_2 446,10671 +write_subroutine 540,13035 +write_tree 554,13457 +xmalloc 984,23155 +xrealloc 973,22986 + +global-alloc.c,636 +#define ALLOCNO_LIVE_P(156,5319 +#define CLEAR_ALLOCNO_LIVE(162,5500 +#define CONFLICTP(108,3889 +#define REGBITP(141,4891 +#define SET_ALLOCNO_LIVE(159,5408 +#define SET_CONFLICT(112,4001 +#define SET_REGBIT(145,5031 +allocno_compare 316,10354 +check_frame_pointer_required 660,21045 +dump_conflicts 1045,32518 +dump_global_regs 1074,33316 +find_reg 484,15508 +global_alloc 187,6256 +global_conflicts 344,11268 +mark_reg_clobber 856,27159 +mark_reg_death 913,28575 +mark_reg_live_nc 949,29704 +mark_reg_store 793,25606 +record_conflicts 758,24418 +record_one_conflict 726,23402 +retry_global_alloc 628,20047 +set_preference 971,30428 + +gnulib.c,842 +#define FLOATIFY(27,652 +#define FLOATIFY(31,716 +#define INTIFY(22,527 +__adddf3 176,2365 +__addsf3 242,3287 +__ashlsi3 140,2031 +__ashrsi3 131,1943 +__bb_init_func 337,4662 +__builtin_delete 436,6230 +__builtin_new 359,4970 +__builtin_vec_delete 444,6306 +__builtin_vec_new 380,5236 +__cmpdf2 194,2535 +__cmpsf2 272,3722 +__divdf3 149,2119 +__divsf3 295,4068 +__divsi3 86,1482 +__eprintf 45,958 +__extendsfdf2 316,4347 +__fixdfsi 224,3110 +__fixunsdfsi 210,2803 +__floatsidf 233,3198 +__lshlsi3 122,1846 +__lshrsi3 113,1749 +__modsi3 104,1663 +__muldf3 158,2204 +__mulsf3 285,3916 +__mulsi3 68,1301 +__negdf2 167,2289 +__negsf2 252,3439 +__set_new_handler 403,5563 +__subdf3 185,2450 +__subsf3 262,3571 +__truncdfsf2 306,4227 +__udivsi3 77,1387 +__umodsi3 95,1568 +__umulsi3 59,1206 +default_new_handler 422,5871 +set_new_handler 415,5772 + +gnulib2.c,870 +__adddi3 79,1730 +__anddi3 125,2454 +__ashldi3 264,4405 +__ashrdi3 298,4949 +__bdiv 576,9757 +__builtin_saveregs 916,17439 +__cmpdi2 747,13616 +__divdi3 431,7166 +__fixdfdi 821,15167 +__fixunsdfdi 791,14434 +__floatdidf 837,15473 +__iordi3 143,2678 +__lshldi3 196,3315 +__lshrdi3 230,3859 +__moddi3 449,7569 +__muldi3 378,6238 +__negdi2 521,8823 +__one_cmpldi2 179,3130 +__subdi3 332,5520 +__ucmpdi2 768,13969 +__udivdi3 467,7974 +__umoddi3 494,8399 +__xordi3 161,2902 +badd 102,2047 +#define big_end(48,1107 +#define big_end(60,1330 +bmul 401,6579 +bneg 541,9072 +bshift 721,13191 +bsub 355,5837 +#define is_not_lsd(53,1256 +#define is_not_lsd(65,1480 +#define is_not_msd(52,1221 +#define is_not_msd(64,1444 +#define little_end(49,1129 +#define little_end(61,1359 +#define next_lsd(51,1191 +#define next_lsd(63,1414 +#define next_msd(50,1161 +#define next_msd(62,1384 + +hard-params.c,938 +Number Diff(1121,30154 +Number Div(1123,30299 +Procedure EPROP(1635,46389 +Procedure EPROP(1709,48412 +int FPROP(1235,33784 +int FPROP(1703,48318 +Procedure F_check(1126,30437 +Procedure IPROP(1023,27573 +Number Mul(1122,30227 +#define Order(597,18214 +Number Self(1124,30371 +Procedure Store(1119,30036 +Number Sum(1120,30082 +Procedure UPROP 1094,29430 +#define Unexpected(236,9540 +Procedure Validate(1201,32819 +int basic(737,21437 +Procedure bitpattern(584,17989 +int ceil_log(531,16884 +int cprop(641,19232 +croak(332,12253 +Procedure eek_a_bug(463,15169 +Procedure endian(602,18438 +int exponent(537,16990 +Procedure f_define(510,16250 +char *f_rep(569,17598 +#define fabs(567,17560 +int floor_log(525,16743 +Procedure i_define(468,15280 +main(350,12666 + overflow(229,9408 +printmode(277,10725 + int setjmp(220,9272 +int setmode(310,11854 +int setmode(326,12143 + signal(221,9313 +Procedure u_define(490,15730 +xmalloc(340,12485 + +integrate.c,447 +#define INTEGRATE_THRESHOLD(50,1493 +#define MIN(42,1262 +access_parm_map 1603,51657 +copy_address 1695,54390 +copy_decl_tree 1168,38296 +copy_for_inline 436,14741 +copy_parm_decls 1143,37604 +copy_rtx_and_substitute 1236,40232 +expand_inline_function 599,19306 +fold_out_const_cc0 1875,58915 +frame_pointer_sum_p 1218,39831 +function_cannot_inline_p 128,4605 +output_inline_function 2015,62832 +save_for_inline 240,8817 +try_fold_cc0 1798,56683 + +jump.c,691 +condjump_p 910,27287 +delete_for_peephole 1321,37954 +delete_insn 1205,34759 +delete_jump 1172,33810 +do_cross_jump 732,22800 +find_cross_jump 650,20681 +follow_jumps 1036,30078 +invert_exp 1378,39252 +invert_jump 1360,38817 +jump_back_p 802,24785 +jump_optimize 115,4405 +mark_jump_label 1115,32330 +next_label 1022,29693 +next_nondeleted_insn 1307,37603 +next_real_insn 1000,29288 +no_labels_between_p 963,28591 +prev_real_insn 977,28872 +redirect_exp 1446,40713 +redirect_jump 1425,40290 +reverse_condition 849,26437 +rtx_renumbered_equal_p 1479,41399 +sets_cc0_p 937,28002 +simplejump_p 893,26962 +squeeze_block_notes 773,24031 +tension_vector_labels 1079,31266 +true_regnum 1602,43988 + +local-alloc.c,433 +alloc_qty 201,7314 +block_alloc 318,10714 +combine_regs 680,23188 +dump_local_alloc 1220,39281 +find_free_reg 1076,35538 +local_alloc 221,7858 +mark_life 1169,38200 +post_mark_life 1184,38524 +qty_compare 641,21801 +qty_compare_1 651,22104 +reg_class_subset_p 888,29956 +reg_classes_overlap_p 907,30376 +reg_is_born 1016,33720 +reg_is_set 945,31377 +reg_meets_class_p 875,29579 +update_qty_class 929,30883 +wipe_dead_reg 1031,34110 + +loop.c,1323 +#define INSN_LUID(58,2095 +addr_overlap_p 2024,61092 +all_sets_invariant_p 2121,63451 +basic_induction_var 3658,111742 +can_eliminate_biv_p 4974,149220 +can_jump_into_range_p 1792,55188 +check_dbra_loop 4571,136031 +check_eliminate_biv 4892,146936 +combine_movables 867,28977 +consec_sets_giv 4364,130312 +consec_sets_invariant_p 2055,61886 +constant_high_bytes 1644,51102 +count_loop_regs_set 2158,64500 +count_nonfixed_reads 1592,50025 +delete_insn_forces 3601,110273 +eliminate_biv 5133,153671 +emit_iv_inc 4496,133848 +emit_iv_init_code 4467,133057 +final_biv_value 5411,161771 +find_mem_givs 3316,102291 +force_movables 830,27861 +gen_iv_mult 4435,132220 +general_induction_var 3750,114361 +ignore_some_movables 801,26969 +invariant_p 1907,57988 +labels_in_range_p 1830,55972 +last_use_this_basic_block 5423,162022 +loop_find_reg_equal 787,26598 +loop_optimize 245,8498 +loop_reg_used_before_p 2280,68831 +loop_skip_over 1410,45302 +move_movables 1096,35425 +note_addr_stored 1847,56253 +other_reg_use_p 3261,101117 +product_cheap_p 4509,134347 +record_giv 3399,104522 +reg_in_basic_block_p 709,24805 +regs_match_p 973,32390 +replace_call_address 1533,48807 +replace_regs 1483,47730 +rtx_equal_for_loop_p 999,32949 +scan_loop 337,11206 +skip_consec_insns 754,25775 +strength_reduce 2461,76757 +verify_loop 1685,52226 + +masm386.c,195 +add_to_implicit_list 28,935 +asm_library_declare 208,5196 +asm_output_labelref 176,4643 +asm_write_decls 69,1912 +mark_name_used 164,4348 +node_compare 149,3967 +write_implicit_declares 50,1461 + +obstack.c,380 +POINTER 227,7107 +POINTER 233,7208 +POINTER 295,8399 +POINTER 301,8504 +POINTER 308,8640 +POINTER 316,8814 +_obstack_allocated_p 151,5095 +_obstack_begin 60,2178 +_obstack_free 175,5727 +_obstack_free 205,6437 +_obstack_newchunk 101,3425 +int 239,7319 +int 245,7430 +obstack_free 173,5675 +void 251,7527 +void 259,7691 +void 267,7857 +void 274,7992 +void 281,8118 +void 288,8263 + +optabs.c,666 +#define INC_MODE(33,1095 +can_fix_p 1007,28930 +can_float_p 1025,29485 +emit_0_to_1_insn 708,20248 +emit_clr_insn 698,20095 +emit_cmp_insn 724,20644 +emit_unop_insn 652,18843 +expand_binop 104,2935 +expand_fix 1291,36580 +expand_float 1159,32744 +expand_twoval_binop 429,12680 +expand_twoval_binop_convert 488,14093 +expand_unop 522,15140 +ftruncify 1283,36440 +gen_add2_insn 917,26326 +gen_extend_insn 969,27545 +gen_move_insn 951,26975 +gen_sub2_insn 934,26651 +have_add2_insn 925,26456 +have_sub2_insn 942,26781 +init_extends 980,27790 +init_fixtab 1032,29624 +init_floattab 1126,31950 +init_optab 1405,39690 +init_optabs 1423,40092 +sign_expand_binop 367,10496 + +print-self.c,10 +main(1,0 + +print-self1.c,0 + +print-tree.c,148 +#define DEFTREECODE(28,939 +#define TREE_CODE_CLASS(42,1437 +debug_tree 66,1931 +indent_to 153,4184 +print_node 170,4527 +print_node_brief 81,2317 + +recog.c,749 +address_operand 253,6388 +adj_offsettable_operand 829,22233 +asm_noperands 441,11199 +constrain_operands 886,23644 +decode_asm_operands 519,13786 +find_constant_term_loc 665,18141 +general_operand 195,4938 +immediate_operand 299,7673 +indirect_operand 428,10853 +inequality_comparisons_p 128,3450 +init_recog 60,1789 +memory_address_p 384,9753 +memory_operand 402,10131 +mode_dependent_address_p 790,21453 +mode_independent_operand 803,21685 +next_insn_tests_no_inequality 90,2590 +next_insns_test_no_inequality 104,2913 +nonimmediate_operand 312,7997 +nonmemory_operand 323,8265 +offsettable_address_p 737,19914 +offsettable_memref_p 719,19407 +push_operand 359,9326 +recog_memoized 76,2269 +reg_fits_class_p 1083,28277 +register_operand 268,6811 + +regclass.c,332 +fix_register 263,7623 +init_reg_sets 123,3934 +init_reg_sets_1 210,6250 +#define max(34,1182 +#define min(35,1223 +record_address_regs 652,17696 +reg_class_record 519,15043 +reg_preferred_class 323,9113 +reg_preferred_or_nothing 332,9257 +reg_scan 829,22281 +reg_scan_mark_refs 859,23031 +regclass 354,9769 +regclass_init 343,9459 + +reload.c,653 +alternative_allows_memconst 2196,71369 +combine_reloads 540,19742 +decompose 911,30503 +find_dummy_reload 613,22066 +find_equiv_reg 2939,92989 +find_inc_amount 3251,102452 +find_reloads 1089,35175 +find_reloads_address 2339,75674 +find_reloads_address_1 2631,83800 +find_reloads_toplev 2223,72225 +forget_volatility 2869,91170 +hard_reg_set_here_p 711,25353 +immune_p 1031,33358 +make_memloc 2313,74855 +#define min(94,3758 +n_occurrences 883,29872 +operands_match_p 772,27000 +push_reload 253,10099 +push_replacement 517,19107 +strict_memory_address_p 744,26144 +subst_indexed_address 2555,81364 +subst_reg_equivs 2502,80186 +subst_reloads 2831,90030 + +reload1.c,866 +alter_frame_pointer_addresses 1305,44664 +alter_reg 1390,46732 +choose_reload_regs 2165,70997 +constraint_accepts_reg_p 3438,114827 +count_occurrences 3475,115679 +delete_output_reload 3239,108287 +eliminate_frame_pointer 1200,41311 +emit_reload_insns 2743,90853 +forget_old_reloads_1 1935,63562 +gen_input_reload 3210,107417 +hard_reg_use_compare 1642,54336 +inc_for_reload 3339,111555 +mark_home_live 1514,51058 +mark_reload_reg_in_use 2027,66783 +#define max(33,1067 +#define min(32,1026 +modes_equiv_for_class_p 1116,38767 +new_spill_reg 1145,39872 +order_regs_for_reload 1657,54829 +possible_group_p 1066,37309 +reload 243,9681 +reload_as_needed 1760,57952 +reload_reg_class_lower 1981,64905 +reload_reg_free_before_p 2084,68407 +reload_reg_free_p 2056,67456 +reload_reg_reaches_end_p 2113,69290 +scan_paradoxical_subregs 1596,53373 +spill_hard_reg 1534,51598 + +rtl.c,440 +#define DEF_MACHMODE(63,1952 +#define DEF_MACHMODE(74,2191 +#define DEF_MACHMODE(85,2441 +#define DEF_MACHMODE(97,2707 +#define DEF_MACHMODE(110,3053 +#define DEF_RTL_EXPR(52,1673 +#define MIN(40,1322 +copy_rtx 205,5658 +debug_rtx 413,10078 +dump_and_abort 463,10998 +init_rtl 783,18380 +print_rtl 428,10388 +print_rtx 276,7222 +read_name 527,12390 +read_rtx 565,13190 +read_skip_spaces 491,11717 +rtvec_alloc 162,4778 +rtx_alloc 184,5226 + +rtlanal.c,461 +dead_or_set_p 472,11729 +find_reg_note 506,12707 +find_regno_note 524,13147 +may_trap_p 621,14848 +no_labels_between 541,13501 +note_stores 426,10258 +refers_to_regno_p 246,5897 +reg_mentioned_p 128,3229 +reg_overlap_mentioned_p 314,7371 +reg_set_between_p 202,4900 +reg_set_p 229,5477 +reg_set_p_1 221,5363 +reg_used_between_p 184,4353 +rtx_addr_varies_p 101,2622 +rtx_equal_p 329,7769 +rtx_unstable_p 33,1102 +rtx_varies_p 68,1929 +volatile_refs_p 562,13853 + +sdbout.c,1318 +#define KNOWN_TYPE_TAG(229,5804 +#define MAKE_LINE_SAFE(245,6393 +#define PUSH_DERIVED_LEVEL(340,8841 +#define PUT_SDB_BLOCK_END(194,4871 +#define PUT_SDB_BLOCK_START(187,4693 +#define PUT_SDB_DEF(145,3645 +#define PUT_SDB_EPILOGUE_END(215,5417 +#define PUT_SDB_FUNCTION_END(208,5235 +#define PUT_SDB_FUNCTION_START(201,5051 +#define PUT_SDB_INT_VAL(134,3380 +#define PUT_SDB_LAST_DIM(176,4406 +#define PUT_SDB_NEXT_DIM(172,4313 +#define PUT_SDB_PLAIN_DEF(152,3843 +#define PUT_SDB_SCL(130,3283 +#define PUT_SDB_SIZE(164,4121 +#define PUT_SDB_TAG(180,4494 +#define PUT_SDB_TYPE(160,4026 +#define PUT_SDB_VAL(138,3478 +#define SDB_GENERATE_FAKE(222,5582 +#define SET_KNOWN_TYPE_TAG(233,5931 +#define TAG_NAME(239,6160 +gen_fake_label 312,7866 +plain_type 353,9214 +plain_type_1 417,10585 +sdbout_begin_block 1022,26699 +sdbout_begin_function 1069,27825 +sdbout_block 521,13001 +sdbout_end_block 1045,27249 +sdbout_end_epilogue 1096,28492 +sdbout_end_function 1082,28157 +sdbout_field_types 774,19432 +sdbout_filename 256,6751 +sdbout_init 281,7241 +sdbout_mark_begin_function 1057,27489 +sdbout_one_type 797,20130 +sdbout_parms 913,23004 +sdbout_record_type_name 384,9960 +sdbout_reg_parms 972,24878 +sdbout_symbol 579,14202 +sdbout_syms 565,13951 +sdbout_tags 730,18444 +sdbout_type 759,18997 +sdbout_types 749,18829 + +stmt.c,2641 +#define MAX(64,2515 +#define MIN(65,2558 +#define POPSTACK(340,11771 +aggregate_value_p 4018,125212 +assign_parms 4053,126128 +assign_stack_local 3291,103207 +balance_case_nodes 2901,91060 +check_for_full_enumeration_handling 2509,78692 +clear_last_expr 1091,35449 +do_jump_if_equal 2835,89194 +drop_through_at_end_p 1642,51705 +emit_case_nodes 3084,96305 +emit_jump 399,13278 +emit_jump_if_reachable 3056,95224 +emit_nop 371,12714 +expand_anon_union_decl 2155,68127 +expand_asm 762,25802 +expand_asm_operands 786,26654 +expand_cleanups 2198,69255 +expand_continue_loop 1363,43527 +expand_decl 1919,60684 +expand_decl_init 2125,67207 +expand_end_bindings 1808,56955 +expand_end_case 2564,80570 +expand_end_case_dummy 2329,73132 +expand_end_cond 1191,38178 +expand_end_else 1220,38885 +expand_end_loop 1294,41048 +expand_end_stmt_expr 1128,36574 +expand_exit_loop 1376,43847 +expand_exit_loop_if_false 1390,44199 +expand_exit_something 1418,44926 +expand_expr_stmt 1011,33222 +expand_fixup 566,18699 +expand_function_end 4931,155054 +expand_function_start 4803,150713 +expand_goto 490,16359 +expand_goto_internal 502,16694 +expand_label 468,15802 +expand_loop_continue_here 1283,40771 +expand_null_return 1436,45295 +expand_null_return_1 1458,45925 +expand_return 1496,46874 +expand_start_bindings 1724,54116 +expand_start_case 2269,71311 +expand_start_case_dummy 2306,72513 +expand_start_cond 1166,37455 +expand_start_else 1206,38462 +expand_start_loop 1242,39516 +expand_start_loop_continue_elsewhere 1270,40413 +expand_start_stmt_expr 1101,35673 +fixup_cleanups 2218,69836 +fixup_gotos 664,22199 +fixup_memory_subreg 3700,115809 +fixup_stack_1 3794,118504 +fixup_stack_slots 3770,117706 +fixup_var_refs 3370,105404 +fixup_var_refs_1 3449,107674 +fixup_var_refs_insns 3412,106573 +get_first_nonparm_insn 3994,124597 +get_frame_size 3278,102945 +get_structure_value_addr 4572,143821 +group_case_nodes 2858,89716 +init_function_start 4681,147070 +inside_loop 1403,44437 +label_rtx 384,13000 +max_parm_reg_num 3986,124470 +move_cleanups_up 2239,70445 +node_has_high_bound 3015,94116 +node_has_low_bound 2980,92996 +node_is_bounded 3045,94971 +optimize_bit_field 3847,119946 +parm_stack_loc 4006,124942 +pop_structure_value 4612,144818 +push_structure_value 4601,144603 +pushcase 2347,73703 +pushcase_range 2427,76189 +put_var_into_stack 3336,104429 +setjmp_protect 4661,146461 +tail_recursion_args 1657,52179 +this_contour_has_cleanups_p 2251,70696 +uninitialized_vars_warning 4627,145205 +use_variable 1762,55413 +use_variable_after 1782,56023 +validize_mem 4036,125639 +walk_fixup_memory_subreg 3731,116827 +warn_if_unused_value 1035,33984 + +stor-layout.c,515 +#define CEIL(29,987 +#define GET_MODE_ALIGNMENT(45,1355 +#define MAX(27,905 +#define MIN(28,946 +agg_mode 181,4654 +build_int 222,5507 +chain_type 73,2220 +convert_units 295,7478 +fixup_unsigned_type 1073,32067 +genop 256,6284 +get_pending_sizes 138,3599 +get_permanent_types 108,2978 +get_temporary_types 120,3211 +layout_decl 343,9382 +layout_record 459,13351 +layout_type 763,23324 +layout_union 667,20230 +make_signed_type 1010,30487 +make_unsigned_type 1051,31572 +round_size 206,5194 +variable_size 149,3832 + +stupid.c,176 +#define INSN_SUID(59,2408 +#define MARK_LIVE_AFTER(104,3665 +stupid_find_reg 336,10565 +stupid_life_analysis 120,4312 +stupid_mark_refs 412,12697 +stupid_reg_compare 303,9471 + +symout.c,678 +#define TYPE_OUTPUT_ADDRESS(50,1540 +filter_undefined_types 518,12890 +subrange_p 539,13374 +symout_array_domain 586,14919 +symout_block 899,24107 +symout_block_symbols 702,18200 +symout_block_tags 865,23091 +symout_enum_value_names 682,17545 +symout_enum_values 644,16380 +symout_finish 1176,31912 +symout_function 967,26149 +symout_function_end 1003,26939 +symout_init 119,3370 +symout_range_bounds 599,15194 +symout_record_field_names 669,17230 +symout_record_fields 618,15711 +symout_source_file 1107,29925 +symout_sources 1141,30923 +symout_strings 171,4823 +symout_strings_print 184,5082 +symout_strings_skip 214,5590 +symout_top_blocks 1018,27444 +symout_types 248,6495 + +toplev.c,868 +#define TIMEVAR(413,10823 +announce_function 499,12553 +botch 769,19055 +compile_file 865,20924 +count_error 429,11171 +error 561,14112 +error_for_asm 623,15605 +error_with_decl 596,14879 +error_with_file_and_line 573,14403 +exact_log2 803,19669 +fancy_abort 760,18890 +fatal 464,11701 +fatal_insn_not_found 477,11944 +fatal_io_error 456,11580 +float_signal 845,20570 +floor_log2 817,19959 +gettime 377,10139 +main 1738,45693 +pfatal_with_name 447,11461 +pipe_closed 856,20723 +print_target_switch_defaults 2059,53011 +print_time 417,10935 +really_sorry 742,18470 +report_error_function 515,12934 +rest_of_compilation 1372,35852 +rest_of_decl_compilation 1307,33880 +set_float_handler 834,20358 +set_target_switch 2040,52568 +sorry 723,18050 +warning 683,17067 +warning_with_decl 696,17394 +warning_with_file_and_line 657,16566 +xmalloc 777,19152 +xrealloc 789,19382 + +tree.c,2237 +#define DEFTREECODE(117,3874 +#define DEFTREECODE(128,4148 +#define TYPE_HASH(1541,39770 +allocation_temporary_p 210,6499 +array_type_nelts 1006,26436 +build 1198,31456 +build_array_type 1841,48099 +build_asm_stmt 1391,35622 +build_case 1404,35875 +build_complex 753,20676 +build_compound 1431,36413 +build_decl 1283,33321 +build_exit 1378,35381 +build_expr_stmt 1348,34788 +build_function_type 1882,49193 +build_goto 1321,34301 +build_if 1362,35035 +build_index_type 1815,47219 +build_int_2 630,17441 +build_let 1450,36905 +build_loop 1418,36172 +build_method_type 1950,51014 +build_nt 1244,32523 +build_offset_type 1987,52017 +build_op_identifier 1267,32902 +build_pointer_type 1775,46022 +build_real 643,17715 +build_real_from_int_cst 709,19602 +build_reference_type 1912,49967 +build_return 1334,34545 +build_string 737,20240 +build_tree_list 850,22774 +build_type_variant 1480,37884 +chainon 831,22413 +clear_momentary 305,8915 +copy_list 528,14901 +copy_node 465,13315 +end_temporary_allocation 188,5925 +get_identifier 555,15441 +get_narrower 2122,56829 +get_unwidened 2033,53677 +init_tree 150,4669 +int_fits_type_p 2214,59639 +int_size_in_bytes 987,25959 +integer_all_onesp 788,21376 +integer_onep 776,21118 +integer_zerop 765,20903 +list_length 814,22082 +lvalue_or_else 1094,28562 +lvalue_p 1055,27784 +make_node 357,10325 +nreverse 948,25022 +oballoc 246,7488 +obfree 257,7746 +perm_tree_cons 877,23364 +permalloc 267,7912 +permanent_allocation 220,6756 +pop_momentary 316,9219 +preserve_data 235,7225 +push_momentary 289,8431 +real_value_from_int_cst 667,18300 +resume_momentary 342,9956 +resume_temporary_allocation 199,6203 +save_expr 1110,29040 +saveable_tree_cons 915,24281 +savealloc 277,8102 +set_identifier_size 619,17187 +simple_cst_equal 1701,44080 +size_in_bytes 968,25525 +stabilize_reference 1134,29808 +start_identifier_warnings 610,16997 +staticp 1021,26897 +suspend_momentary 329,9599 +temp_tree_cons 896,23818 +temporary_allocation 175,5540 +tree_cons 864,23078 +tree_int_cst_equal 1668,43349 +tree_int_cst_lt 1687,43831 +tree_last 934,24745 +type_hash_add 1589,41258 +type_hash_canon 1617,42195 +type_hash_list 1548,39982 +type_hash_lookup 1562,40328 +type_list_equal 1648,42896 +type_precision 2201,59310 + +varasm.c,1067 +#define MIN(40,1339 +assemble_asm 281,7952 +assemble_external 579,16300 +assemble_function 293,8189 +assemble_integer_zero 352,9756 +assemble_name 600,16945 +assemble_static_space 614,17225 +assemble_string 360,9912 +assemble_variable 421,11642 +clear_const_double_mem 785,22367 +compare_constant 945,26553 +compare_constant_1 962,27148 +compare_constant_rtx 1425,39850 +const_hash 878,24595 +const_hash_rtx 1402,39343 +data_section 102,2772 +decode_addr_const 810,22874 +decode_reg_name 151,3848 +decode_rtx_const 1326,37654 +force_const_double_mem 758,21463 +force_const_mem 1474,41069 +get_or_assign_label 1184,33561 +immed_double_const 657,18700 +immed_real_const 746,21100 +immed_real_const_1 693,19617 +in_text_section 124,3169 +init_const_rtx_hash_table 1306,37216 +make_decl_rtl 181,4479 +make_function_rtl 134,3402 +output_addressed_constants 1623,45096 +output_constant 1691,47084 +output_constant_def 1267,36103 +output_constructor 1860,50836 +record_constant 1075,30188 +record_constant_1 1093,30717 +record_constant_rtx 1451,40468 +text_section 90,2568 + +version.c,0 diff --git a/gcc-1.40/alloca.c b/gcc-1.40/alloca.c new file mode 100644 index 0000000..cfe98f9 --- /dev/null +++ b/gcc-1.40/alloca.c @@ -0,0 +1,191 @@ +/* + alloca -- (mostly) portable public-domain implementation -- D A Gwyn + + last edit: 86/05/30 rms + include config.h, since on VMS it renames some symbols. + Use xmalloc instead of malloc. + + This implementation of the PWB library alloca() function, + which is used to allocate space off the run-time stack so + that it is automatically reclaimed upon procedure exit, + was inspired by discussions with J. Q. Johnson of Cornell. + + It should work under any C implementation that uses an + actual procedure stack (as opposed to a linked list of + frames). There are some preprocessor constants that can + be defined when compiling for your specific system, for + improved efficiency; however, the defaults should be okay. + + The general concept of this implementation is to keep + track of all alloca()-allocated blocks, and reclaim any + that are found to be deeper in the stack than the current + invocation. This heuristic does not reclaim storage as + soon as it becomes invalid, but it will do so eventually. + + As a special case, alloca(0) reclaims storage without + allocating any. It is a good idea to use alloca(0) in + your main control loop, etc. to force garbage collection. +*/ +#ifndef lint +static char SCCSid[] = "@(#)alloca.c 1.1"; /* for the "what" utility */ +#endif + +#ifdef emacs +#include "config.h" +#ifdef static +/* actually, only want this if static is defined as "" + -- this is for usg, in which emacs must undefine static + in order to make unexec workable + */ +#ifndef STACK_DIRECTION +you +lose +-- must know STACK_DIRECTION at compile-time +#endif /* STACK_DIRECTION undefined */ +#endif static +#endif emacs + +#ifdef X3J11 +typedef void *pointer; /* generic pointer type */ +#else +typedef char *pointer; /* generic pointer type */ +#endif + +#define NULL 0 /* null pointer constant */ + +extern void free(); +extern pointer xmalloc(); + +/* + Define STACK_DIRECTION if you know the direction of stack + growth for your system; otherwise it will be automatically + deduced at run-time. + + STACK_DIRECTION > 0 => grows toward higher addresses + STACK_DIRECTION < 0 => grows toward lower addresses + STACK_DIRECTION = 0 => direction of growth unknown +*/ + +#ifndef STACK_DIRECTION +#define STACK_DIRECTION 0 /* direction unknown */ +#endif + +#if STACK_DIRECTION != 0 + +#define STACK_DIR STACK_DIRECTION /* known at compile-time */ + +#else /* STACK_DIRECTION == 0; need run-time code */ + +static int stack_dir; /* 1 or -1 once known */ +#define STACK_DIR stack_dir + +static void +find_stack_direction (/* void */) +{ + static char *addr = NULL; /* address of first + `dummy', once known */ + auto char dummy; /* to get stack address */ + + if (addr == NULL) + { /* initial entry */ + addr = &dummy; + + find_stack_direction (); /* recurse once */ + } + else /* second entry */ + if (&dummy > addr) + stack_dir = 1; /* stack grew upward */ + else + stack_dir = -1; /* stack grew downward */ +} + +#endif /* STACK_DIRECTION == 0 */ + +/* + An "alloca header" is used to: + (a) chain together all alloca()ed blocks; + (b) keep track of stack depth. + + It is very important that sizeof(header) agree with malloc() + alignment chunk size. The following default should work okay. +*/ + +#ifndef ALIGN_SIZE +#define ALIGN_SIZE sizeof(double) +#endif + +typedef union hdr +{ + char align[ALIGN_SIZE]; /* to force sizeof(header) */ + struct + { + union hdr *next; /* for chaining headers */ + char *deep; /* for stack depth measure */ + } h; +} header; + +/* + alloca( size ) returns a pointer to at least `size' bytes of + storage which will be automatically reclaimed upon exit from + the procedure that called alloca(). Originally, this space + was supposed to be taken from the current stack frame of the + caller, but that method cannot be made to work for some + implementations of C, for example under Gould's UTX/32. +*/ + +static header *last_alloca_header = NULL; /* -> last alloca header */ + +pointer +alloca (size) /* returns pointer to storage */ + unsigned size; /* # bytes to allocate */ +{ + auto char probe; /* probes stack depth: */ + register char *depth = &probe; + +#if STACK_DIRECTION == 0 + if (STACK_DIR == 0) /* unknown growth direction */ + find_stack_direction (); +#endif + + /* Reclaim garbage, defined as all alloca()ed storage that + was allocated from deeper in the stack than currently. */ + + { + register header *hp; /* traverses linked list */ + + for (hp = last_alloca_header; hp != NULL;) + if (STACK_DIR > 0 && hp->h.deep > depth + || STACK_DIR < 0 && hp->h.deep < depth) + { + register header *np = hp->h.next; + + free ((pointer) hp); /* collect garbage */ + + hp = np; /* -> next header */ + } + else + break; /* rest are not deeper */ + + last_alloca_header = hp; /* -> last valid storage */ + } + + if (size == 0) + return NULL; /* no allocation required */ + + /* Allocate combined header + user data storage. */ + + { + register pointer new = xmalloc (sizeof (header) + size); + /* address of header */ + + ((header *)new)->h.next = last_alloca_header; + ((header *)new)->h.deep = depth; + + last_alloca_header = (header *)new; + + /* User storage begins just after header. */ + + return (pointer)((char *)new + sizeof(header)); + } +} + diff --git a/gcc-1.40/assert.h b/gcc-1.40/assert.h new file mode 100644 index 0000000..0cc8b8d --- /dev/null +++ b/gcc-1.40/assert.h @@ -0,0 +1,32 @@ +/* Allow this file to be included multiple times + with different settings of NDEBUG. */ +#undef assert +#undef __assert + +#ifdef NDEBUG +#define assert(ignore) ((void)0) +#else + +void __eprintf (); /* Defined in gnulib */ + +#ifdef __STDC__ + +#define assert(expression) \ + ((void) ((expression) ? 0 : __assert (#expression, __FILE__, __LINE__))) + +#define __assert(expression, file, lineno) \ + (__eprintf ("Failed assertion `%s' at line %d of `%s'.\n", \ + expression, lineno, file), 0) + +#else /* no __STDC__; i.e. -traditional. */ + +#define assert(expression) \ + ((void) ((expression) ? 0 : __assert (expression, __FILE__, __LINE__))) + +#define __assert(expression, file, lineno) \ + (__eprintf ("Failed assertion `%s' at line %d of `%s'.\n", \ + "expression", lineno, file), 0) + +#endif /* no __STDC__; i.e. -traditional. */ + +#endif diff --git a/gcc-1.40/basic-block.h b/gcc-1.40/basic-block.h new file mode 100644 index 0000000..42d4cc9 --- /dev/null +++ b/gcc-1.40/basic-block.h @@ -0,0 +1,62 @@ +/* Define control and data flow tables, and regsets. + Copyright (C) 1987 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 1, 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. */ + + +/* Define the type for a pointer to a set with a bit for each + (hard or pseudo) register. */ + +typedef long *regset; + +/* Size of a regset for the current function, + in (1) bytes and (2) elements. */ + +extern int regset_bytes; +extern int regset_size; + +/* Number of bits in each actual element of a regset. */ + +#define REGSET_ELT_BITS HOST_BITS_PER_INT + +/* Number of basic blocks in the current function. */ + +extern int n_basic_blocks; + +/* Index by basic block number, get first insn in the block. */ + +extern rtx *basic_block_head; + +/* Index by basic block number, get last insn in the block. */ + +extern rtx *basic_block_end; + +/* 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; + +/* 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. */ + +#define REG_BLOCK_UNKNOWN -1 +#define REG_BLOCK_GLOBAL -2 +extern short *reg_basic_block; diff --git a/gcc-1.40/c-convert.c b/gcc-1.40/c-convert.c new file mode 100644 index 0000000..85ac17b --- /dev/null +++ b/gcc-1.40/c-convert.c @@ -0,0 +1,397 @@ +/* Language-level data type conversion for GNU C. + Copyright (C) 1987, 1988 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 1, 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 contains the functions for converting C expressions + to different data types. The only entry point is `convert'. + Every language front end must have a `convert' function + but what kind of conversions it does will depend on the language. */ + +#include "config.h" +#include "tree.h" + +/* Change of width--truncation and extension of integers or reals-- + is represented with NOP_EXPR. Proper functioning of many things + assumes that no other conversions can be NOP_EXPRs. + + Conversion between integer and pointer is represented with CONVERT_EXPR. + Converting integer to real uses FLOAT_EXPR + and real to integer uses FIX_TRUNC_EXPR. + + Here is a list of all the functions that assume that widening and + narrowing is always done with a NOP_EXPR: + In c-convert.c, convert_to_integer. + In c-typeck.c, build_binary_op_nodefault (boolean ops), + and truthvalue_conversion. + In expr.c: expand_expr, for operands of a MULT_EXPR. + In fold-const.c: fold. + In tree.c: get_narrower and get_unwidened. */ + +/* Subroutines of `convert'. */ + +static 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)) + { + if (type == TREE_TYPE (null_pointer_node)) + return null_pointer_node; + expr = build_int_2 (0, 0); + TREE_TYPE (expr) = type; + return expr; + } + + if (form == POINTER_TYPE) + return build (NOP_EXPR, type, expr); + + + if (form == INTEGER_TYPE || form == ENUMERAL_TYPE) + { + if (type_precision (intype) == POINTER_SIZE) + return build (CONVERT_EXPR, type, expr); + return convert_to_pointer (type, + convert (type_for_size (POINTER_SIZE, 0), + expr)); + } + + error ("cannot convert to a pointer type"); + + return null_pointer_node; +} + +static tree +convert_to_real (type, expr) + tree type, expr; +{ + register enum tree_code form = TREE_CODE (TREE_TYPE (expr)); + extern int flag_float_store; + + if (form == REAL_TYPE) + return build (flag_float_store ? CONVERT_EXPR : NOP_EXPR, + type, expr); + + if (form == INTEGER_TYPE || form == ENUMERAL_TYPE) + return build (FLOAT_EXPR, type, expr); + + if (form == POINTER_TYPE) + error ("pointer value used where a float 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"); + return tem; + } +} + +/* The result of this is always supposed to be a newly created tree node + not in use in any existing structure. */ + +static tree +convert_to_integer (type, expr) + tree type, expr; +{ + register tree intype = TREE_TYPE (expr); + register enum tree_code form = TREE_CODE (intype); + extern tree build_binary_op_nodefault (); + extern tree build_unary_op (); + + if (form == POINTER_TYPE) + { + if (integer_zerop (expr)) + expr = integer_zero_node; + else + expr = fold (build (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) + { + register int outprec = TYPE_PRECISION (type); + register int inprec = TYPE_PRECISION (intype); + register enum tree_code ex_form = TREE_CODE (expr); + + if (outprec >= inprec) + return build (NOP_EXPR, type, expr); + +/* Here detect when we can distribute the truncation down past some arithmetic. + For example, if adding two longs and converting to an int, + we can equally well convert both to ints and then add. + For the operations handled here, such truncation distribution + is always safe. + It is desirable in these cases: + 1) when truncating down to full-word from a larger size + 2) when truncating takes no work. + 3) when at least one operand of the arithmetic has been extended + (as by C's default conversions). In this case we need two conversions + if we do the arithmetic as already requested, so we might as well + truncate both and then combine. Perhaps that way we need only one. + + Note that in general we cannot do the arithmetic in a type + shorter than the desired result of conversion, even if the operands + are both extended from a shorter type, because they might overflow + if combined in that type. The exceptions to this--the times when + two narrow values can be combined in their narrow type even to + make a wider result--are handled by "shorten" in build_binary_op. */ + + switch (ex_form) + { + case RSHIFT_EXPR: + /* We can pass truncation down through right shifting + when the shift count is a negative constant. */ + if (TREE_CODE (TREE_OPERAND (expr, 1)) != INTEGER_CST + || TREE_INT_CST_LOW (TREE_OPERAND (expr, 1)) > 0) + break; + goto trunc1; + + case LSHIFT_EXPR: + /* We can pass truncation down through left shifting + when the shift count is a positive constant. */ + if (TREE_CODE (TREE_OPERAND (expr, 1)) != INTEGER_CST + || TREE_INT_CST_LOW (TREE_OPERAND (expr, 1)) < 0) + break; + /* In this case, shifting is like multiplication. */ + goto trunc1; + + case MAX_EXPR: + case MIN_EXPR: + case MULT_EXPR: + { + tree arg0 = get_unwidened (TREE_OPERAND (expr, 0), type); + tree arg1 = get_unwidened (TREE_OPERAND (expr, 1), type); + + /* Don't distribute unless the output precision is at least as big + as the actual inputs. Otherwise, the comparison of the + truncated values will be wrong. */ + if (outprec >= TYPE_PRECISION (TREE_TYPE (arg0)) + && outprec >= TYPE_PRECISION (TREE_TYPE (arg1)) + /* If signedness of arg0 and arg1 don't match, + we can't necessarily find a type to compare them in. */ + && (TREE_UNSIGNED (TREE_TYPE (arg0)) + == TREE_UNSIGNED (TREE_TYPE (arg1)))) + goto trunc1; + break; + } + + case PLUS_EXPR: + case MINUS_EXPR: + case BIT_AND_EXPR: + case BIT_IOR_EXPR: + case BIT_XOR_EXPR: + case BIT_ANDTC_EXPR: + trunc1: + { + tree arg0 = get_unwidened (TREE_OPERAND (expr, 0), type); + tree arg1 = get_unwidened (TREE_OPERAND (expr, 1), type); + + if (outprec >= BITS_PER_WORD + || TRULY_NOOP_TRUNCATION (outprec, inprec) + || inprec > TYPE_PRECISION (TREE_TYPE (arg0)) + || inprec > TYPE_PRECISION (TREE_TYPE (arg1))) + { + /* 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. + Exception: if the original operands were unsigned + then can safely do the work as unsigned. + And we may need to do it as unsigned + if we truncate to the original size. */ + typex = ((TREE_UNSIGNED (TREE_TYPE (expr)) + || TREE_UNSIGNED (TREE_TYPE (arg0))) + ? unsigned_type (typex) : signed_type (typex)); + return convert (type, + build_binary_op_nodefault (ex_form, + convert (typex, arg0), + convert (typex, arg1), + ex_form)); + } + } + } + break; + + case EQ_EXPR: + case NE_EXPR: + case GT_EXPR: + case GE_EXPR: + case LT_EXPR: + case LE_EXPR: + case TRUTH_AND_EXPR: + case TRUTH_ANDIF_EXPR: + case TRUTH_OR_EXPR: + case TRUTH_ORIF_EXPR: + case TRUTH_NOT_EXPR: + /* If we want result of comparison converted to a byte, + we can just regard it as a byte, since it is 0 or 1. */ + TREE_TYPE (expr) = type; + return expr; + + case NEGATE_EXPR: + case BIT_NOT_EXPR: + case ABS_EXPR: + { + 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, + build_unary_op (ex_form, + convert (typex, TREE_OPERAND (expr, 0)), + 1)); + } + } + + case NOP_EXPR: + /* If truncating after truncating, might as well do all at once. + If truncating after extending, we may get rid of wasted work. */ + 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, + build (COND_EXPR, typex, + TREE_OPERAND (expr, 0), + convert (typex, arg1), + convert (typex, arg2))); + } + } + } + + } + + return build (NOP_EXPR, type, expr); + } + + if (form == REAL_TYPE) + return build (FIX_TRUNC_EXPR, type, expr); + + error ("aggregate value used where an integer was expected"); + + { + register tree tem = build_int_2 (0, 0); + TREE_TYPE (tem) = type; + return tem; + } +} + +/* Create an expression whose value is that of EXPR, + 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. */ + +tree +convert (type, expr) + tree type, expr; +{ + register tree e = expr; + register enum tree_code code = TREE_CODE (type); + + if (type == TREE_TYPE (expr) || TREE_CODE (expr) == ERROR_MARK) + return expr; + if (TREE_CODE (TREE_TYPE (expr)) == ERROR_MARK) + return error_mark_node; + if (TREE_CODE (TREE_TYPE (expr)) == VOID_TYPE) + { + error ("void value not ignored as it ought to be"); + return error_mark_node; + } + if (code == VOID_TYPE) + return build (CONVERT_EXPR, type, e); +#if 0 + /* This is incorrect. A truncation can't be stripped this way. + Extensions will be stripped by the use of get_unwidened. */ + if (TREE_CODE (expr) == NOP_EXPR) + return convert (type, TREE_OPERAND (expr, 0)); +#endif + 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)); + + error ("conversion to non-scalar type requested"); + return error_mark_node; +} diff --git a/gcc-1.40/c-decl.c b/gcc-1.40/c-decl.c new file mode 100644 index 0000000..0af12fb --- /dev/null +++ b/gcc-1.40/c-decl.c @@ -0,0 +1,4103 @@ +/* Process declarations and variables for C compiler. + Copyright (C) 1988 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 1, 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. */ + + +/* Process declarations and symbol lookup for C front end. + Also constructs types; the standard scalar types at initialization, + and structure, union, array and enum types when they are declared. */ + +/* ??? not all decl nodes are given the most useful possible + line numbers. For example, the CONST_DECLs for enum values. */ + +#include "config.h" +#include "tree.h" +#include "flags.h" +#include "c-tree.h" +#include "c-parse.h" + +#include + +/* In grokdeclarator, distinguish syntactic contexts of declarators. */ +enum decl_context +{ NORMAL, /* Ordinary declaration */ + FUNCDEF, /* Function definition */ + PARM, /* Declaration of parm before function body */ + FIELD, /* Declaration inside struct or union */ + TYPENAME}; /* Typename (inside cast or sizeof) */ + +#define NULL 0 +#define MIN(X,Y) ((X) < (Y) ? (X) : (Y)) +#define MAX(X,Y) ((X) > (Y) ? (X) : (Y)) + +#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 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 + +/* 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 + multiple error messages from one error in the input. */ + +tree error_mark_node; + +/* INTEGER_TYPE and REAL_TYPE nodes for the standard data types */ + +tree short_integer_type_node; +tree integer_type_node; +tree long_integer_type_node; +tree long_long_integer_type_node; + +tree short_unsigned_type_node; +tree unsigned_type_node; +tree long_unsigned_type_node; +tree long_long_unsigned_type_node; + +tree unsigned_char_type_node; +tree signed_char_type_node; +tree char_type_node; + +tree float_type_node; +tree double_type_node; +tree long_double_type_node; + +/* a VOID_TYPE node. */ + +tree void_type_node; + +/* A node for type `void *'. */ + +tree ptr_type_node; + +/* A node for type `char *'. */ + +tree string_type_node; + +/* Type `char[256]' or something like it. + Used when an array of char is needed and the size is irrelevant. */ + +tree char_array_type_node; + +/* Type `int[256]' or something like it. + Used when an array of int needed and the size is irrelevant. */ + +tree int_array_type_node; + +/* 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 type `void (void *, void *, int)' and similar ones */ + +tree void_ftype_ptr_ptr_int, int_ftype_ptr_ptr_int, void_ftype_ptr_int_int; + +/* Two expressions that are constants with value zero. + The first is of type `int', the second of type `void *'. */ + +tree integer_zero_node; +tree null_pointer_node; + +/* A node for the integer constant 1. */ + +tree integer_one_node; + +/* An identifier whose name is . This is used as the "name" + of the RESULT_DECLs for values of functions. */ + +tree value_identifier; + +/* While defining an enum type, this is 1 plus the last enumerator + constant value. */ + +static tree enum_next_value; + +/* Parsing a function declarator leaves a list of parameter names + or a chain or parameter decls here. */ + +static tree last_function_parms; + +/* Parsing a function declarator leaves here a chain of structure + and enum types declared in the parmlist. */ + +static tree last_function_parm_tags; + +/* After parsing the declarator that starts a function definition, + `start_function' puts here the list of parameter names or chain of decls. + `store_parm_decls' finds it here. */ + +static tree current_function_parms; + +/* Similar, for last_function_parm_tags. */ +static tree current_function_parm_tags; + +/* A list (chain of TREE_LIST nodes) of all LABEL_STMTs 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; + +/* The FUNCTION_DECL for the function currently being compiled, + or 0 if between functions. */ +tree current_function_decl; + +/* Set to 0 at beginning of a function definition, set to 1 if + a return statement that specifies a return value is seen. */ + +int current_function_returns_value; + +/* Set to 0 at beginning of a function definition, set to 1 if + a return statement with no argument is seen. */ + +int current_function_returns_null; + +/* Set to nonzero by `grokdeclarator' for a function + whose return type is defaulted, if warnings for this are desired. */ + +static int warn_about_return_type; + +/* Nonzero when starting a function delcared `extern inline'. */ + +static int current_extern_inline; + +/* 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. + */ + +/* 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; + + /* 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. + */ + tree tags; + + /* 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 + whose TREE_VALUE is its old definition (a kind of ..._DECL node). */ + tree shadowed; + + /* For each level (except not the global one), + a chain of LET_STMT nodes for all the levels + that were entered and exited one level down. */ + tree blocks; + + /* The binding level which this one is contained in (inherits from). */ + struct binding_level *level_chain; + + /* Nonzero for the level that holds the parameters of a function. */ + char parm_flag; + + /* Nonzero if this level "doesn't exist" for tags. */ + char tag_transparent; + + /* Nonzero means make a LET_STMT for this level regardless of all else. */ + char keep; + + /* Nonzero means make a LET_STMT if this level has any subblocks. */ + char keep_if_subblocks; + + /* Number of decls in `names' that have incomplete + structure or union types. */ + int n_incomplete; + }; + +#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, NULL, 0, 0, 0}; + +/* Nonzero means unconditionally make a LET_STMT for the next level pushed. */ + +static int keep_next_level_flag; + +/* Nonzero means make a LET_STMT for the next level pushed + if it has subblocks. */ + +static int keep_next_if_subblocks; + +/* Forward declarations. */ + +static tree grokparms (), grokdeclarator (); +tree pushdecl (); +static void builtin_function (); + +static tree lookup_tag (); +static tree lookup_tag_reverse (); +static tree lookup_name_current_level (); +static char *redeclaration_error_message (); +static void layout_array_type (); + +/* C-specific option variables. */ + +/* Nonzero means allow type mismatches in conditional expressions; + just make their values `void'. */ + +int flag_cond_mismatch; + +/* Nonzero means don't recognize the keyword `asm'. */ + +int flag_no_asm; + +/* Nonzero means do some things the same way PCC does. */ + +int flag_traditional; + +/* Nonzero means warn about implicit declarations. */ + +int warn_implicit; + +/* Nonzero means warn about function definitions that default the return type + or that use a null return and have a return-type other than void. */ + +int warn_return_type; + +/* 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. */ + +int warn_write_strings; + +/* Nonzero means warn about pointer casts that can drop a type qualifier + from the pointer target type. */ + +int warn_cast_qual; + +/* Nonzero means warn about sizeof(function) or addition/subtraction + of function pointers. */ + +int warn_pointer_arith; + +/* Nonzero means warn for all old-style non-prototype function decls. */ + +int warn_strict_prototypes; + +/* Nonzero means `$' can be in an identifier. + See cccp.c for reasons why this breaks some obscure ANSI C programs. */ + +#ifndef DOLLARS_IN_IDENTIFIERS +#define DOLLARS_IN_IDENTIFIERS 0 +#endif +int dollars_in_ident = DOLLARS_IN_IDENTIFIERS; + +char *language_string = "GNU C"; + +/* Decode the string P as a language-specific option. + Return 1 if it is recognized (and handle it); + return 0 if not recognized. */ + +int +lang_decode_option (p) + char *p; +{ + if (!strcmp (p, "-ftraditional") || !strcmp (p, "-traditional")) + flag_traditional = 1, dollars_in_ident = 1, flag_writable_strings = 1; + else if (!strcmp (p, "-fsigned-char")) + flag_signed_char = 1; + else if (!strcmp (p, "-funsigned-char")) + flag_signed_char = 0; + else if (!strcmp (p, "-fno-signed-char")) + flag_signed_char = 0; + else if (!strcmp (p, "-fno-unsigned-char")) + flag_signed_char = 1; + else if (!strcmp (p, "-fshort-enums")) + flag_short_enums = 1; + else if (!strcmp (p, "-fno-short-enums")) + flag_short_enums = 0; + else if (!strcmp (p, "-fcond-mismatch")) + flag_cond_mismatch = 1; + else if (!strcmp (p, "-fno-cond-mismatch")) + flag_cond_mismatch = 0; + else if (!strcmp (p, "-fasm")) + flag_no_asm = 0; + else if (!strcmp (p, "-fno-asm")) + flag_no_asm = 1; + else if (!strcmp (p, "-ansi")) + flag_no_asm = 1, dollars_in_ident = 0; + else if (!strcmp (p, "-Wimplicit")) + warn_implicit = 1; + else if (!strcmp (p, "-Wreturn-type")) + warn_return_type = 1; + else if (!strcmp (p, "-Wwrite-strings")) + warn_write_strings = 1; + else if (!strcmp (p, "-Wcast-qual")) + warn_cast_qual = 1; + else if (!strcmp (p, "-Wpointer-arith")) + warn_pointer_arith = 1; + else if (!strcmp (p, "-Wstrict-prototypes")) + warn_strict_prototypes = 1; + else if (!strcmp (p, "-Wcomment")) + ; /* cpp handles this one. */ + else if (!strcmp (p, "-Wcomments")) + ; /* cpp handles this one. */ + else if (!strcmp (p, "-Wtrigraphs")) + ; /* cpp handles this one. */ + else if (!strcmp (p, "-Wall")) + { + extra_warnings = 1; + warn_implicit = 1; + warn_return_type = 1; + warn_unused = 1; + warn_switch = 1; + } + else + return 0; + + return 1; +} + +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); + print_node (file, "label", IDENTIFIER_LABEL_VALUE (node), indent + 4); + print_node (file, "implicit", IDENTIFIER_IMPLICIT_DECL (node), indent + 4); + print_node (file, "error locus", IDENTIFIER_ERROR_LOCUS (node), indent + 4); +} + +/* 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 +global_bindings_p () +{ + return current_binding_level == global_binding_level; +} + +void +keep_next_level () +{ + keep_next_level_flag = 1; +} + +/* Nonzero if the current level needs to have a LET_STMT made. */ + +int +kept_level_p () +{ + return ((current_binding_level->keep_if_subblocks + && current_binding_level->blocks != 0) + || current_binding_level->keep + || current_binding_level->names != 0); +} + +/* Identify this binding level as a level of parameters. */ + +void +declare_parm_level () +{ + current_binding_level->parm_flag = 1; +} + +/* Nonzero if currently making parm declarations. */ + +in_parm_level_p () +{ + return current_binding_level->parm_flag; +} + +/* 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; + + /* If this is the top level of a function, + just make sure that NAMED_LABELS is 0. + They should have been set to 0 at the end of the previous function. */ + + if (current_binding_level == global_binding_level) + { + if (named_labels) + abort (); + } + + /* 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; + newlevel->tag_transparent = tag_transparent; + newlevel->keep = keep_next_level_flag; + keep_next_level_flag = 0; + newlevel->keep_if_subblocks = keep_next_if_subblocks; + keep_next_if_subblocks = 0; +} + +/* 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 LET_STMT 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 LET_STMT. */ + +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 tags = current_binding_level->tags; + tree subblocks = current_binding_level->blocks; + tree block = 0; + + keep |= current_binding_level->keep; + + /* 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)) == 0) + { + 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, IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (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. */ + + if (reverse) + current_binding_level->names + = decls = nreverse (current_binding_level->names); + else + decls = current_binding_level->names; + + /* If there were any declarations or structure tags in that level, + or if this level is a function body, + create a LET_STMT to record them for the life of this function. */ + + if (keep || functionbody + || (current_binding_level->keep_if_subblocks && subblocks != 0)) + block = build_let (0, 0, keep ? decls : 0, + subblocks, 0, keep ? tags : 0); + + /* In each subblock, record that this is its superior. */ + + for (link = subblocks; link; link = TREE_CHAIN (link)) + STMT_SUPERCONTEXT (link) = block; + + /* Clear out the meanings of the local variables of this level; + also record in each decl which block it belongs to. */ + + for (link = decls; link; link = TREE_CHAIN (link)) + { + if (DECL_NAME (link) != 0) + { + /* If the ident. was used via a local extern decl, + don't forget that fact. */ + if (TREE_USED (link) && TREE_EXTERNAL (link)) + TREE_USED (DECL_NAME (link)) = 1; + IDENTIFIER_LOCAL_VALUE (DECL_NAME (link)) = 0; + } + DECL_CONTEXT (link) = block; + } + + /* 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); + + /* If the level being exited is the top level of a function, + check over all the labels. */ + + if (functionbody) + { + /* Clear out the definitions of all label names, + since their scopes end here. */ + + for (link = named_labels; link; link = TREE_CHAIN (link)) + { + if (DECL_SOURCE_LINE (TREE_VALUE (link)) == 0) + { + error ("label `%s' used somewhere above but not defined", + IDENTIFIER_POINTER (DECL_NAME (TREE_VALUE (link)))); + /* Avoid crashing later. */ + define_label (input_filename, 1, DECL_NAME (TREE_VALUE (link))); + } + else if (warn_unused && !TREE_USED (TREE_VALUE (link))) + warning_with_decl (TREE_VALUE (link), + "label `%s' defined but not used"); + IDENTIFIER_LABEL_VALUE (DECL_NAME (TREE_VALUE (link))) = 0; + } + + named_labels = 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; + } + + if (functionbody) + { + DECL_INITIAL (current_function_decl) = block; + /* If this is the top level block of a function, + the vars are the function's parameters. + Don't leave them in the LET_STMT because they are + found in the FUNCTION_DECL instead. */ + STMT_VARS (block) = 0; + } + else if (block) + 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); + + if (block) + TREE_USED (block) = 1; + return block; +} + +/* Push a definition of struct, union or enum tag "name". + "type" should be the type node. + We assume that the tag "name" is not already defined. + + Note that the definition may really be just a forward reference. + In that case, the TYPE_SIZE will be zero. */ + +void +pushtag (name, type) + tree name, type; +{ + register struct binding_level *b = current_binding_level; + while (b->tag_transparent) b = b->level_chain; + + if (name) + { + /* Record the identifier as the type's name if it has none. */ + + if (TYPE_NAME (type) == 0) + TYPE_NAME (type) = name; + + if (b == global_binding_level) + b->tags = perm_tree_cons (name, type, b->tags); + else + b->tags = saveable_tree_cons (name, type, b->tags); + } +} + +/* 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 (newdecl, olddecl) + register tree newdecl, olddecl; +{ + int types_match = comptypes (TREE_TYPE (newdecl), TREE_TYPE (olddecl)); + + if (TREE_CODE (TREE_TYPE (newdecl)) == ERROR_MARK + || TREE_CODE (TREE_TYPE (olddecl)) == ERROR_MARK) + types_match = 0; + + /* If this decl has linkage, and the old one does too, maybe no error. */ + if (TREE_CODE (olddecl) != TREE_CODE (newdecl)) + { + error_with_decl (newdecl, "`%s' redeclared as different kind of symbol"); + error_with_decl (olddecl, "previous declaration of `%s'"); + } + else + { + if (flag_traditional && TREE_CODE (newdecl) == FUNCTION_DECL + && IDENTIFIER_IMPLICIT_DECL (DECL_NAME (newdecl)) == olddecl + && DECL_INITIAL (olddecl) == 0) + /* If -traditional, avoid error for redeclaring fcn + after implicit decl. */ + ; + else if (TREE_CODE (olddecl) == FUNCTION_DECL + && DECL_FUNCTION_CODE (olddecl) != NOT_BUILT_IN) + { + if (!types_match) + error_with_decl (newdecl, "conflicting types for built-in function `%s'"); + else if (extra_warnings) + warning_with_decl (newdecl, "built-in function `%s' redeclared"); + } + else if (!types_match) + { + error_with_decl (newdecl, "conflicting types for `%s'"); + /* Check for function type mismatch + involving an empty arglist vs a nonempty one. */ + if (TREE_CODE (olddecl) == FUNCTION_DECL + && comptypes (TREE_TYPE (TREE_TYPE (olddecl)), + TREE_TYPE (TREE_TYPE (newdecl))) + && ((TYPE_ARG_TYPES (TREE_TYPE (olddecl)) == 0 + && DECL_INITIAL (olddecl) == 0) + || + (TYPE_ARG_TYPES (TREE_TYPE (newdecl)) == 0 + && DECL_INITIAL (newdecl) == 0))) + { + /* Classify the problem further. */ + register tree t = TYPE_ARG_TYPES (TREE_TYPE (olddecl)); + if (t == 0) + t = TYPE_ARG_TYPES (TREE_TYPE (newdecl)); + for (; t; t = TREE_CHAIN (t)) + { + register tree type = TREE_VALUE (t); + + if (TREE_CHAIN (t) == 0 && type != void_type_node) + { + error ("A parameter list with an ellipsis can't match"); + error ("an empty parameter name list declaration."); + break; + } + + if (type == float_type_node + || (TREE_CODE (type) == INTEGER_TYPE + && (TYPE_PRECISION (type) + < TYPE_PRECISION (integer_type_node)))) + { + error ("An argument type that has a default promotion"); + error ("can't match an empty parameter name list declaration."); + break; + } + } + } + error_with_decl (olddecl, "previous declaration of `%s'"); + } + else + { + char *errmsg = redeclaration_error_message (newdecl, olddecl); + if (errmsg) + { + error_with_decl (newdecl, errmsg); + error_with_decl (olddecl, + "here is the previous declaration of `%s'"); + } + else if (TREE_CODE (olddecl) == FUNCTION_DECL + && DECL_INITIAL (olddecl) != 0 + && TYPE_ARG_TYPES (TREE_TYPE (olddecl)) == 0 + && TYPE_ARG_TYPES (TREE_TYPE (newdecl)) != 0) + { + /* Prototype decl follows defn w/o prototype. */ + warning_with_decl (newdecl, "prototype for `%s'"); + warning_with_decl (olddecl, + "follows non-prototype definition here"); + } + + /* These bits are logically part of the type. */ + if (pedantic + && (TREE_READONLY (newdecl) != TREE_READONLY (olddecl) + || TREE_THIS_VOLATILE (newdecl) != TREE_THIS_VOLATILE (olddecl))) + warning_with_decl (newdecl, "type qualifiers for `%s' conflict with previous decl"); + } + } + + if (TREE_CODE (olddecl) == TREE_CODE (newdecl)) + { + int new_is_definition = (TREE_CODE (newdecl) == FUNCTION_DECL + && DECL_INITIAL (newdecl) != 0); + + /* Copy all the DECL_... slots specified in the new decl + except for any that we copy here from the old type. */ + + if (types_match) + { + tree oldtype = TREE_TYPE (olddecl); + /* Merge the data types specified in the two decls. */ + TREE_TYPE (newdecl) + = TREE_TYPE (olddecl) + = commontype (TREE_TYPE (newdecl), TREE_TYPE (olddecl)); + + /* 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); + DECL_SIZE_UNIT (newdecl) = DECL_SIZE_UNIT (olddecl); + if (DECL_ALIGN (olddecl) > DECL_ALIGN (newdecl)) + DECL_ALIGN (newdecl) = DECL_ALIGN (olddecl); + } + + /* Merge the type qualifiers. */ + if (TREE_READONLY (newdecl)) + TREE_READONLY (olddecl) = 1; + if (TREE_THIS_VOLATILE (newdecl)) + TREE_THIS_VOLATILE (olddecl) = 1; + + /* Merge the initialization information. */ + if (DECL_INITIAL (newdecl) == 0) + DECL_INITIAL (newdecl) = DECL_INITIAL (olddecl); + /* Keep the old rtl since we can safely use it. */ + DECL_RTL (newdecl) = DECL_RTL (olddecl); + } + /* 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_VOLATILE (olddecl) = TREE_VOLATILE (newdecl); + } + + /* Merge the storage class information. */ + if (TREE_EXTERNAL (newdecl)) + { + TREE_STATIC (newdecl) = TREE_STATIC (olddecl); + TREE_EXTERNAL (newdecl) = TREE_EXTERNAL (olddecl); + + /* 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; + } + else + TREE_PUBLIC (newdecl) = TREE_PUBLIC (olddecl); + } + else + { + TREE_STATIC (olddecl) = TREE_STATIC (newdecl); + TREE_EXTERNAL (olddecl) = 0; + TREE_PUBLIC (olddecl) = TREE_PUBLIC (newdecl); + } + + /* If either decl says `inline', this fn is inline, + unless its definition was passed already. */ + if (TREE_INLINE (newdecl) && DECL_INITIAL (olddecl) == 0) + TREE_INLINE (olddecl) = 1; + + /* 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) + { + DECL_SET_FUNCTION_CODE (newdecl, DECL_FUNCTION_CODE (olddecl)); + DECL_RESULT (newdecl) = DECL_RESULT (olddecl); + DECL_INITIAL (newdecl) = DECL_INITIAL (olddecl); + DECL_SAVED_INSNS (newdecl) = DECL_SAVED_INSNS (olddecl); + DECL_RESULT_TYPE (newdecl) = DECL_RESULT_TYPE (olddecl); + DECL_ARGUMENTS (newdecl) = DECL_ARGUMENTS (olddecl); + DECL_FRAME_SIZE (newdecl) = DECL_FRAME_SIZE (olddecl); + } + + /* Don't lose track of having output OLDDECL as GDB symbol. */ + DECL_BLOCK_SYMTAB_ADDRESS (newdecl) + = DECL_BLOCK_SYMTAB_ADDRESS (olddecl); + + bcopy ((char *) newdecl + sizeof (struct tree_common), + (char *) olddecl + sizeof (struct tree_common), + sizeof (struct tree_decl) - sizeof (struct tree_common)); + + return 1; + } + + /* New decl is completely inconsistent with the old one => + tell caller to replace the old one. */ + return 0; +} + +/* 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 (name) + { + char *file; + int line; + + t = lookup_name_current_level (name); + if (t != 0 && t == error_mark_node) + /* error_mark_node is 0 for a while during initialization! */ + { + t = 0; + error_with_decl (x, "`%s' used prior to declaration"); + } + + if (t != 0) + { + file = DECL_SOURCE_FILE (t); + line = DECL_SOURCE_LINE (t); + } + + 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) + && ! TREE_PUBLIC (x) && ! TREE_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) + { + warning ("`%s' was declared implicitly `extern' and later `static'", + IDENTIFIER_POINTER (name)); + warning_with_file_and_line (file, line, + "previous declaration of `%s'", + IDENTIFIER_POINTER (name)); + } + return t; + } + + /* If declaring a type as a typedef, and the type has no known + typedef name, install this TYPE_DECL as its typedef name. */ + if (TREE_CODE (x) == TYPE_DECL) + if (TYPE_NAME (TREE_TYPE (x)) == 0) + TYPE_NAME (TREE_TYPE (x)) = x; + + /* Multiple external decls of the same identifier ought to match. */ + + if (TREE_EXTERNAL (x) && IDENTIFIER_GLOBAL_VALUE (name) != 0 + && (TREE_EXTERNAL (IDENTIFIER_GLOBAL_VALUE (name)) + || TREE_PUBLIC (IDENTIFIER_GLOBAL_VALUE (name)))) + { + if (! comptypes (TREE_TYPE (x), + TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (name)))) + { + warning_with_decl (x, + "type mismatch with previous external decl"); + warning_with_decl (IDENTIFIER_GLOBAL_VALUE (name), + "previous external decl of `%s'"); + } + } + + /* 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 && TREE_EXTERNAL (x) + && lookup_name (name) == 0) + { + tree type = TREE_TYPE (x); + + /* But don't do this if the type contains temporary nodes. */ + while (type) + { + if (! TREE_PERMANENT (type)) + { + warning_with_decl (x, "Type of `extern' decl is not global"); + break; + } + else if (TREE_CODE (type) == FUNCTION_TYPE + && TYPE_ARG_TYPES (type) != 0) + /* The types might not be truly local, + but the list of arg types certainly is temporary. + Since prototypes are nontraditional, + ok not to do the traditional thing. */ + break; + type = TREE_TYPE (type); + } + + if (type == 0) + b = global_binding_level; + } + + /* This name is new in its binding level. + Install the new declaration and return it. */ + if (b == global_binding_level) + { + /* Install a global value. */ + + /* If the first global decl has external linkage, + warn if we later see static one. */ + if (IDENTIFIER_GLOBAL_VALUE (name) == 0 && TREE_PUBLIC (x)) + TREE_PUBLIC (name) = 1; + + IDENTIFIER_GLOBAL_VALUE (name) = x; + + /* Don't forget if the function was used via an implicit decl. */ + if (IDENTIFIER_IMPLICIT_DECL (name) + && TREE_USED (IDENTIFIER_IMPLICIT_DECL (name))) + TREE_USED (x) = 1, TREE_USED (name) = 1; + + /* Don't forget if its address was taken in that way. */ + if (IDENTIFIER_IMPLICIT_DECL (name) + && TREE_ADDRESSABLE (IDENTIFIER_IMPLICIT_DECL (name))) + TREE_ADDRESSABLE (x) = 1; + + /* Warn about mismatches against previous implicit decl. */ + if (IDENTIFIER_IMPLICIT_DECL (name) != 0 + /* If this real decl matches the implicit, don't complain. */ + && ! (TREE_CODE (x) == FUNCTION_DECL + && TREE_TYPE (TREE_TYPE (x)) == integer_type_node)) + warning ("`%s' was previously implicitly declared to return `int'", + IDENTIFIER_POINTER (name)); + + /* If this decl is `static' and an `extern' was seen previously, + that is erroneous. */ + if (TREE_PUBLIC (name) + && ! TREE_PUBLIC (x) && ! TREE_EXTERNAL (x)) + { + if (IDENTIFIER_IMPLICIT_DECL (name)) + warning ("`%s' was declared implicitly `extern' and later `static'", + IDENTIFIER_POINTER (name)); + else + warning ("`%s' was declared `extern' and later `static'", + IDENTIFIER_POINTER (name)); + } + } + else + { + /* Here to install a non-global value. */ + tree oldlocal = IDENTIFIER_LOCAL_VALUE (name); + tree oldglobal = IDENTIFIER_GLOBAL_VALUE (name); + IDENTIFIER_LOCAL_VALUE (name) = x; + + /* If this is an extern function declaration, see if we + have a global definition for the function. */ + if (oldlocal == 0 + && oldglobal != 0 + && TREE_CODE (x) == FUNCTION_DECL + && TREE_CODE (oldglobal) == FUNCTION_DECL) + { + /* We have one. Their types must agree. */ + if (! comptypes (TREE_TYPE (x), + TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (name)))) + warning_with_decl (x, "local declaration of `%s' doesn't match global one"); + /* If the global one is inline, make the local one inline. */ + else if (TREE_INLINE (oldglobal) + || DECL_FUNCTION_CODE (oldglobal) != NOT_BUILT_IN + || (TYPE_ARG_TYPES (TREE_TYPE (oldglobal)) != 0 + && TYPE_ARG_TYPES (TREE_TYPE (x)) == 0)) + IDENTIFIER_LOCAL_VALUE (name) = 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 == 0 + && oldglobal == 0 + && TREE_EXTERNAL (x) + && TREE_PUBLIC (x)) + { + TREE_PUBLIC (name) = 1; + } + + /* Warn if shadowing an argument at the top level of the body. */ + if (oldlocal != 0 && !TREE_EXTERNAL (x) + && TREE_CODE (oldlocal) == PARM_DECL + && TREE_CODE (x) != PARM_DECL + && current_binding_level->level_chain->parm_flag) + warning ("declaration of `%s' shadows a parameter", + IDENTIFIER_POINTER (name)); + + /* Maybe warn if shadowing something else. */ + else if (warn_shadow && !TREE_EXTERNAL (x) + /* No shadow warnings for vars made for inlining. */ + && !TREE_INLINE (x)) + { + char *warnstring = 0; + + if (oldlocal != 0 && TREE_CODE (oldlocal) == PARM_DECL) + warnstring = "declaration of `%s' shadows a parameter"; + else if (oldlocal != 0) + warnstring = "declaration of `%s' shadows previous local"; + else if (IDENTIFIER_GLOBAL_VALUE (name) != 0) + warnstring = "declaration of `%s' shadows global declaration"; + + if (warnstring) + warning (warnstring, IDENTIFIER_POINTER (name)); + } + + /* If storing a local value, there may already be one (inherited). + If so, record it for restoration when this binding level ends. */ + if (oldlocal != 0) + b->shadowed = tree_cons (name, oldlocal, b->shadowed); + } + + /* Keep count of variables in this level with incomplete type. */ + if (TYPE_SIZE (TREE_TYPE (x)) == 0) + ++b->n_incomplete; + } + + /* Put decls on list in reverse order. + We will reverse them later if necessary. */ + TREE_CHAIN (x) = b->names; + b->names = x; + + return x; +} + +/* Generate an implicit declaration for identifier FUNCTIONID + as a function of type int (). Print a warning if appropriate. */ + +tree +implicitly_declare (functionid) + tree functionid; +{ + register tree decl; + + /* Save the decl permanently so we can warn if definition follows. */ +#if 0 /* A temporary implicit decl causes a crash in pushdecl. + In 1.38, fix pushdecl. */ + if (flag_traditional || !warn_implicit + || current_binding_level == global_binding_level) +#endif + end_temporary_allocation (); + + /* We used to reuse an old implicit decl here, + but this loses with inline functions because it can clobber + the saved decl chains. */ +/* if (IDENTIFIER_IMPLICIT_DECL (functionid) != 0) + decl = IDENTIFIER_IMPLICIT_DECL (functionid); + else */ + decl = build_decl (FUNCTION_DECL, functionid, default_function_type); + + TREE_EXTERNAL (decl) = 1; + 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. */ + pushdecl (decl); + rest_of_decl_compilation (decl, 0, 0, 0); + + if (warn_implicit + /* Only one warning per identifier. */ + && IDENTIFIER_IMPLICIT_DECL (functionid) == 0) + warning ("implicit declaration of function `%s'", + IDENTIFIER_POINTER (functionid)); + + IDENTIFIER_IMPLICIT_DECL (functionid) = decl; + +#if 0 + if (flag_traditional || ! warn_implicit + || current_binding_level == global_binding_level) +#endif + resume_temporary_allocation (); + + return decl; +} + +/* Return zero if the declaration NEWDECL is valid + when the declaration OLDDECL (assumed to be for the same name) + has already been seen. + Otherwise return an error message format string with a %s + where the identifier should go. */ + +static char * +redeclaration_error_message (newdecl, olddecl) + tree newdecl, olddecl; +{ + if (TREE_CODE (newdecl) == TYPE_DECL) + { + if (flag_traditional && TREE_TYPE (newdecl) == TREE_TYPE (olddecl)) + return 0; + return "redefinition of `%s'"; + } + else if (TREE_CODE (newdecl) == FUNCTION_DECL) + { + /* Declarations of functions can insist on internal linkage + but they can't be inconsistent with internal linkage, + so there can be no error on that account. + However defining the same name twice is no good. */ + if (DECL_INITIAL (olddecl) != 0 && DECL_INITIAL (newdecl) != 0 + /* However, defining once as extern inline and a second + time in another way is ok. */ + && !(TREE_INLINE (olddecl) && TREE_EXTERNAL (olddecl) + && !(TREE_INLINE (newdecl) && TREE_EXTERNAL (newdecl)))) + return "redefinition of `%s'"; + return 0; + } + else if (current_binding_level == global_binding_level) + { + /* Objects declared at top level: */ + /* If at least one is a reference, it's ok. */ + if (TREE_EXTERNAL (newdecl) || TREE_EXTERNAL (olddecl)) + return 0; + /* Reject two definitions. */ + if (DECL_INITIAL (olddecl) != 0 && DECL_INITIAL (newdecl) != 0) + return "redefinition of `%s'"; + /* Now we have two tentative defs, or one tentative and one real def. */ + /* Insist that the linkage match. */ + if (TREE_PUBLIC (olddecl) != TREE_PUBLIC (newdecl)) + return "conflicting declarations of `%s'"; + return 0; + } + else + { + /* Objects declared with block scope: */ + /* Reject two definitions, and reject a definition + together with an external reference. */ + if (!(TREE_EXTERNAL (newdecl) && TREE_EXTERNAL (olddecl))) + return "redeclaration of `%s'"; + return 0; + } +} + +/* Get the LABEL_DECL corresponding to identifier ID as a label. + Create one if none exists so far for the current function. + This function is called for both label definitions and label references. */ + +tree +lookup_label (id) + tree id; +{ + register tree decl = IDENTIFIER_LABEL_VALUE (id); + + if (decl != 0) + return decl; + + decl = build_decl (LABEL_DECL, id, NULL_TREE); + DECL_MODE (decl) = VOIDmode; + /* Mark that the label's definition has not been seen. */ + DECL_SOURCE_LINE (decl) = 0; + + IDENTIFIER_LABEL_VALUE (id) = decl; + + named_labels + = tree_cons (NULL_TREE, decl, named_labels); + + return decl; +} + +/* Define a label, specifying the location in the source file. + Return the LABEL_DECL node for the label, if the definition is valid. + Otherwise return 0. */ + +tree +define_label (filename, line, name) + char *filename; + int line; + tree name; +{ + tree decl = lookup_label (name); + if (DECL_SOURCE_LINE (decl) != 0) + { + error_with_decl (decl, "duplicate label `%s'"); + return 0; + } + else + { + /* Mark label as having been defined. */ + DECL_SOURCE_FILE (decl) = filename; + DECL_SOURCE_LINE (decl) = line; + return decl; + } +} + +/* 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; +} + +/* Return the list of type-tags (for structs, etc) of the current level. */ + +tree +gettags () +{ + return current_binding_level->tags; +} + +/* 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 void +storedecls (decls) + tree decls; +{ + current_binding_level->names = decls; +} + +/* Similarly, store the list of tags of the current level. */ + +static void +storetags (tags) + tree tags; +{ + current_binding_level->tags = tags; +} + +/* Given NAME, an IDENTIFIER_NODE, + return the structure (or union or enum) definition for that name. + Searches binding levels from BINDING_LEVEL up to the global level. + If THISLEVEL_ONLY is nonzero, searches only the specified context + (but skips any tag-transparent contexts to find one that is + meaningful for tags). + FORM says which kind of type the caller wants; + it is RECORD_TYPE or UNION_TYPE or ENUMERAL_TYPE. + If the wrong kind of type is found, an error is reported. */ + +static tree +lookup_tag (form, name, binding_level, thislevel_only) + enum tree_code form; + struct binding_level *binding_level; + tree name; + int thislevel_only; +{ + register struct binding_level *level; + + for (level = binding_level; level; level = level->level_chain) + { + register tree tail; + for (tail = level->tags; tail; tail = TREE_CHAIN (tail)) + { + if (TREE_PURPOSE (tail) == name) + { + if (TREE_CODE (TREE_VALUE (tail)) != form) + { + /* Definition isn't the kind we were looking for. */ + error ("`%s' defined as wrong kind of tag", + IDENTIFIER_POINTER (name)); + } + return TREE_VALUE (tail); + } + } + if (thislevel_only && ! level->tag_transparent) + return NULL_TREE; + } + return NULL_TREE; +} + +/* 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 + in the cases in which this is used. */ + +static tree +lookup_tag_reverse (type) + tree type; +{ + register struct binding_level *level; + + for (level = current_binding_level; level; level = level->level_chain) + { + register tree tail; + for (tail = level->tags; tail; tail = TREE_CHAIN (tail)) + { + if (TREE_VALUE (tail) == type) + return TREE_PURPOSE (tail); + } + } + return NULL_TREE; +} + +/* Look up NAME in the current binding level and its superiors + in the namespace of variables, functions and typedefs. + Return a ..._DECL node of some kind representing its definition, + or return 0 if it is undefined. */ + +tree +lookup_name (name) + tree name; +{ + register tree val; + if (current_binding_level != global_binding_level + && IDENTIFIER_LOCAL_VALUE (name)) + val = IDENTIFIER_LOCAL_VALUE (name); + else + val = IDENTIFIER_GLOBAL_VALUE (name); + if (val && TREE_TYPE (val) == error_mark_node) + return error_mark_node; + return val; +} + +/* Similar to `lookup_name' but look only at current binding level. */ + +static tree +lookup_name_current_level (name) + 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 the predefined scalar types of C, + and some nodes representing standard constants (0, 1, (void *)0). + Initialize the global binding level. + Make definitions for built-in primitive functions. */ + +void +init_decl_processing () +{ + register tree endlink; + + /* Make identifier nodes long enough for the language-specific slots. */ + set_identifier_size (sizeof (struct lang_identifier)); + + current_function_decl = NULL; + named_labels = NULL; + 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; + + value_identifier = get_identifier (""); + + /* 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, ridpointers[(int) RID_INT], + integer_type_node)); + + /* 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)); + 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)); + + /* `unsigned long' or `unsigned int' is the standard type for sizeof. + Traditionally, use a signed type. */ + if (INT_TYPE_SIZE != LONG_TYPE_SIZE) + sizetype = flag_traditional ? long_integer_type_node : long_unsigned_type_node; + else + sizetype = flag_traditional ? integer_type_node : unsigned_type_node; + + 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; + + 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)); + + 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)); + + short_unsigned_type_node = make_unsigned_type (SHORT_TYPE_SIZE); + pushdecl (build_decl (TYPE_DECL, get_identifier ("short unsigned int"), + short_unsigned_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)); + + /* 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; + pushdecl (build_decl (TYPE_DECL, ridpointers[(int) RID_FLOAT], + float_type_node)); + layout_type (float_type_node); + + double_type_node = make_node (REAL_TYPE); + TYPE_PRECISION (double_type_node) = DOUBLE_TYPE_SIZE; + pushdecl (build_decl (TYPE_DECL, ridpointers[(int) RID_DOUBLE], + double_type_node)); + layout_type (double_type_node); + + long_double_type_node = make_node (REAL_TYPE); + TYPE_PRECISION (long_double_type_node) = LONG_DOUBLE_TYPE_SIZE; + pushdecl (build_decl (TYPE_DECL, get_identifier ("long double"), + long_double_type_node)); + layout_type (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, + ridpointers[(int) RID_VOID], void_type_node)); + layout_type (void_type_node); /* Uses integer_zero_node */ + + 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); + + /* make a type for arrays of 256 characters. + 256 is picked randomly because we have a type for integers from 0 to 255. + With luck nothing will ever really depend on the length of this + array type. */ + char_array_type_node + = build_array_type (char_type_node, unsigned_char_type_node); + /* Likewise for arrays of ints. */ + int_array_type_node + = build_array_type (integer_type_node, unsigned_char_type_node); + + default_function_type + = build_function_type (integer_type_node, NULL_TREE); + + ptr_type_node = build_pointer_type (void_type_node); + endlink = tree_cons (NULL_TREE, void_type_node, NULL_TREE); + + double_ftype_double + = build_function_type (double_type_node, + tree_cons (NULL_TREE, double_type_node, endlink)); + + double_ftype_double_double + = build_function_type (double_type_node, + tree_cons (NULL_TREE, double_type_node, + tree_cons (NULL_TREE, + double_type_node, endlink))); + + int_ftype_int + = build_function_type (integer_type_node, + tree_cons (NULL_TREE, integer_type_node, endlink)); + + long_ftype_long + = build_function_type (long_integer_type_node, + 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, + tree_cons (NULL_TREE, + integer_type_node, + endlink)))); + + int_ftype_ptr_ptr_int + = build_function_type (integer_type_node, + tree_cons (NULL_TREE, ptr_type_node, + tree_cons (NULL_TREE, ptr_type_node, + tree_cons (NULL_TREE, + integer_type_node, + 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, + tree_cons (NULL_TREE, + integer_type_node, + endlink)))); + + builtin_function ("__builtin_alloca", + build_function_type (ptr_type_node, + tree_cons (NULL_TREE, + integer_type_node, + endlink)), + BUILT_IN_ALLOCA); + + builtin_function ("__builtin_abs", int_ftype_int, BUILT_IN_ABS); + builtin_function ("__builtin_fabs", double_ftype_double, BUILT_IN_FABS); + builtin_function ("__builtin_labs", long_ftype_long, BUILT_IN_LABS); + builtin_function ("__builtin_ffs", int_ftype_int, BUILT_IN_FFS); + builtin_function ("__builtin_saveregs", default_function_type, + BUILT_IN_SAVEREGS); + builtin_function ("__builtin_classify_type", default_function_type, + BUILT_IN_CLASSIFY_TYPE); + builtin_function ("__builtin_next_arg", + build_function_type (ptr_type_node, endlink), + BUILT_IN_NEXT_ARG); +#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); + builtin_function ("__builtin_ldiv", default_ftype, BUILT_IN_LDIV); + builtin_function ("__builtin_ffloor", double_ftype_double, BUILT_IN_FFLOOR); + builtin_function ("__builtin_fceil", double_ftype_double, BUILT_IN_FCEIL); + builtin_function ("__builtin_fmod", double_ftype_double_double, BUILT_IN_FMOD); + builtin_function ("__builtin_frem", double_ftype_double_double, BUILT_IN_FREM); + builtin_function ("__builtin_memcpy", void_ftype_ptr_ptr_int, BUILT_IN_MEMCPY); + builtin_function ("__builtin_memcmp", int_ftype_ptr_ptr_int, BUILT_IN_MEMCMP); + builtin_function ("__builtin_memset", void_ftype_ptr_int_int, BUILT_IN_MEMSET); + builtin_function ("__builtin_fsqrt", double_ftype_double, BUILT_IN_FSQRT); + builtin_function ("__builtin_getexp", double_ftype_double, BUILT_IN_GETEXP); + builtin_function ("__builtin_getman", double_ftype_double, BUILT_IN_GETMAN); +#endif + + start_identifier_warnings (); +} + +/* 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. + See tree.h for its possible values. */ + +static void +builtin_function (name, type, function_code) + char *name; + tree type; + enum built_in_function function_code; +{ + tree decl = build_decl (FUNCTION_DECL, get_identifier (name), type); + TREE_EXTERNAL (decl) = 1; + TREE_PUBLIC (decl) = 1; + make_decl_rtl (decl, 0, 1); + pushdecl (decl); + DECL_SET_FUNCTION_CODE (decl, function_code); +} + +/* Called when a declaration is seen that contains no names to declare. + If its type is a reference to a structure, union or enum inherited + from a containing scope, shadow that tag name for the current scope + with a forward reference. + If its type defines a new named structure or union + or defines an enum, it is valid but we need not do anything here. + Otherwise, it is an error. */ + +void +shadow_tag (declspecs) + tree declspecs; +{ + int found_tag = 0; + int warned = 0; + register tree link; + + for (link = declspecs; link; link = TREE_CHAIN (link)) + { + register tree value = TREE_VALUE (link); + register enum tree_code code = TREE_CODE (value); + int ok = 0; + + if (code == RECORD_TYPE || code == UNION_TYPE || code == ENUMERAL_TYPE) + /* Used to test also that TYPE_SIZE (value) != 0. + That caused warning for `struct foo;' at top level in the file. */ + { + register tree name = lookup_tag_reverse (value); + register tree t = lookup_tag (code, name, current_binding_level, 1); + + if (t == 0) + { + t = make_node (code); + pushtag (name, t); + ok = 1; + } + else if (name != 0 || code == ENUMERAL_TYPE) + ok = 1; + } + + if (ok) + found_tag++; + else + { + if (!warned) + warning ("useless keyword or type name in declaration"); + warned = 1; + } + } + + if (!warned) + { + if (found_tag > 1) + warning ("multiple types in one declaration"); + if (found_tag == 0) + warning ("empty declaration"); + } +} + +/* Decode a "typename", such as "int **", returning a ..._TYPE node. */ + +tree +groktypename (typename) + tree typename; +{ + if (TREE_CODE (typename) != TREE_LIST) + return typename; + return grokdeclarator (TREE_VALUE (typename), + TREE_PURPOSE (typename), + TYPENAME, 0); +} + +/* Decode a declarator in an ordinary declaration or data definition. + This is called as soon as the type information and variable name + have been parsed, before parsing the initializer if any. + Here we create the ..._DECL node, fill in its type, + and put it on the list of decls for the current context. + The ..._DECL node is returned as the value. + + Exception: for arrays where the length is not specified, + the type is left null, to be filled in by `finish_decl'. + + Function definitions do not come here; they go to start_function + instead. However, external and forward declarations of functions + do go through here. Structure field declarations are done by + grokfield and not through here. */ + +/* Set this to zero to debug not using the temporary obstack + to parse initializers. */ +int debug_temp_inits = 1; + +tree +start_decl (declarator, declspecs, initialized) + tree declspecs, declarator; + int initialized; +{ + register tree decl = grokdeclarator (declarator, declspecs, + NORMAL, initialized); + register tree tem; + int init_written = initialized; + + if (initialized) + /* Is it valid for this decl to have an initializer at all? + If not, set INITIALIZED to zero, which will indirectly + tell `finish_decl' to ignore the initializer once it is parsed. */ + switch (TREE_CODE (decl)) + { + case TYPE_DECL: + /* typedef foo = bar means give foo the same type as bar. + We haven't parsed bar yet, so `finish_decl' will fix that up. + Any other case of an initialization in a TYPE_DECL is an error. */ + if (pedantic || list_length (declspecs) > 1) + { + error ("typedef `%s' is initialized", + IDENTIFIER_POINTER (DECL_NAME (decl))); + initialized = 0; + } + break; + + case FUNCTION_DECL: + error ("function `%s' is initialized like a variable", + IDENTIFIER_POINTER (DECL_NAME (decl))); + initialized = 0; + break; + + default: + /* Don't allow initializations for incomplete types + except for arrays which might be completed by the initialization. */ + if (TYPE_SIZE (TREE_TYPE (decl)) != 0) + ; /* A complete type is ok. */ + else if (TREE_CODE (TREE_TYPE (decl)) != ARRAY_TYPE) + { + error ("variable `%s' has initializer but incomplete type", + IDENTIFIER_POINTER (DECL_NAME (decl))); + initialized = 0; + } + else if (TYPE_SIZE (TREE_TYPE (TREE_TYPE (decl))) == 0) + { + error ("elements of array `%s' have incomplete type", + IDENTIFIER_POINTER (DECL_NAME (decl))); + initialized = 0; + } + } + + if (initialized) + { +#if 0 /* Seems redundant. */ + if (current_binding_level != global_binding_level + && TREE_EXTERNAL (decl) + && TREE_CODE (decl) != FUNCTION_DECL) + warning ("declaration of `%s' has `extern' and is initialized", + IDENTIFIER_POINTER (DECL_NAME (decl))); +#endif + TREE_EXTERNAL (decl) = 0; + if (current_binding_level == global_binding_level) + TREE_STATIC (decl) = 1; + + /* Tell `pushdecl' this is an initialized decl + even though we don't yet have the initializer expression. + Also tell `finish_decl' it may store the real initializer. */ + DECL_INITIAL (decl) = error_mark_node; + } + + /* Add this decl to the current binding level. + TEM may equal DECL or it may be a previous decl of the same name. */ + tem = pushdecl (decl); + + /* For a local variable, define the RTL now. */ + if (current_binding_level != global_binding_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, NULL_TREE); + else if (TREE_CODE (TREE_TYPE (tem)) == ARRAY_TYPE + && DECL_INITIAL (tem) != 0) + expand_decl (tem, NULL_TREE); + } + + if (init_written) + { + /* When parsing and digesting the initializer, + use temporary storage. Do this even if we will ignore the value. */ + if (current_binding_level == global_binding_level && debug_temp_inits) + temporary_allocation (); + } + + return tem; +} + +/* Finish processing of a declaration; + install its line number and 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. */ + +void +finish_decl (decl, init, asmspec_tree) + tree decl, init; + tree asmspec_tree; +{ + register tree type = TREE_TYPE (decl); + int was_incomplete = (DECL_SIZE (decl) == 0); + int temporary = allocation_temporary_p (); + char *asmspec = 0; + + if (asmspec_tree) + asmspec = TREE_STRING_POINTER (asmspec_tree); + + /* If `start_decl' didn't like having an initialization, ignore it now. */ + + if (init != 0 && DECL_INITIAL (decl) == 0) + init = 0; + + if (init) + { + if (TREE_CODE (decl) != TYPE_DECL) + store_init_value (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; + } + } + + /* For top-level declaration, the initial value was read in + the temporary obstack. MAXINDEX, rtl, etc. to be made below + must go in the permanent obstack; but don't discard the + temporary data yet. */ + + if (current_binding_level == global_binding_level && temporary) + end_temporary_allocation (); + + /* 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) + { +#if 0 + int do_default = ! ((!pedantic && TREE_STATIC (decl)) + || TREE_EXTERNAL (decl)); +#endif + int do_default + = (TREE_STATIC (decl) + /* Even if pedantic, an external linkage array + may have incomplete type at first. */ + ? pedantic && !TREE_PUBLIC (decl) + : !TREE_EXTERNAL (decl)); + int failure + = complete_array_type (type, DECL_INITIAL (decl), do_default); + + if (failure == 1) + error_with_decl (decl, "initializer fails to determine size of `%s'"); + + if (failure == 2) + { + if (do_default) + { + if (! TREE_PUBLIC (decl)) + error_with_decl (decl, "array size missing in `%s'"); + } + else if (!pedantic && TREE_STATIC (decl)) + TREE_EXTERNAL (decl) = 1; + } + + if (pedantic && TYPE_DOMAIN (type) != 0 + && tree_int_cst_lt (TYPE_MAX_VALUE (TYPE_DOMAIN (type)), + integer_zero_node)) + error_with_decl (decl, "zero-size array `%s'"); + + layout_decl (decl, 0); + } + + if (TREE_CODE (decl) == VAR_DECL) + { + if (TREE_STATIC (decl) && DECL_SIZE (decl) == 0) + { + /* A static variable with an incomplete type: + that is an error if it is initialized or `static'. + Otherwise, let it through, but if it is not `extern' + then it may cause an error message later. */ + if (! (TREE_PUBLIC (decl) && DECL_INITIAL (decl) == 0)) + error_with_decl (decl, "storage size of `%s' isn't known"); + } + else if (!TREE_EXTERNAL (decl) && DECL_SIZE (decl) == 0) + { + /* An automatic variable with an incomplete type: + that is an error. */ + error_with_decl (decl, "storage size of `%s' isn't known"); + TREE_TYPE (decl) = error_mark_node; + } + + if ((TREE_EXTERNAL (decl) || TREE_STATIC (decl)) + && DECL_SIZE (decl) != 0 && ! TREE_LITERAL (DECL_SIZE (decl))) + error_with_decl (decl, "storage size of `%s' isn't constant"); + } + + /* 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) + { + if (flag_traditional && allocation_temporary_p ()) + { + end_temporary_allocation (); + rest_of_decl_compilation (decl, asmspec, + current_binding_level == global_binding_level, + 0); + resume_temporary_allocation (); + } + else + rest_of_decl_compilation (decl, asmspec, + current_binding_level == global_binding_level, + 0); + if (current_binding_level != global_binding_level) + { + /* Recompute the RTL of a local array now + if it used to be an incomplete type. */ + if (was_incomplete + && ! TREE_STATIC (decl) && ! TREE_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, NULL_TREE); + } + /* Compute and store the initial value. */ + expand_decl_init (decl); + } + } + + if (TREE_CODE (decl) == TYPE_DECL) + rest_of_decl_compilation (decl, 0, + current_binding_level == global_binding_level, + 0); + + /* Resume permanent allocation, if not within a function. */ + if (temporary && current_binding_level == global_binding_level) + { + permanent_allocation (); + /* We need to remember that this array HAD an initialization, + but discard the actual nodes, since they are temporary anyway. */ + if (DECL_INITIAL (decl) != 0) + DECL_INITIAL (decl) = error_mark_node; + } + + /* 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 (); +} + +/* Given a parsed parameter declaration, + decode it into a PARM_DECL and push that on the current binding level. */ + +void +push_parm_decl (parm) + tree parm; +{ + register tree decl = grokdeclarator (TREE_VALUE (parm), TREE_PURPOSE (parm), + PARM, 0); + + /* Add this decl to the current binding level. */ + finish_decl (pushdecl (decl), NULL_TREE, NULL_TREE); +} + +/* Make TYPE a complete type based on INITIAL_VALUE. + Return 0 if successful, 1 if INITIAL_VALUE can't be decyphered, + 2 if there was no information (in which case assume 1 if DO_DEFAULT). */ + +int +complete_array_type (type, initial_value, do_default) + tree type; + tree initial_value; + int do_default; +{ + register tree maxindex = NULL_TREE; + int value = 0; + int temporary = (TREE_PERMANENT (type) && allocation_temporary_p ()); + + /* Don't put temporary nodes in permanent type. */ + if (temporary) + end_temporary_allocation (); + + if (initial_value) + { + /* Note MAXINDEX is really the maximum index, + one less than the size. */ + if (TREE_CODE (initial_value) == STRING_CST) + { + int eltsize = TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (TREE_TYPE (initial_value)))); + maxindex = build_int_2 (TREE_STRING_LENGTH (initial_value) / eltsize - 1, 0); + } + else if (TREE_CODE (initial_value) == CONSTRUCTOR) + { + register int nelts + = list_length (CONSTRUCTOR_ELTS (initial_value)); + maxindex = build_int_2 (nelts - 1, 0); + } + else + { + /* Make an error message unless that happened already. */ + if (initial_value != error_mark_node) + value = 1; + + /* Prevent further error messages. */ + maxindex = build_int_2 (1, 0); + } + } + + if (!maxindex) + { + if (do_default) + maxindex = build_int_2 (1, 0); + value = 2; + } + + if (maxindex) + { + TYPE_DOMAIN (type) = build_index_type (maxindex); + if (!TREE_TYPE (maxindex)) + TREE_TYPE (maxindex) = TYPE_DOMAIN (type); + } + + /* Lay out the type now that we can get the real answer. */ + + layout_type (type); + + if (temporary) + resume_temporary_allocation (); + + return value; +} + +/* Given declspecs and a declarator, + determine the name and type of the object declared + and construct a ..._DECL node for it. + (In one case we can return a ..._TYPE node instead. + For invalid input we sometimes return 0.) + + DECLSPECS is a chain of tree_list nodes whose value fields + are the storage classes and type specifiers. + + DECL_CONTEXT says which syntactic context this declaration is in: + NORMAL for most contexts. Make a VAR_DECL or FUNCTION_DECL or TYPE_DECL. + FUNCDEF for a function definition. Like NORMAL but a few different + error messages in each case. Return value may be zero meaning + this definition is too screwy to try to parse. + PARM for a parameter declaration (either within a function prototype + or before a function body). Make a PARM_DECL, or return void_type_node. + TYPENAME if for a typename (in a cast or sizeof). + Don't make a DECL node; just return the ..._TYPE node. + FIELD for a struct or union field; make a FIELD_DECL. + INITIALIZED is 1 if the decl has an initializer. + + In the TYPENAME case, DECLARATOR is really an absolute declarator. + It may also be so in the PARM case, for a prototype where the + argument type is specified but not the name. + + This function is where the complicated C meanings of `static' + and `extern' are intrepreted. */ + +static tree +grokdeclarator (declarator, declspecs, decl_context, initialized) + tree declspecs; + tree declarator; + enum decl_context decl_context; + int initialized; +{ + int specbits = 0; + tree spec; + tree type = NULL_TREE; + int longlong = 0; + int constp; + int volatilep; + int inlinep; + int explicit_int = 0; + int explicit_char = 0; + char *name; + tree typedef_type = 0; + int funcdef_flag = 0; + int resume_temporary = 0; + enum tree_code innermost_code = ERROR_MARK; + + if (decl_context == FUNCDEF) + funcdef_flag = 1, decl_context = NORMAL; + + if (flag_traditional && allocation_temporary_p ()) + { + resume_temporary = 1; + end_temporary_allocation (); + } + + /* Look inside a declarator for the name being declared + and get it as a string, for an error message. */ + { + register tree decl = declarator; + name = 0; + + while (decl) + switch (TREE_CODE (decl)) + { + case ARRAY_REF: + case INDIRECT_REF: + case CALL_EXPR: + innermost_code = TREE_CODE (decl); + decl = TREE_OPERAND (decl, 0); + break; + + case IDENTIFIER_NODE: + name = IDENTIFIER_POINTER (decl); + decl = 0; + break; + + default: + abort (); + } + if (name == 0) + name = "type name"; + } + + /* A function definition's declarator must have the form of + a function declarator. */ + + if (funcdef_flag && innermost_code != CALL_EXPR) + return 0; + + /* Anything declared one level down from the top level + must be one of the parameters of a function + (because the body is at least two levels down). */ + + if (decl_context == NORMAL + && current_binding_level->level_chain == global_binding_level) + decl_context = PARM; + + /* Look through the decl specs and record which ones appear. + Some typespecs are defined as built-in typenames. + Others, the ones that are modifiers of other types, + are represented by bits in SPECBITS: set the bits for + the modifiers that appear. Storage class keywords are also in SPECBITS. + + If there is a typedef name or a type, store the type in TYPE. + This includes builtin typedefs such as `int'. + + Set EXPLICIT_INT if the type is `int' or `char' and did not + come from a user typedef. + + Set LONGLONG if `long' is mentioned twice. */ + + for (spec = declspecs; spec; spec = TREE_CHAIN (spec)) + { + register int i; + register tree id = TREE_VALUE (spec); + + if (id == ridpointers[(int) RID_INT]) + explicit_int = 1; + if (id == ridpointers[(int) RID_CHAR]) + explicit_char = 1; + + if (TREE_CODE (id) == IDENTIFIER_NODE) + for (i = (int) RID_FIRST_MODIFIER; i < (int) RID_MAX; i++) + { + if (ridpointers[i] == id) + { + if (i == (int) RID_LONG && specbits & (1< 1) + warning ("duplicate `const'"); + if (volatilep > 1) + warning ("duplicate `volatile'"); + type = TYPE_MAIN_VARIANT (type); + + /* Warn if two storage classes are given. Default to `auto'. */ + + { + int nclasses = 0; + + if (specbits & 1 << (int) RID_AUTO) nclasses++; + if (specbits & 1 << (int) RID_STATIC) nclasses++; + if (specbits & 1 << (int) RID_EXTERN) nclasses++; + if (specbits & 1 << (int) RID_REGISTER) nclasses++; + if (specbits & 1 << (int) RID_TYPEDEF) nclasses++; + + /* Warn about storage classes that are invalid for certain + kinds of declarations (parameters, typenames, etc.). */ + + if (nclasses > 1) + error ("multiple storage classes in declaration of `%s'", name); + else if (funcdef_flag + && (specbits + & ((1 << (int) RID_REGISTER) + | (1 << (int) RID_AUTO) + | (1 << (int) RID_TYPEDEF)))) + { + if (specbits & 1 << (int) RID_AUTO) + error ("function definition declared `auto'"); + if (specbits & 1 << (int) RID_REGISTER) + error ("function definition declared `auto'"); + if (specbits & 1 << (int) RID_TYPEDEF) + error ("function definition declared `typedef'"); + specbits &= ~ ((1 << (int) RID_TYPEDEF) | (1 << (int) RID_REGISTER) + | (1 << (int) RID_AUTO)); + } + else if (decl_context != NORMAL && nclasses > 0) + { + if (decl_context == PARM && specbits & 1 << (int) RID_REGISTER) + ; + else + { + error ((decl_context == FIELD + ? "storage class specified for structure field `%s'" + : (decl_context == PARM + ? "storage class specified for parameter `%s'" + : "storage class specified for typename")), + name); + specbits &= ~ ((1 << (int) RID_TYPEDEF) | (1 << (int) RID_REGISTER) + | (1 << (int) RID_AUTO) | (1 << (int) RID_STATIC) + | (1 << (int) RID_EXTERN)); + } + } + else if (specbits & 1 << (int) RID_EXTERN && initialized + && ! funcdef_flag) + warning ("`%s' initialized and declared `extern'", name); + else if (current_binding_level == global_binding_level + && specbits & (1 << (int) RID_AUTO)) + error ("top-level declaration of `%s' specifies `auto'", name); + } + + /* 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) + { + if (type == error_mark_node) + { + declarator = TREE_OPERAND (declarator, 0); + continue; + } + + /* Each level of DECLARATOR is either an ARRAY_REF (for ...[..]), + an INDIRECT_REF (for *...), + a CALL_EXPR (for ...(...)), + an identifier (for the name being declared) + or a null pointer (for the place in an absolute declarator + where the name was omitted). + For the last two cases, we have just exited the loop. + + At this point, TYPE is the type of elements of an array, + or for a function to return, or for a pointer to point to. + After this sequence of ifs, TYPE is the type of the + array or function or pointer, and DECLARATOR has had its + outermost layer removed. */ + + if (TREE_CODE (declarator) == ARRAY_REF) + { + register tree itype = NULL_TREE; + register tree size = TREE_OPERAND (declarator, 1); + + declarator = TREE_OPERAND (declarator, 0); + + /* Check for some types that there cannot be arrays of. */ + + if (type == void_type_node) + { + error ("declaration of `%s' as array of voids", name); + type = error_mark_node; + } + + if (TREE_CODE (type) == FUNCTION_TYPE) + { + error ("declaration of `%s' as array of functions", name); + type = error_mark_node; + } + + if (size == error_mark_node) + type = error_mark_node; + + if (type == error_mark_node) + continue; + + /* If size was specified, set ITYPE to a range-type for that size. + Otherwise, ITYPE remains null. finish_decl may figure it out + from an initial value. */ + + if (size) + { + /* 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 (TREE_CODE (TREE_TYPE (size)) != INTEGER_TYPE + && TREE_CODE (TREE_TYPE (size)) != ENUMERAL_TYPE) + { + error ("size of array `%s' has non-integer type", name); + size = integer_one_node; + } + if (pedantic && integer_zerop (size)) + warning ("ANSI C forbids zero-size array `%s'", name); + if (TREE_CODE (size) == INTEGER_CST) + { + if (INT_CST_LT (size, integer_zero_node)) + { + error ("size of array `%s' is negative", name); + size = integer_one_node; + } + itype = build_index_type (build_int_2 (TREE_INT_CST_LOW (size) - 1, 0)); + } + else + { + if (pedantic) + warning ("ANSI C forbids variable-size array `%s'", name); + itype = build_binary_op (MINUS_EXPR, size, integer_one_node); + itype = build_index_type (itype); + } + } + + /* Complain about arrays of incomplete types, except in typedefs. */ + + if (TYPE_SIZE (type) == 0 + && !(specbits & (1 << (int) RID_TYPEDEF))) + warning ("array type has incomplete element type"); + + /* Build the array type itself. + Merge any constancy or volatility into the target type. */ + + if (constp || volatilep) + type = c_build_type_variant (type, constp, volatilep); + +#if 0 /* don't clear these; leave them set so that the array type + or the variable is itself const or volatile. */ + constp = 0; + volatilep = 0; +#endif + + type = build_array_type (type, itype); + } + else if (TREE_CODE (declarator) == CALL_EXPR) + { + tree arg_types; + + /* Declaring a function type. + Make sure we have a valid type for the function to return. */ + if (type == error_mark_node) + continue; + + if (pedantic && (constp || volatilep)) + warning ("function declared to return const or volatile result"); + + /* Warn about some types functions can't return. */ + + if (TREE_CODE (type) == FUNCTION_TYPE) + { + error ("`%s' declared as function returning a function", name); + type = integer_type_node; + } + if (TREE_CODE (type) == ARRAY_TYPE) + { + error ("`%s' declared as function returning an array", name); + type = integer_type_node; + } + + /* Traditionally, declaring return type float means double. */ + + if (flag_traditional && type == float_type_node) + type = double_type_node; + + /* Construct the function type and go to the next + inner layer of declarator. */ + + arg_types = grokparms (TREE_OPERAND (declarator, 1), + funcdef_flag + /* Say it's a definition + only for the CALL_EXPR + closest to the identifier. */ + && TREE_CODE (TREE_OPERAND (declarator, 0)) == IDENTIFIER_NODE); +#if 0 /* This seems to be false. We turn off temporary allocation + above in this function if -traditional. + And this code caused inconsistent results with prototypes: + callers would ignore them, and pass arguments wrong. */ + + /* Omit the arg types if -traditional, since the arg types + and the list links might not be permanent. */ + type = build_function_type (type, flag_traditional ? 0 : arg_types); +#endif + type = build_function_type (type, arg_types); + declarator = TREE_OPERAND (declarator, 0); + } + else if (TREE_CODE (declarator) == INDIRECT_REF) + { + /* Merge any constancy or volatility into the target type + for the pointer. */ + + if (constp || volatilep) + type = c_build_type_variant (type, constp, volatilep); + constp = 0; + volatilep = 0; + + type = build_pointer_type (type); + + /* Process a list of type modifier keywords + (such as const or volatile) that were given inside the `*'. */ + + if (TREE_TYPE (declarator)) + { + register tree typemodlist; + int erred = 0; + for (typemodlist = TREE_TYPE (declarator); typemodlist; + typemodlist = TREE_CHAIN (typemodlist)) + { + if (TREE_VALUE (typemodlist) == ridpointers[(int) RID_CONST]) + constp++; + else if (TREE_VALUE (typemodlist) == ridpointers[(int) RID_VOLATILE]) + volatilep++; + else if (!erred) + { + erred = 1; + error ("invalid type modifier within pointer declarator"); + } + } + if (constp > 1) + warning ("duplicate `const'"); + if (volatilep > 1) + warning ("duplicate `volatile'"); + } + + declarator = TREE_OPERAND (declarator, 0); + } + else + abort (); + +/* layout_type (type); */ + + /* @@ Should perhaps replace the following code by changes in + * @@ stor_layout.c. */ + if (TREE_CODE (type) == FUNCTION_DECL) + { + /* A function variable in C should be Pmode rather than EPmode + because it has just the address of a function, no static chain.*/ + TYPE_MODE (type) = Pmode; + } + } + + /* Now TYPE has the actual type. */ + + /* If this is declaring a typedef name, return a TYPE_DECL. */ + + if (specbits & (1 << (int) RID_TYPEDEF)) + { + /* Note that the grammar rejects storage classes + in typenames, fields or parameters */ + if (constp || volatilep) + type = c_build_type_variant (type, constp, volatilep); + if (resume_temporary) + resume_temporary_allocation (); + return build_decl (TYPE_DECL, declarator, type); + } + + /* Detect the case of an array type of unspecified size + which came, as such, direct from a typedef name. + We must copy the type, so that each identifier gets + a distinct type, so that each identifier's size can be + controlled separately by its own initializer. */ + + if (type != 0 && typedef_type != 0 + && TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (typedef_type) + && TREE_CODE (type) == ARRAY_TYPE && TYPE_DOMAIN (type) == 0) + type = build_array_type (TREE_TYPE (type), 0); + + /* If this is a type name (such as, in a cast or sizeof), + compute the type and return it now. */ + + if (decl_context == TYPENAME) + { + /* Note that the grammar rejects storage classes + in typenames, fields or parameters */ + if (constp || volatilep) + type = c_build_type_variant (type, constp, volatilep); + if (resume_temporary) + resume_temporary_allocation (); + return type; + } + + /* `void' at top level (not within pointer) + is allowed only in typedefs or type names. + We don't complain about parms either, but that is because + a better error message can be made later. */ + + if (type == void_type_node && decl_context != PARM) + { + error ("variable or field `%s' declared void", + IDENTIFIER_POINTER (declarator)); + type = integer_type_node; + } + + /* Now create the decl, which may be a VAR_DECL, a PARM_DECL + or a FUNCTION_DECL, depending on DECL_CONTEXT and TYPE. */ + + { + register tree decl; + + if (decl_context == PARM) + { + /* A parameter declared as an array of T is really a pointer to T. + One declared as a function is really a pointer to a function. */ + + if (TREE_CODE (type) == ARRAY_TYPE) + { + /* Transfer const-ness of array into that of type pointed to. */ + type = build_pointer_type + (c_build_type_variant (TREE_TYPE (type), constp, volatilep)); + volatilep = constp = 0; + } + else if (TREE_CODE (type) == FUNCTION_TYPE) + { + if (pedantic && (constp || volatilep)) + warning ("ANSI C forbids const or volatile function types"); + type = build_pointer_type (c_build_type_variant (type, constp, volatilep)); + volatilep = constp = 0; + } + + if (initialized) + error ("parameter `%s' is initialized", name); + + decl = build_decl (PARM_DECL, declarator, type); + + /* Compute the type actually passed in the parmlist, + for the case where there is no prototype. + (For example, shorts and chars are passed as ints.) + When there is a prototype, this is overridden later. */ + + DECL_ARG_TYPE (decl) = type; + if (type == float_type_node) + DECL_ARG_TYPE (decl) = double_type_node; + else if (TREE_CODE (type) == INTEGER_TYPE + /* ANSI C says short and char are promoted to int + or unsigned int, even if that is not wider. */ + && (TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node) + || type == short_integer_type_node + || type == short_unsigned_type_node)) + { + if (TYPE_PRECISION (type) == TYPE_PRECISION (integer_type_node) + && TREE_UNSIGNED (type)) + DECL_ARG_TYPE (decl) = unsigned_type_node; + else + DECL_ARG_TYPE (decl) = integer_type_node; + } + } + else if (decl_context == FIELD) + { + /* Structure field. It may not be a function. */ + + if (TREE_CODE (type) == FUNCTION_TYPE) + { + error ("field `%s' declared as a function", + IDENTIFIER_POINTER (declarator)); + type = build_pointer_type (type); + } + else if (TREE_CODE (type) != ERROR_MARK && TYPE_SIZE (type) == 0) + { + error ("field `%s' has incomplete type", + IDENTIFIER_POINTER (declarator)); + type = error_mark_node; + } + /* Move type qualifiers down to element of an array. */ + if (TREE_CODE (type) == ARRAY_TYPE && (constp || volatilep)) + { + type = c_build_type_variant (type, constp, volatilep); + constp = volatilep = 0; + } + /* Note that the grammar rejects storage classes + in typenames, fields or parameters */ + decl = build_decl (FIELD_DECL, declarator, type); + } + else if (TREE_CODE (type) == FUNCTION_TYPE) + { + if (specbits & ((1 << (int) RID_AUTO) | (1 << (int) RID_REGISTER))) + error ("invalid storage class for function `%s'", + IDENTIFIER_POINTER (declarator)); + /* Function declaration not at top level. + Storage classes other than `extern' are not allowed + and `extern' makes no difference. */ + if (current_binding_level != global_binding_level + && (specbits & ((1 << (int) RID_STATIC) | (1 << (int) RID_INLINE))) + && pedantic) + warning ("invalid storage class for function `%s'", + IDENTIFIER_POINTER (declarator)); + decl = build_decl (FUNCTION_DECL, declarator, type); + + TREE_EXTERNAL (decl) = 1; + /* Record presence of `static'. */ + TREE_PUBLIC (decl) = !(specbits & (1 << (int) RID_STATIC)); + /* 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 && TREE_VALUE (last) != void_type_node) + warning ("inline declaration ignored for function with `...'"); + else + /* Assume that otherwise the function can be inlined. */ + TREE_INLINE (decl) = 1; + + if (specbits & (1 << (int) RID_EXTERN)) + current_extern_inline = 1; + } + } + else + { + /* It's a variable. */ + + /* Move type qualifiers down to element of an array. */ + if (TREE_CODE (type) == ARRAY_TYPE && (constp || volatilep)) + { + type = c_build_type_variant (type, constp, volatilep); +#if 0 /* but a variable whose type is const should still have TREE_READONLY. */ + constp = volatilep = 0; +#endif + } + + decl = build_decl (VAR_DECL, declarator, type); + + if (inlinep) + warning_with_decl (decl, "variable `%s' declared `inline'"); + + /* An uninitialized decl with `extern' is a reference. */ + TREE_EXTERNAL (decl) + = !initialized && (specbits & (1 << (int) RID_EXTERN)); + /* At top level, either `static' or no s.c. makes a definition + (perhaps tentative), and absence of `static' makes it public. */ + if (current_binding_level == global_binding_level) + { + TREE_PUBLIC (decl) = !(specbits & (1 << (int) RID_STATIC)); + TREE_STATIC (decl) = ! TREE_EXTERNAL (decl); + } + /* Not at top level, only `static' makes a static definition. */ + else + { + TREE_STATIC (decl) = (specbits & (1 << (int) RID_STATIC)) != 0; + TREE_PUBLIC (decl) = TREE_EXTERNAL (decl); + /* `extern' with initialization is invalid if not at top level. */ + if ((specbits & (1 << (int) RID_EXTERN)) && initialized) + error ("`%s' has both `extern' and initializer", name); + } + } + + /* Record `register' declaration for warnings on & + and in case doing stupid register allocation. */ + + if (specbits & (1 << (int) RID_REGISTER)) + TREE_REGDECL (decl) = 1; + + /* Record constancy and volatility. */ + + if (constp) + TREE_READONLY (decl) = 1; + if (volatilep) + { + TREE_VOLATILE (decl) = 1; + TREE_THIS_VOLATILE (decl) = 1; + } + + if (resume_temporary) + resume_temporary_allocation (); + + return decl; + } +} + +/* Make a variant type in the proper way for C, propagating qualifiers + down to the element type of an array. */ + +tree +c_build_type_variant (type, constp, volatilep) + tree type; + int constp, volatilep; +{ + if (TREE_CODE (type) != ARRAY_TYPE) + return build_type_variant (type, constp, volatilep); + + return build_array_type (c_build_type_variant (TREE_TYPE (type), + constp, volatilep), + TYPE_DOMAIN (type)); +} + +/* Decode the parameter-list info for a function type or function definition. + The argument is the value returned by `get_parm_info' (or made in parse.y + if there is an identifier list instead of a parameter decl list). + These two functions are separate because when a function returns + or receives functions then each is called multiple times but the order + of calls is different. The last call to `grokparms' is always the one + that contains the formal parameter names of a function definition. + + Store in `last_function_parms' a chain of the decls of parms. + Also store in `last_function_parm_tags' a chain of the struct and union + tags declared among the parms. + + Return a list of arg types to use in the FUNCTION_TYPE for this function. + + FUNCDEF_FLAG is nonzero for a function definition, 0 for + a mere declaration. A nonempty identifier-list gets an error message + when FUNCDEF_FLAG is zero. */ + +static tree +grokparms (parms_info, funcdef_flag) + tree parms_info; + int funcdef_flag; +{ + tree first_parm = TREE_CHAIN (parms_info); + + last_function_parms = TREE_PURPOSE (parms_info); + last_function_parm_tags = TREE_VALUE (parms_info); + + if (warn_strict_prototypes && first_parm == 0 && !funcdef_flag) + warning ("function declaration isn't a prototype"); + + if (first_parm != 0 + && TREE_CODE (TREE_VALUE (first_parm)) == IDENTIFIER_NODE) + { + if (! funcdef_flag) + warning ("parameter names (without types) in function declaration"); + + last_function_parms = first_parm; + return 0; + } + else + { + tree parm; + tree typelt; + /* We no longer test FUNCDEF_FLAG. + If the arg types are incomplete in a declaration, + they must include undefined tags. + These tags can never be defined in the scope of the declaration, + so the types can never be completed, + and no call can be compiled successfully. */ +#if 0 + /* In a fcn definition, arg types must be complete. */ + if (funcdef_flag) +#endif + for (parm = last_function_parms, typelt = first_parm; + parm; + parm = TREE_CHAIN (parm)) + /* Skip over any enumeration constants declared here. */ + if (TREE_CODE (parm) == PARM_DECL) + { + /* Barf if the parameter itself has an incomplete type. */ + tree type = TREE_VALUE (typelt); + if (TYPE_SIZE (type) == 0) + { + if (funcdef_flag && DECL_NAME (parm) != 0) + error ("parameter `%s' has incomplete type", + IDENTIFIER_POINTER (DECL_NAME (parm))); + else + warning ("parameter has incomplete type"); + if (funcdef_flag) + { + TREE_VALUE (typelt) = error_mark_node; + TREE_TYPE (parm) = error_mark_node; + } + } +#if 0 /* This has been replaced by parm_tags_warning + which uses a more accurate criterion for what to warn about. */ + else + { + /* Now warn if is a pointer to an incomplete type. */ + while (TREE_CODE (type) == POINTER_TYPE + || TREE_CODE (type) == REFERENCE_TYPE) + type = TREE_TYPE (type); + type = TYPE_MAIN_VARIANT (type); + if (TYPE_SIZE (type) == 0) + { + if (DECL_NAME (parm) != 0) + warning ("parameter `%s' points to incomplete type", + IDENTIFIER_POINTER (DECL_NAME (parm))); + else + warning ("parameter points to incomplete type"); + } + } +#endif + typelt = TREE_CHAIN (typelt); + } + + return first_parm; + } +} + + +/* Return a tree_list node with info on a parameter list just parsed. + The TREE_PURPOSE is a chain of decls of those parms. + The TREE_VALUE is a list of structure, union and enum tags defined. + The TREE_CHAIN is a list of argument types to go in the FUNCTION_TYPE. + This tree_list node is later fed to `grokparms'. + + VOID_AT_END nonzero means append `void' to the end of the type-list. + Zero means the parmlist ended with an ellipsis so don't append `void'. */ + +tree +get_parm_info (void_at_end) + int void_at_end; +{ + register tree decl; + register tree types = 0; + int erred = 0; + tree tags = gettags (); + tree parms = nreverse (getdecls ()); + + /* Just `void' (and no ellipsis) is special. There are really no parms. */ + if (void_at_end && parms != 0 + && TREE_CHAIN (parms) == 0 + && TREE_TYPE (parms) == void_type_node + && DECL_NAME (parms) == 0) + { + parms = NULL_TREE; + storedecls (NULL_TREE); + return saveable_tree_cons (NULL_TREE, NULL_TREE, + saveable_tree_cons (NULL_TREE, void_type_node, NULL_TREE)); + } + + storedecls (parms); + + for (decl = parms; decl; decl = TREE_CHAIN (decl)) + /* There may also be declarations for enumerators if an enumeration + type is declared among the parms. Ignore them here. */ + if (TREE_CODE (decl) == PARM_DECL) + { + /* Since there is a prototype, + args are passed in their declared types. */ + tree type = TREE_TYPE (decl); + DECL_ARG_TYPE (decl) = type; +#ifdef PROMOTE_PROTOTYPES + if (TREE_CODE (type) == INTEGER_TYPE + && TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)) + DECL_ARG_TYPE (decl) = integer_type_node; +#endif + + types = saveable_tree_cons (NULL_TREE, TREE_TYPE (decl), types); + if (TREE_VALUE (types) == void_type_node && ! erred + && DECL_NAME (decl) == 0) + { + error ("`void' in parameter list must be the entire list"); + erred = 1; + } + } + + if (void_at_end) + return saveable_tree_cons (parms, tags, + nreverse (saveable_tree_cons (NULL_TREE, void_type_node, types))); + + return saveable_tree_cons (parms, tags, nreverse (types)); +} + +/* At end of parameter list, warn about any struct, union or enum tags + defined within. Do so because these types cannot ever become complete. */ + +void +parmlist_tags_warning () +{ + tree elt; + static int already; + + for (elt = current_binding_level->tags; elt; elt = TREE_CHAIN (elt)) + { + enum tree_code code = TREE_CODE (TREE_VALUE (elt)); + warning ("`%s %s' declared inside parameter list", + (code == RECORD_TYPE ? "struct" + : code == UNION_TYPE ? "union" + : "enum"), + IDENTIFIER_POINTER (TREE_PURPOSE (elt))); + if (! already) + { + warning ("its scope is only this definition or declaration,"); + warning ("which is probably not what you want."); + already = 1; + } + } +} + +/* Get the struct, enum or union (CODE says which) with tag NAME. + Define the tag as a forward-reference if it is not defined. */ + +tree +xref_tag (code, name) + enum tree_code code; + tree name; +{ + int temporary = allocation_temporary_p (); + + /* If a cross reference is requested, look up the type + already defined for this tag and return it. */ + + register tree ref = lookup_tag (code, name, current_binding_level, 0); + if (ref) return ref; + + if (current_binding_level == global_binding_level && temporary) + end_temporary_allocation (); + + /* If no such tag is yet defined, create a forward-reference node + and record it as the "definition". + When a real declaration of this type is found, + the forward-reference will be altered into a real type. */ + + ref = make_node (code); + if (code == ENUMERAL_TYPE) + { + /* (In ANSI, Enums can be referred to only if already defined.) */ + if (pedantic) + warning ("ANSI C forbids forward references to `enum' types"); + /* Give the type a default layout like unsigned int + to avoid crashing if it does not get defined. */ + TYPE_MODE (ref) = SImode; + TYPE_ALIGN (ref) = TYPE_ALIGN (unsigned_type_node); + TREE_UNSIGNED (ref) = 1; + TYPE_PRECISION (ref) = TYPE_PRECISION (unsigned_type_node); + TYPE_MIN_VALUE (ref) = TYPE_MIN_VALUE (unsigned_type_node); + TYPE_MAX_VALUE (ref) = TYPE_MAX_VALUE (unsigned_type_node); + } + + pushtag (name, ref); + + if (current_binding_level == global_binding_level && temporary) + resume_temporary_allocation (); + + return ref; +} + +/* Make sure that the tag NAME is defined *in the current binding level* + at least as a forward reference. + CODE says which kind of tag NAME ought to be. */ + +tree +start_struct (code, name) + enum tree_code code; + tree name; +{ + /* If there is already a tag defined at this binding level + (as a forward reference), just return it. */ + + register tree ref = 0; + + if (name != 0) + ref = lookup_tag (code, name, current_binding_level, 1); + if (ref && TREE_CODE (ref) == code) + { + if (TYPE_FIELDS (ref)) + error ((code == UNION_TYPE ? "redefinition of `union %s'" + : "redefinition of `struct %s'"), + IDENTIFIER_POINTER (name)); + + return ref; + } + + /* Otherwise create a forward-reference just so the tag is in scope. */ + + ref = make_node (code); + pushtag (name, ref); + return ref; +} + +/* Process the specs, declarator (NULL if omitted) and width (NULL if omitted) + of a structure component, returning a FIELD_DECL node. + WIDTH is non-NULL for bit fields only, and is an INTEGER_CST node. + + This is done during the parsing of the struct declaration. + The FIELD_DECL nodes are chained together and the lot of them + are ultimately passed to `build_struct' to make the RECORD_TYPE node. */ + +tree +grokfield (filename, line, declarator, declspecs, width) + char *filename; + int line; + tree declarator, declspecs, width; +{ + register tree value = grokdeclarator (declarator, declspecs, FIELD, 0); + + finish_decl (value, NULL, NULL); + DECL_INITIAL (value) = width; + + return value; +} + +/* Fill in the fields of a RECORD_TYPE or UNION_TYPE node, T. + FIELDLIST is a chain of FIELD_DECL nodes for the fields. */ + +tree +finish_struct (t, fieldlist) + register tree t, fieldlist; +{ + register tree x; + int old_momentary; + int round_up_size = 1; + + /* If this type was previously laid out as a forward reference, + make sure we lay it out again. */ + + TYPE_SIZE (t) = 0; + + if (in_parm_level_p ()) + warning ((TREE_CODE (t) == UNION_TYPE ? "union defined inside parms" + : "structure defined inside parms")); + + old_momentary = suspend_momentary (); + + if (fieldlist == 0 && pedantic) + warning ((TREE_CODE (t) == UNION_TYPE ? "union has no members" + : "structure has no members")); + + /* Install struct as DECL_CONTEXT of each field decl. + Also process specified field sizes. + Set DECL_SIZE_UNIT to the specified size, or 0 if none specified. + The specified size is found in the DECL_INITIAL. + Store 0 there, except for ": 0" fields (so we can find them + and delete them, below). */ + + for (x = fieldlist; x; x = TREE_CHAIN (x)) + { + DECL_CONTEXT (x) = t; + DECL_SIZE_UNIT (x) = 0; + + /* If any field is const, the structure type is pseudo-const. */ + if (TREE_READONLY (x)) + C_TYPE_FIELDS_READONLY (t) = 1; + else + { + /* A field that is pseudo-const makes the structure likewise. */ + tree t1 = TREE_TYPE (x); + while (TREE_CODE (t1) == ARRAY_TYPE) + t1 = TREE_TYPE (t1); + if ((TREE_CODE (t1) == RECORD_TYPE || TREE_CODE (t1) == UNION_TYPE) + && C_TYPE_FIELDS_READONLY (t1)) + C_TYPE_FIELDS_READONLY (t) = 1; + } + + /* Detect invalid bit-field size. */ + if (DECL_INITIAL (x) && TREE_CODE (DECL_INITIAL (x)) != INTEGER_CST) + { + error_with_decl (x, "bit-field `%s' width not an integer constant"); + DECL_INITIAL (x) = NULL; + } + + /* Detect invalid bit-field type. */ + if (DECL_INITIAL (x) + && TREE_CODE (TREE_TYPE (x)) != INTEGER_TYPE + && TREE_CODE (TREE_TYPE (x)) != ENUMERAL_TYPE) + { + error_with_decl (x, "bit-field `%s' has invalid type"); + DECL_INITIAL (x) = NULL; + } + if (DECL_INITIAL (x) && pedantic + && TREE_TYPE (x) != integer_type_node + && TREE_TYPE (x) != unsigned_type_node) + warning_with_decl (x, "bit-field `%s' type invalid in ANSI C"); + + /* Detect and ignore out of range field width. */ + if (DECL_INITIAL (x)) + { + register int width = TREE_INT_CST_LOW (DECL_INITIAL (x)); + + if (width < 0) + { + DECL_INITIAL (x) = NULL; + warning_with_decl (x, "negative width in bit-field `%s'"); + } + else if (width == 0 && DECL_NAME (x) != 0) + { + error_with_decl (x, "zero width for bit-field `%s'"); + DECL_INITIAL (x) = NULL; + } + else if (width > TYPE_PRECISION (TREE_TYPE (x))) + { + DECL_INITIAL (x) = NULL; + warning_with_decl (x, "width of `%s' exceeds its type"); + } + } + + /* Process valid field width. */ + if (DECL_INITIAL (x)) + { + register int width = TREE_INT_CST_LOW (DECL_INITIAL (x)); + + if (width == 0) + { + /* 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; + } + else + { + DECL_INITIAL (x) = NULL; + DECL_SIZE_UNIT (x) = width; + TREE_PACKED (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 + /* Non-bit-fields are aligned for their type. */ + DECL_ALIGN (x) = MAX (DECL_ALIGN (x), TYPE_ALIGN (TREE_TYPE (x))); + } + + /* Now DECL_INITIAL is null on all members except for zero-width bit-fields. + And they have already done their work. */ + + /* Delete all zero-width bit-fields from the front of the fieldlist */ + while (fieldlist + && DECL_INITIAL (fieldlist)) + fieldlist = TREE_CHAIN (fieldlist); + /* Delete all such members from the rest of the fieldlist */ + for (x = fieldlist; x;) + { + if (TREE_CHAIN (x) && DECL_INITIAL (TREE_CHAIN (x))) + TREE_CHAIN (x) = TREE_CHAIN (TREE_CHAIN (x)); + else x = TREE_CHAIN (x); + } + + /* Delete all duplicate fields from the fieldlist */ + for (x = fieldlist; x && TREE_CHAIN (x);) + /* Anonymous fields aren't duplicates. */ + if (DECL_NAME (TREE_CHAIN (x)) == 0) + x = TREE_CHAIN (x); + else + { + register tree y = fieldlist; + + while (1) + { + if (DECL_NAME (y) == DECL_NAME (TREE_CHAIN (x))) + break; + if (y == x) + break; + y = TREE_CHAIN (y); + } + if (DECL_NAME (y) == DECL_NAME (TREE_CHAIN (x))) + { + error_with_decl (TREE_CHAIN (x), "duplicate member `%s'"); + TREE_CHAIN (x) = TREE_CHAIN (TREE_CHAIN (x)); + } + else x = TREE_CHAIN (x); + } + + /* Now we have the final fieldlist. Record it, + then lay out the structure or union (including the fields). */ + + TYPE_FIELDS (t) = fieldlist; + + /* If there's a :0 field at the end, round the size to the + EMPTY_FIELD_BOUNDARY. */ + TYPE_ALIGN (t) = round_up_size; + + for (x = TYPE_MAIN_VARIANT (t); x; x = TYPE_NEXT_VARIANT (x)) + { + TYPE_FIELDS (x) = TYPE_FIELDS (t); + TYPE_ALIGN (x) = TYPE_ALIGN (t); + } + + layout_type (t); + + /* Promote each bit-field's type to int if it is narrower than that. */ + for (x = fieldlist; x; x = TREE_CHAIN (x)) + if (TREE_PACKED (x) + && TREE_CODE (TREE_TYPE (x)) == INTEGER_TYPE + && (TREE_INT_CST_LOW (DECL_SIZE (x)) * DECL_SIZE_UNIT (x) + < TYPE_PRECISION (integer_type_node))) + TREE_TYPE (x) = integer_type_node; + + /* If this structure or union completes the type of any previous + variable declaration, lay it out and output its rtl. */ + + if (current_binding_level->n_incomplete != 0) + { + tree decl; + for (decl = current_binding_level->names; decl; decl = TREE_CHAIN (decl)) + { + if (TREE_TYPE (decl) == t + && TREE_CODE (decl) != TYPE_DECL) + { + int toplevel = global_binding_level == current_binding_level; + layout_decl (decl, 0); + rest_of_decl_compilation (decl, 0, toplevel, 0); + if (! toplevel) + expand_decl (decl, NULL_TREE); + --current_binding_level->n_incomplete; + } + else if (TYPE_SIZE (TREE_TYPE (decl)) == 0 + && TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE) + { + tree element = TREE_TYPE (decl); + while (TREE_CODE (element) == ARRAY_TYPE) + element = TREE_TYPE (element); + if (element == t) + layout_array_type (TREE_TYPE (decl)); + } + } + } + + resume_momentary (old_momentary); + + return t; +} + +/* Lay out the type T, and its element type, and so on. */ + +static void +layout_array_type (t) + tree t; +{ + if (TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE) + layout_array_type (TREE_TYPE (t)); + layout_type (t); +} + +/* Begin compiling the definition of an enumeration type. + NAME is its name (or null if anonymous). + Returns the type object, as yet incomplete. + Also records info about it so that build_enumerator + may be used to declare the individual values as they are read. */ + +tree +start_enum (name) + tree name; +{ + register tree enumtype = 0; + + /* 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. */ + + if (name != 0) + enumtype = lookup_tag (ENUMERAL_TYPE, name, current_binding_level, 1); + + if (enumtype == 0 || TREE_CODE (enumtype) != ENUMERAL_TYPE) + { + enumtype = make_node (ENUMERAL_TYPE); + pushtag (name, enumtype); + } + + if (TYPE_VALUES (enumtype) != 0) + { + /* This enum is a named one that has been declared already. */ + error ("redeclaration of `enum %s'", IDENTIFIER_POINTER (name)); + + /* Completely replace its old definition. + The old enumerators remain defined, however. */ + TYPE_VALUES (enumtype) = 0; + } + + /* 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) = 0; + fixup_unsigned_type (enumtype); + + enum_next_value = integer_zero_node; + + return enumtype; +} + +/* After processing and defining all the values of an enumeration type, + install their decls in the enumeration type and finish it off. + ENUMTYPE is the type object and VALUES a list of name-value pairs. + Returns ENUMTYPE. */ + +tree +finish_enum (enumtype, values) + register tree enumtype, values; +{ + register tree pair; + tree maximum = 0, minimum = 0; + register long maxvalue = 0; + register long minvalue = 0; + register int i; + + if (in_parm_level_p ()) + warning ("enum defined inside parms"); + + TYPE_VALUES (enumtype) = values; + + /* Calculate the maximum and minimum values + of any enumerator in this type. */ + + for (pair = values; pair; pair = TREE_CHAIN (pair)) + { + tree value = TREE_VALUE (pair); + if (pair == values) + maximum = minimum = value; + else + { + if (tree_int_cst_lt (maximum, value)) + maximum = value; + if (tree_int_cst_lt (value, minimum)) + minimum = value; + } + } + + TYPE_MIN_VALUE (enumtype) = minimum; + TYPE_MAX_VALUE (enumtype) = maximum; + + /* An enum can have some negative values; then it is signed. */ + if (tree_int_cst_lt (minimum, integer_zero_node)) + TREE_UNSIGNED (enumtype) = 0; + + if (flag_short_enums) + { + /* Determine the precision this type needs, lay it out, and define it. */ + int maxvalue = TREE_INT_CST_LOW (maximum); + int minvalue = TREE_INT_CST_LOW (minimum); + int prec = floor_log2 (maxvalue) + 1; + + if (! tree_int_cst_lt (minimum, integer_zero_node)) + { + /* All values are nonnegatives. */ + if (prec == 0) + prec = 1; + + TYPE_PRECISION (enumtype) = prec; + } + else + { + int negprec = floor_log2 (-1 - minvalue) + 1; + + if (prec < negprec) + prec = negprec; + TYPE_PRECISION (enumtype) = prec + 1; + } + + /* Increase the size till it becomes the size of some mode. */ + + TYPE_PRECISION (enumtype) = round_size (TYPE_PRECISION (enumtype)); + + /* Cancel the laying out previously done for the enum type, + so that fixup_unsigned_type will do it over. */ + TYPE_SIZE (enumtype) = 0; + + layout_type (enumtype); + } + + return enumtype; +} + +/* Build and install a CONST_DECL for one value of the + current enumeration type (one that was begun with start_enum). + Return a tree-list containing the name and its value. + Assignment of sequential values by default is handled here. */ + +tree +build_enumerator (name, value) + tree name, value; +{ + register tree decl; + + /* Validate and default VALUE. */ + + /* Remove no-op casts from the value. */ + while (value != 0 && TREE_CODE (value) == NOP_EXPR) + value = TREE_OPERAND (value, 0); + + if (value != 0 && TREE_CODE (value) != INTEGER_CST) + { + error ("enumerator value for `%s' not integer constant", + IDENTIFIER_POINTER (name)); + value = 0; + } + + /* Default based on previous value. */ + if (value == 0) + value = enum_next_value; + + /* Might as well enforce the ANSI restriction, since + values outside this range don't work in version 1. */ + if (! int_fits_type_p (value, integer_type_node)) + { + error ("enumerator value outside range of `int'"); + value = integer_zero_node; + } + + /* Set basis for default for next value. */ + enum_next_value = build_binary_op_nodefault (PLUS_EXPR, value, + integer_one_node, PLUS_EXPR); + + /* Now create a declaration for the enum value name. */ + + decl = build_decl (CONST_DECL, name, integer_type_node); + DECL_INITIAL (decl) = value; + TREE_TYPE (value) = integer_type_node; + pushdecl (decl); + + return saveable_tree_cons (name, value, NULL); +} + +/* 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. */ + +int +start_function (declspecs, declarator) + tree declarator, declspecs; +{ + tree decl1, old_decl; + tree restype; + + 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; + + decl1 = grokdeclarator (declarator, declspecs, FUNCDEF, 1); + + /* If the declarator is not suitable for a function definition, + cause a syntax error. */ + if (decl1 == 0) + return 0; + + current_function_decl = decl1; + + announce_function (current_function_decl); + + if (TYPE_SIZE (TREE_TYPE (TREE_TYPE (decl1))) == 0) + { + error ("return-type is an incomplete type"); + /* Make it return void instead. */ + TREE_TYPE (decl1) + = build_function_type (void_type_node, + TYPE_ARG_TYPES (TREE_TYPE (decl1))); + } + + if (warn_about_return_type) + warning ("return-type defaults to `int'"); + + /* 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; + + /* Make the init_value nonzero so pushdecl knows this is not tentative. + error_mark_node is replaced below (in poplevel) with the LET_STMT. */ + DECL_INITIAL (current_function_decl) = error_mark_node; + + /* If this definition isn't a prototype and we had a prototype declaration + before, copy the arg type info from that prototype. */ + old_decl = lookup_name_current_level (DECL_NAME (current_function_decl)); + if (old_decl != 0 + && TREE_TYPE (TREE_TYPE (current_function_decl)) == TREE_TYPE (TREE_TYPE (old_decl)) + && TYPE_ARG_TYPES (TREE_TYPE (current_function_decl)) == 0) + TREE_TYPE (current_function_decl) = TREE_TYPE (old_decl); + + /* This is a definition, not a reference. + So normally clear TREE_EXTERNAL. + However, `extern inline' acts like a declaration + except for defining how to inline. So set TREE_EXTERNAL in that case. */ + TREE_EXTERNAL (current_function_decl) = current_extern_inline; + + /* This function exists in static storage. + (This does not mean `static' in the C sense!) */ + TREE_STATIC (current_function_decl) = 1; + + /* 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 (current_function_decl); + + pushlevel (0); + declare_parm_level (); + + make_function_rtl (current_function_decl); + + restype = TREE_TYPE (TREE_TYPE (current_function_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_TYPE (current_function_decl) = restype; + DECL_RESULT (current_function_decl) + = build_decl (RESULT_DECL, value_identifier, restype); + + /* Allocate further tree nodes temporarily during compilation + of this function only. */ + temporary_allocation (); + + /* 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_NAME (current_function_decl))) + TREE_ADDRESSABLE (current_function_decl) = 1; + + return 1; +} + +/* Store the parameter declarations into the current function declaration. + This is called after parsing the parameter declarations, before + digesting the body of the function. */ + +void +store_parm_decls () +{ + register tree fndecl = current_function_decl; + register tree parm; + + /* This is either a chain of PARM_DECLs (if a prototype was used) + or a list of IDENTIFIER_NODEs (for an old-fashioned C definition). */ + tree specparms = current_function_parms; + + /* This is a list of types declared among parms in a prototype. */ + tree parmtags = current_function_parm_tags; + + /* This is a chain of PARM_DECLs from old-style parm declarations. */ + register tree parmdecls = getdecls (); + + /* This is a chain of any other decls that came in among the parm + declarations. If a parm is declared with enum {foo, bar} x; + then CONST_DECLs for foo and bar are put here. */ + tree nonparms = 0; + + if (specparms != 0 && TREE_CODE (specparms) != TREE_LIST) + { + /* This case is when the function was defined with an ANSI prototype. + The parms already have decls, so we need not do anything here + except record them as in effect + and complain if any redundant old-style parm decls were written. */ + + register tree next; + tree others = 0; + + if (parmdecls != 0) + error_with_decl (fndecl, + "parm types given both in parmlist and separately"); + + specparms = nreverse (specparms); + for (parm = specparms; parm; parm = next) + { + next = TREE_CHAIN (parm); + if (DECL_NAME (parm) == 0) + error_with_decl (parm, "parameter name omitted"); + else if (TREE_TYPE (parm) == void_type_node) + error_with_decl (parm, "parameter `%s' declared void"); + else if (TREE_CODE (parm) == PARM_DECL) + pushdecl (parm); + else + { + /* If we find an enum constant, put it aside for the moment. */ + TREE_CHAIN (parm) = 0; + others = chainon (others, parm); + } + } + + /* Get the decls in their original chain order + and record in the function. */ + DECL_ARGUMENTS (fndecl) = getdecls (); + + /* Now pushdecl the enum constants. */ + for (parm = others; parm; parm = next) + { + next = TREE_CHAIN (parm); + if (DECL_NAME (parm) == 0) + ; + else if (TREE_TYPE (parm) == void_type_node) + ; + else if (TREE_CODE (parm) != PARM_DECL) + pushdecl (parm); + } + + storetags (chainon (parmtags, gettags ())); + } + else + { + /* SPECPARMS is an identifier list--a chain of TREE_LIST nodes + each with a parm name as the TREE_VALUE. + + PARMDECLS is a list of declarations for parameters. + Warning! It can also contain CONST_DECLs which are not parameters + but are names of enumerators of any enum types + declared among the parameters. + + First match each formal parameter name with its declaration. + Associate decls with the names and store the decls + into the TREE_PURPOSE slots. */ + + for (parm = specparms; parm; parm = TREE_CHAIN (parm)) + { + register tree tail, found = NULL; + + if (TREE_VALUE (parm) == 0) + { + error_with_decl (fndecl, "parameter name missing from parameter list"); + TREE_PURPOSE (parm) = 0; + continue; + } + + /* See if any of the parmdecls specifies this parm by name. + Ignore any enumerator decls. */ + for (tail = parmdecls; tail; tail = TREE_CHAIN (tail)) + if (DECL_NAME (tail) == TREE_VALUE (parm) + && TREE_CODE (tail) == PARM_DECL) + { + found = tail; + break; + } + + /* If declaration already marked, we have a duplicate name. + Complain, and don't use this decl twice. */ + if (found && DECL_CONTEXT (found) != 0) + { + error_with_decl (found, "multiple parameters named `%s'"); + found = 0; + } + + /* If the declaration says "void", complain and ignore it. */ + if (found && TREE_TYPE (found) == void_type_node) + { + error_with_decl (found, "parameter `%s' declared void"); + TREE_TYPE (found) = integer_type_node; + DECL_ARG_TYPE (found) = integer_type_node; + layout_decl (found, 0); + } + + /* If no declaration found, default to int. */ + if (!found) + { + found = build_decl (PARM_DECL, TREE_VALUE (parm), + integer_type_node); + DECL_ARG_TYPE (found) = TREE_TYPE (found); + DECL_SOURCE_LINE (found) = DECL_SOURCE_LINE (fndecl); + DECL_SOURCE_FILE (found) = DECL_SOURCE_FILE (fndecl); + if (extra_warnings) + warning_with_decl (found, "type of `%s' defaults to `int'"); + pushdecl (found); + } + + TREE_PURPOSE (parm) = found; + + /* Mark this decl as "already found" -- see test, above. + It is safe to clobber DECL_CONTEXT temporarily + because the final values are not stored until + the `poplevel' in `finish_function'. */ + DECL_CONTEXT (found) = error_mark_node; + } + + /* Complain about declarations not matched with any names. + Put any enumerator constants onto the list NONPARMS. */ + + nonparms = 0; + for (parm = parmdecls; parm; ) + { + tree next = TREE_CHAIN (parm); + TREE_CHAIN (parm) = 0; + + /* Complain about args with incomplete types. */ + if (TYPE_SIZE (TREE_TYPE (parm)) == 0) + { + error_with_decl (parm, "parameter `%s' has incomplete type"); + TREE_TYPE (parm) = error_mark_node; + } + + if (TREE_CODE (parm) != PARM_DECL) + nonparms = chainon (nonparms, parm); + + else if (DECL_CONTEXT (parm) == 0) + { + error_with_decl (parm, + "declaration for parameter `%s' but no such parameter"); + /* Pretend the parameter was not missing. + This gets us to a standard state and minimizes + further error messages. */ + specparms + = chainon (specparms, + tree_cons (parm, NULL_TREE, NULL_TREE)); + } + + parm = next; + } + + /* Chain the declarations together in the order of the list of names. */ + /* Store that chain in the function decl, replacing the list of names. */ + parm = specparms; + DECL_ARGUMENTS (fndecl) = 0; + { + register tree last; + for (last = 0; parm; parm = TREE_CHAIN (parm)) + if (TREE_PURPOSE (parm)) + { + if (last == 0) + DECL_ARGUMENTS (fndecl) = TREE_PURPOSE (parm); + else + TREE_CHAIN (last) = TREE_PURPOSE (parm); + last = TREE_PURPOSE (parm); + TREE_CHAIN (last) = 0; + DECL_CONTEXT (last) = 0; + } + } + + /* If there was a previous prototype, + set the DECL_ARG_TYPE of each argument according to + the type previously specified, and report any mismatches. */ + + if (TYPE_ARG_TYPES (TREE_TYPE (fndecl))) + { + register tree type; + for (parm = DECL_ARGUMENTS (fndecl), + type = TYPE_ARG_TYPES (TREE_TYPE (fndecl)); + parm || (type && TREE_VALUE (type) != void_type_node); + parm = TREE_CHAIN (parm), type = TREE_CHAIN (type)) + { + if (parm == 0 || type == 0 + || TREE_VALUE (type) == void_type_node) + { + error ("number of arguments doesn't match prototype"); + break; + } + /* Type for passing arg must be consistent + with that declared for the arg. */ + if (! comptypes (DECL_ARG_TYPE (parm), TREE_VALUE (type)) + /* If -traditional, allow `unsigned int' instead of `int' + in the prototype. */ + && (! (flag_traditional + && DECL_ARG_TYPE (parm) == integer_type_node + && TREE_VALUE (type) == unsigned_type_node))) + { + error ("argument `%s' doesn't match function prototype", + IDENTIFIER_POINTER (DECL_NAME (parm))); + if (DECL_ARG_TYPE (parm) == integer_type_node + && TREE_VALUE (type) == TREE_TYPE (parm)) + { + error ("a formal parameter type that promotes to `int'"); + error ("can match only `int' in the prototype"); + } + if (DECL_ARG_TYPE (parm) == double_type_node + && TREE_VALUE (type) == TREE_TYPE (parm)) + { + error ("a formal parameter type that promotes to `double'"); + error ("can match only `double' in the prototype"); + } + } + } + } + + /* Now store the final chain of decls for the arguments + as the decl-chain of the current lexical scope. + Put the enumerators in as well, at the front so that + DECL_ARGUMENTS is not modified. */ + + storedecls (chainon (nonparms, DECL_ARGUMENTS (fndecl))); + } + + /* Make sure the binding level for the top of the function body + gets a LET_STMT if there are any in the function. + Otherwise, the dbx output is wrong. */ + + keep_next_if_subblocks = 1; + + /* 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); +} + +/* 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. + LINENO is the current line number. */ + +void +finish_function (lineno) + int lineno; +{ + register tree fndecl = current_function_decl; + +/* 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); + + /* 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)); + + /* Generate rtl for function exit. */ + expand_function_end (input_filename, lineno); + + /* So we can tell if jump_optimize sets it to 1. */ + current_function_returns_null = 0; + + /* Run the optimizers and output the assembler code for this function. */ + rest_of_compilation (fndecl); + + if (TREE_THIS_VOLATILE (fndecl) && current_function_returns_null) + warning ("`volatile' function does return"); + else if (warn_return_type && current_function_returns_null + && TREE_TYPE (TREE_TYPE (fndecl)) != void_type_node) + /* If this function returns non-void and control can drop through, + complain. */ + warning ("control reaches end of non-void function"); + /* 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"); + + /* Free all the tree nodes making up this function. */ + /* Switch back to allocating nodes permanently + until we start another function. */ + permanent_allocation (); + + if (DECL_SAVED_INSNS (fndecl) == 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 (fndecl) = error_mark_node; + DECL_ARGUMENTS (fndecl) = 0; + } + + /* Let the error reporting routines know that we're outside a function. */ + current_function_decl = NULL; +} diff --git a/gcc-1.40/c-parse.gperf b/gcc-1.40/c-parse.gperf new file mode 100644 index 0000000..feef59b --- /dev/null +++ b/gcc-1.40/c-parse.gperf @@ -0,0 +1,56 @@ +%{ +/* Command-line: gperf -p -j1 -i 1 -g -o -t -N is_reserved_word -k1,3,$ c-parse.gperf */ +%} +struct resword { char *name; short token; enum rid rid; }; +%% +__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 +__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/gcc-1.40/c-parse.h b/gcc-1.40/c-parse.h new file mode 100644 index 0000000..697442e --- /dev/null +++ b/gcc-1.40/c-parse.h @@ -0,0 +1,49 @@ +/* Define constants for communication with parse.y. + Copyright (C) 1987 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 1, 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. */ + + + +enum rid +{ + RID_UNUSED, + RID_INT, + RID_CHAR, + RID_FLOAT, + RID_DOUBLE, + RID_VOID, + RID_UNUSED1, + + RID_UNSIGNED, + RID_SHORT, + RID_LONG, + RID_AUTO, + RID_STATIC, + RID_EXTERN, + RID_REGISTER, + RID_TYPEDEF, + RID_SIGNED, + RID_CONST, + RID_VOLATILE, + RID_INLINE, + RID_NOALIAS, + + RID_MAX +}; + +#define RID_FIRST_MODIFIER RID_UNSIGNED diff --git a/gcc-1.40/c-parse.output b/gcc-1.40/c-parse.output new file mode 100644 index 0000000..e423a41 --- /dev/null +++ b/gcc-1.40/c-parse.output @@ -0,0 +1,8092 @@ +Conflict in state 172 between rule 160 and token '(' resolved as shift. +Conflict in state 172 between rule 160 and token '[' resolved as shift. +Conflict in state 220 between rule 71 and token ASSIGN resolved as shift. +Conflict in state 220 between rule 71 and token '=' resolved as shift. +Conflict in state 220 between rule 71 and token '?' resolved as shift. +Conflict in state 220 between rule 71 and token OROR resolved as shift. +Conflict in state 220 between rule 71 and token ANDAND resolved as shift. +Conflict in state 220 between rule 71 and token '|' resolved as shift. +Conflict in state 220 between rule 71 and token '^' resolved as shift. +Conflict in state 220 between rule 71 and token '&' resolved as shift. +Conflict in state 220 between rule 71 and token EQCOMPARE resolved as shift. +Conflict in state 220 between rule 71 and token ARITHCOMPARE resolved as shift. +Conflict in state 220 between rule 71 and token LSHIFT resolved as shift. +Conflict in state 220 between rule 71 and token RSHIFT resolved as shift. +Conflict in state 220 between rule 71 and token '+' resolved as shift. +Conflict in state 220 between rule 71 and token '-' resolved as shift. +Conflict in state 220 between rule 71 and token '*' resolved as shift. +Conflict in state 220 between rule 71 and token '/' resolved as shift. +Conflict in state 220 between rule 71 and token '%' resolved as shift. +Conflict in state 221 between rule 70 and token ASSIGN resolved as shift. +Conflict in state 221 between rule 70 and token '=' resolved as shift. +Conflict in state 221 between rule 70 and token '?' resolved as shift. +Conflict in state 221 between rule 70 and token OROR resolved as shift. +Conflict in state 221 between rule 70 and token ANDAND resolved as shift. +Conflict in state 221 between rule 70 and token '|' resolved as shift. +Conflict in state 221 between rule 70 and token '^' resolved as shift. +Conflict in state 221 between rule 70 and token '&' resolved as shift. +Conflict in state 221 between rule 70 and token EQCOMPARE resolved as shift. +Conflict in state 221 between rule 70 and token ARITHCOMPARE resolved as shift. +Conflict in state 221 between rule 70 and token LSHIFT resolved as shift. +Conflict in state 221 between rule 70 and token RSHIFT resolved as shift. +Conflict in state 221 between rule 70 and token '+' resolved as shift. +Conflict in state 221 between rule 70 and token '-' resolved as shift. +Conflict in state 221 between rule 70 and token '*' resolved as shift. +Conflict in state 221 between rule 70 and token '/' resolved as shift. +Conflict in state 221 between rule 70 and token '%' resolved as shift. +Conflict in state 224 between rule 68 and token ASSIGN resolved as reduce. +Conflict in state 224 between rule 68 and token '=' resolved as reduce. +Conflict in state 224 between rule 68 and token '?' resolved as reduce. +Conflict in state 224 between rule 68 and token OROR resolved as reduce. +Conflict in state 224 between rule 68 and token ANDAND resolved as shift. +Conflict in state 224 between rule 68 and token '|' resolved as shift. +Conflict in state 224 between rule 68 and token '^' resolved as shift. +Conflict in state 224 between rule 68 and token '&' resolved as shift. +Conflict in state 224 between rule 68 and token EQCOMPARE resolved as shift. +Conflict in state 224 between rule 68 and token ARITHCOMPARE resolved as shift. +Conflict in state 224 between rule 68 and token LSHIFT resolved as shift. +Conflict in state 224 between rule 68 and token RSHIFT resolved as shift. +Conflict in state 224 between rule 68 and token '+' resolved as shift. +Conflict in state 224 between rule 68 and token '-' resolved as shift. +Conflict in state 224 between rule 68 and token '*' resolved as shift. +Conflict in state 224 between rule 68 and token '/' resolved as shift. +Conflict in state 224 between rule 68 and token '%' resolved as shift. +Conflict in state 225 between rule 67 and token ASSIGN resolved as reduce. +Conflict in state 225 between rule 67 and token '=' resolved as reduce. +Conflict in state 225 between rule 67 and token '?' resolved as reduce. +Conflict in state 225 between rule 67 and token OROR resolved as reduce. +Conflict in state 225 between rule 67 and token ANDAND resolved as reduce. +Conflict in state 225 between rule 67 and token '|' resolved as shift. +Conflict in state 225 between rule 67 and token '^' resolved as shift. +Conflict in state 225 between rule 67 and token '&' resolved as shift. +Conflict in state 225 between rule 67 and token EQCOMPARE resolved as shift. +Conflict in state 225 between rule 67 and token ARITHCOMPARE resolved as shift. +Conflict in state 225 between rule 67 and token LSHIFT resolved as shift. +Conflict in state 225 between rule 67 and token RSHIFT resolved as shift. +Conflict in state 225 between rule 67 and token '+' resolved as shift. +Conflict in state 225 between rule 67 and token '-' resolved as shift. +Conflict in state 225 between rule 67 and token '*' resolved as shift. +Conflict in state 225 between rule 67 and token '/' resolved as shift. +Conflict in state 225 between rule 67 and token '%' resolved as shift. +Conflict in state 226 between rule 65 and token ASSIGN resolved as reduce. +Conflict in state 226 between rule 65 and token '=' resolved as reduce. +Conflict in state 226 between rule 65 and token '?' resolved as reduce. +Conflict in state 226 between rule 65 and token OROR resolved as reduce. +Conflict in state 226 between rule 65 and token ANDAND resolved as reduce. +Conflict in state 226 between rule 65 and token '|' resolved as reduce. +Conflict in state 226 between rule 65 and token '^' resolved as shift. +Conflict in state 226 between rule 65 and token '&' resolved as shift. +Conflict in state 226 between rule 65 and token EQCOMPARE resolved as shift. +Conflict in state 226 between rule 65 and token ARITHCOMPARE resolved as shift. +Conflict in state 226 between rule 65 and token LSHIFT resolved as shift. +Conflict in state 226 between rule 65 and token RSHIFT resolved as shift. +Conflict in state 226 between rule 65 and token '+' resolved as shift. +Conflict in state 226 between rule 65 and token '-' resolved as shift. +Conflict in state 226 between rule 65 and token '*' resolved as shift. +Conflict in state 226 between rule 65 and token '/' resolved as shift. +Conflict in state 226 between rule 65 and token '%' resolved as shift. +Conflict in state 227 between rule 66 and token ASSIGN resolved as reduce. +Conflict in state 227 between rule 66 and token '=' resolved as reduce. +Conflict in state 227 between rule 66 and token '?' resolved as reduce. +Conflict in state 227 between rule 66 and token OROR resolved as reduce. +Conflict in state 227 between rule 66 and token ANDAND resolved as reduce. +Conflict in state 227 between rule 66 and token '|' resolved as reduce. +Conflict in state 227 between rule 66 and token '^' resolved as reduce. +Conflict in state 227 between rule 66 and token '&' resolved as shift. +Conflict in state 227 between rule 66 and token EQCOMPARE resolved as shift. +Conflict in state 227 between rule 66 and token ARITHCOMPARE resolved as shift. +Conflict in state 227 between rule 66 and token LSHIFT resolved as shift. +Conflict in state 227 between rule 66 and token RSHIFT resolved as shift. +Conflict in state 227 between rule 66 and token '+' resolved as shift. +Conflict in state 227 between rule 66 and token '-' resolved as shift. +Conflict in state 227 between rule 66 and token '*' resolved as shift. +Conflict in state 227 between rule 66 and token '/' resolved as shift. +Conflict in state 227 between rule 66 and token '%' resolved as shift. +Conflict in state 228 between rule 64 and token ASSIGN resolved as reduce. +Conflict in state 228 between rule 64 and token '=' resolved as reduce. +Conflict in state 228 between rule 64 and token '?' resolved as reduce. +Conflict in state 228 between rule 64 and token OROR resolved as reduce. +Conflict in state 228 between rule 64 and token ANDAND resolved as reduce. +Conflict in state 228 between rule 64 and token '|' resolved as reduce. +Conflict in state 228 between rule 64 and token '^' resolved as reduce. +Conflict in state 228 between rule 64 and token '&' resolved as reduce. +Conflict in state 228 between rule 64 and token EQCOMPARE resolved as shift. +Conflict in state 228 between rule 64 and token ARITHCOMPARE resolved as shift. +Conflict in state 228 between rule 64 and token LSHIFT resolved as shift. +Conflict in state 228 between rule 64 and token RSHIFT resolved as shift. +Conflict in state 228 between rule 64 and token '+' resolved as shift. +Conflict in state 228 between rule 64 and token '-' resolved as shift. +Conflict in state 228 between rule 64 and token '*' resolved as shift. +Conflict in state 228 between rule 64 and token '/' resolved as shift. +Conflict in state 228 between rule 64 and token '%' resolved as shift. +Conflict in state 229 between rule 63 and token ASSIGN resolved as reduce. +Conflict in state 229 between rule 63 and token '=' resolved as reduce. +Conflict in state 229 between rule 63 and token '?' resolved as reduce. +Conflict in state 229 between rule 63 and token OROR resolved as reduce. +Conflict in state 229 between rule 63 and token ANDAND resolved as reduce. +Conflict in state 229 between rule 63 and token '|' resolved as reduce. +Conflict in state 229 between rule 63 and token '^' resolved as reduce. +Conflict in state 229 between rule 63 and token '&' resolved as reduce. +Conflict in state 229 between rule 63 and token EQCOMPARE resolved as reduce. +Conflict in state 229 between rule 63 and token ARITHCOMPARE resolved as shift. +Conflict in state 229 between rule 63 and token LSHIFT resolved as shift. +Conflict in state 229 between rule 63 and token RSHIFT resolved as shift. +Conflict in state 229 between rule 63 and token '+' resolved as shift. +Conflict in state 229 between rule 63 and token '-' resolved as shift. +Conflict in state 229 between rule 63 and token '*' resolved as shift. +Conflict in state 229 between rule 63 and token '/' resolved as shift. +Conflict in state 229 between rule 63 and token '%' resolved as shift. +Conflict in state 230 between rule 62 and token ASSIGN resolved as reduce. +Conflict in state 230 between rule 62 and token '=' resolved as reduce. +Conflict in state 230 between rule 62 and token '?' resolved as reduce. +Conflict in state 230 between rule 62 and token OROR resolved as reduce. +Conflict in state 230 between rule 62 and token ANDAND resolved as reduce. +Conflict in state 230 between rule 62 and token '|' resolved as reduce. +Conflict in state 230 between rule 62 and token '^' resolved as reduce. +Conflict in state 230 between rule 62 and token '&' resolved as reduce. +Conflict in state 230 between rule 62 and token EQCOMPARE resolved as reduce. +Conflict in state 230 between rule 62 and token ARITHCOMPARE resolved as reduce. +Conflict in state 230 between rule 62 and token LSHIFT resolved as shift. +Conflict in state 230 between rule 62 and token RSHIFT resolved as shift. +Conflict in state 230 between rule 62 and token '+' resolved as shift. +Conflict in state 230 between rule 62 and token '-' resolved as shift. +Conflict in state 230 between rule 62 and token '*' resolved as shift. +Conflict in state 230 between rule 62 and token '/' resolved as shift. +Conflict in state 230 between rule 62 and token '%' resolved as shift. +Conflict in state 231 between rule 60 and token ASSIGN resolved as reduce. +Conflict in state 231 between rule 60 and token '=' resolved as reduce. +Conflict in state 231 between rule 60 and token '?' resolved as reduce. +Conflict in state 231 between rule 60 and token OROR resolved as reduce. +Conflict in state 231 between rule 60 and token ANDAND resolved as reduce. +Conflict in state 231 between rule 60 and token '|' resolved as reduce. +Conflict in state 231 between rule 60 and token '^' resolved as reduce. +Conflict in state 231 between rule 60 and token '&' resolved as reduce. +Conflict in state 231 between rule 60 and token EQCOMPARE resolved as reduce. +Conflict in state 231 between rule 60 and token ARITHCOMPARE resolved as reduce. +Conflict in state 231 between rule 60 and token LSHIFT resolved as reduce. +Conflict in state 231 between rule 60 and token RSHIFT resolved as reduce. +Conflict in state 231 between rule 60 and token '+' resolved as shift. +Conflict in state 231 between rule 60 and token '-' resolved as shift. +Conflict in state 231 between rule 60 and token '*' resolved as shift. +Conflict in state 231 between rule 60 and token '/' resolved as shift. +Conflict in state 231 between rule 60 and token '%' resolved as shift. +Conflict in state 232 between rule 61 and token ASSIGN resolved as reduce. +Conflict in state 232 between rule 61 and token '=' resolved as reduce. +Conflict in state 232 between rule 61 and token '?' resolved as reduce. +Conflict in state 232 between rule 61 and token OROR resolved as reduce. +Conflict in state 232 between rule 61 and token ANDAND resolved as reduce. +Conflict in state 232 between rule 61 and token '|' resolved as reduce. +Conflict in state 232 between rule 61 and token '^' resolved as reduce. +Conflict in state 232 between rule 61 and token '&' resolved as reduce. +Conflict in state 232 between rule 61 and token EQCOMPARE resolved as reduce. +Conflict in state 232 between rule 61 and token ARITHCOMPARE resolved as reduce. +Conflict in state 232 between rule 61 and token LSHIFT resolved as reduce. +Conflict in state 232 between rule 61 and token RSHIFT resolved as reduce. +Conflict in state 232 between rule 61 and token '+' resolved as shift. +Conflict in state 232 between rule 61 and token '-' resolved as shift. +Conflict in state 232 between rule 61 and token '*' resolved as shift. +Conflict in state 232 between rule 61 and token '/' resolved as shift. +Conflict in state 232 between rule 61 and token '%' resolved as shift. +Conflict in state 233 between rule 55 and token ASSIGN resolved as reduce. +Conflict in state 233 between rule 55 and token '=' resolved as reduce. +Conflict in state 233 between rule 55 and token '?' resolved as reduce. +Conflict in state 233 between rule 55 and token OROR resolved as reduce. +Conflict in state 233 between rule 55 and token ANDAND resolved as reduce. +Conflict in state 233 between rule 55 and token '|' resolved as reduce. +Conflict in state 233 between rule 55 and token '^' resolved as reduce. +Conflict in state 233 between rule 55 and token '&' resolved as reduce. +Conflict in state 233 between rule 55 and token EQCOMPARE resolved as reduce. +Conflict in state 233 between rule 55 and token ARITHCOMPARE resolved as reduce. +Conflict in state 233 between rule 55 and token LSHIFT resolved as reduce. +Conflict in state 233 between rule 55 and token RSHIFT resolved as reduce. +Conflict in state 233 between rule 55 and token '+' resolved as reduce. +Conflict in state 233 between rule 55 and token '-' resolved as reduce. +Conflict in state 233 between rule 55 and token '*' resolved as shift. +Conflict in state 233 between rule 55 and token '/' resolved as shift. +Conflict in state 233 between rule 55 and token '%' resolved as shift. +Conflict in state 234 between rule 56 and token ASSIGN resolved as reduce. +Conflict in state 234 between rule 56 and token '=' resolved as reduce. +Conflict in state 234 between rule 56 and token '?' resolved as reduce. +Conflict in state 234 between rule 56 and token OROR resolved as reduce. +Conflict in state 234 between rule 56 and token ANDAND resolved as reduce. +Conflict in state 234 between rule 56 and token '|' resolved as reduce. +Conflict in state 234 between rule 56 and token '^' resolved as reduce. +Conflict in state 234 between rule 56 and token '&' resolved as reduce. +Conflict in state 234 between rule 56 and token EQCOMPARE resolved as reduce. +Conflict in state 234 between rule 56 and token ARITHCOMPARE resolved as reduce. +Conflict in state 234 between rule 56 and token LSHIFT resolved as reduce. +Conflict in state 234 between rule 56 and token RSHIFT resolved as reduce. +Conflict in state 234 between rule 56 and token '+' resolved as reduce. +Conflict in state 234 between rule 56 and token '-' resolved as reduce. +Conflict in state 234 between rule 56 and token '*' resolved as shift. +Conflict in state 234 between rule 56 and token '/' resolved as shift. +Conflict in state 234 between rule 56 and token '%' resolved as shift. +Conflict in state 235 between rule 57 and token ASSIGN resolved as reduce. +Conflict in state 235 between rule 57 and token '=' resolved as reduce. +Conflict in state 235 between rule 57 and token '?' resolved as reduce. +Conflict in state 235 between rule 57 and token OROR resolved as reduce. +Conflict in state 235 between rule 57 and token ANDAND resolved as reduce. +Conflict in state 235 between rule 57 and token '|' resolved as reduce. +Conflict in state 235 between rule 57 and token '^' resolved as reduce. +Conflict in state 235 between rule 57 and token '&' resolved as reduce. +Conflict in state 235 between rule 57 and token EQCOMPARE resolved as reduce. +Conflict in state 235 between rule 57 and token ARITHCOMPARE resolved as reduce. +Conflict in state 235 between rule 57 and token LSHIFT resolved as reduce. +Conflict in state 235 between rule 57 and token RSHIFT resolved as reduce. +Conflict in state 235 between rule 57 and token '+' resolved as reduce. +Conflict in state 235 between rule 57 and token '-' resolved as reduce. +Conflict in state 235 between rule 57 and token '*' resolved as reduce. +Conflict in state 235 between rule 57 and token '/' resolved as reduce. +Conflict in state 235 between rule 57 and token '%' resolved as reduce. +Conflict in state 236 between rule 58 and token ASSIGN resolved as reduce. +Conflict in state 236 between rule 58 and token '=' resolved as reduce. +Conflict in state 236 between rule 58 and token '?' resolved as reduce. +Conflict in state 236 between rule 58 and token OROR resolved as reduce. +Conflict in state 236 between rule 58 and token ANDAND resolved as reduce. +Conflict in state 236 between rule 58 and token '|' resolved as reduce. +Conflict in state 236 between rule 58 and token '^' resolved as reduce. +Conflict in state 236 between rule 58 and token '&' resolved as reduce. +Conflict in state 236 between rule 58 and token EQCOMPARE resolved as reduce. +Conflict in state 236 between rule 58 and token ARITHCOMPARE resolved as reduce. +Conflict in state 236 between rule 58 and token LSHIFT resolved as reduce. +Conflict in state 236 between rule 58 and token RSHIFT resolved as reduce. +Conflict in state 236 between rule 58 and token '+' resolved as reduce. +Conflict in state 236 between rule 58 and token '-' resolved as reduce. +Conflict in state 236 between rule 58 and token '*' resolved as reduce. +Conflict in state 236 between rule 58 and token '/' resolved as reduce. +Conflict in state 236 between rule 58 and token '%' resolved as reduce. +Conflict in state 237 between rule 59 and token ASSIGN resolved as reduce. +Conflict in state 237 between rule 59 and token '=' resolved as reduce. +Conflict in state 237 between rule 59 and token '?' resolved as reduce. +Conflict in state 237 between rule 59 and token OROR resolved as reduce. +Conflict in state 237 between rule 59 and token ANDAND resolved as reduce. +Conflict in state 237 between rule 59 and token '|' resolved as reduce. +Conflict in state 237 between rule 59 and token '^' resolved as reduce. +Conflict in state 237 between rule 59 and token '&' resolved as reduce. +Conflict in state 237 between rule 59 and token EQCOMPARE resolved as reduce. +Conflict in state 237 between rule 59 and token ARITHCOMPARE resolved as reduce. +Conflict in state 237 between rule 59 and token LSHIFT resolved as reduce. +Conflict in state 237 between rule 59 and token RSHIFT resolved as reduce. +Conflict in state 237 between rule 59 and token '+' resolved as reduce. +Conflict in state 237 between rule 59 and token '-' resolved as reduce. +Conflict in state 237 between rule 59 and token '*' resolved as reduce. +Conflict in state 237 between rule 59 and token '/' resolved as reduce. +Conflict in state 237 between rule 59 and token '%' resolved as reduce. +Conflict in state 243 between rule 209 and token '(' resolved as shift. +Conflict in state 243 between rule 209 and token '[' resolved as shift. +Conflict in state 274 between rule 151 and token '(' resolved as shift. +Conflict in state 274 between rule 151 and token '[' resolved as shift. +Conflict in state 304 between rule 208 and token '(' resolved as shift. +Conflict in state 304 between rule 208 and token '[' resolved as shift. +Conflict in state 366 between rule 235 and token ELSE resolved as shift. +Conflict in state 373 between rule 69 and token ASSIGN resolved as reduce. +Conflict in state 373 between rule 69 and token '=' resolved as reduce. +Conflict in state 373 between rule 69 and token '?' resolved as shift. +Conflict in state 373 between rule 69 and token OROR resolved as shift. +Conflict in state 373 between rule 69 and token ANDAND resolved as shift. +Conflict in state 373 between rule 69 and token '|' resolved as shift. +Conflict in state 373 between rule 69 and token '^' resolved as shift. +Conflict in state 373 between rule 69 and token '&' resolved as shift. +Conflict in state 373 between rule 69 and token EQCOMPARE resolved as shift. +Conflict in state 373 between rule 69 and token ARITHCOMPARE resolved as shift. +Conflict in state 373 between rule 69 and token LSHIFT resolved as shift. +Conflict in state 373 between rule 69 and token RSHIFT resolved as shift. +Conflict in state 373 between rule 69 and token '+' resolved as shift. +Conflict in state 373 between rule 69 and token '-' resolved as shift. +Conflict in state 373 between rule 69 and token '*' resolved as shift. +Conflict in state 373 between rule 69 and token '/' resolved as shift. +Conflict in state 373 between rule 69 and token '%' resolved as shift. +Conflict in state 377 between rule 209 and token '(' resolved as shift. +Conflict in state 377 between rule 209 and token '[' resolved as shift. +Conflict in state 380 between rule 209 and token '(' resolved as shift. +Conflict in state 380 between rule 209 and token '[' resolved as shift. +Conflict in state 423 between rule 156 and token '(' resolved as shift. +Conflict in state 423 between rule 156 and token '[' resolved as shift. +State 41 contains 1 shift/reduce conflict. +State 93 contains 1 shift/reduce conflict. +State 100 contains 1 shift/reduce conflict. +State 104 contains 1 shift/reduce conflict. +State 120 contains 1 shift/reduce conflict. +State 184 contains 1 shift/reduce conflict. +State 195 contains 1 shift/reduce conflict. +State 201 contains 1 shift/reduce conflict. + + +token types: + type -1 is $ + type 33 is '!' + type 37 is '%' + type 38 is '&' + type 40 is '(' + type 41 is ')' + type 42 is '*' + type 43 is '+' + type 44 is ',' + type 45 is '-' + type 46 is '.' + type 47 is '/' + type 58 is ':' + type 59 is ';' + type 61 is '=' + type 63 is '?' + type 91 is '[' + type 93 is ']' + type 94 is '^' + type 123 is '{' + type 124 is '|' + type 125 is '}' + type 126 is '~' + type 256 is error + type 258 is IDENTIFIER + type 259 is TYPENAME + type 260 is SCSPEC + type 261 is TYPESPEC + type 262 is TYPE_QUAL + type 263 is CONSTANT + type 264 is STRING + type 265 is ELLIPSIS + type 266 is SIZEOF + type 267 is ENUM + type 268 is STRUCT + type 269 is UNION + type 270 is IF + type 271 is ELSE + type 272 is WHILE + type 273 is DO + type 274 is FOR + type 275 is SWITCH + type 276 is CASE + type 277 is DEFAULT + type 278 is BREAK + type 279 is CONTINUE + type 280 is RETURN + type 281 is GOTO + type 282 is ASM + type 283 is TYPEOF + type 284 is ALIGNOF + type 285 is ATTRIBUTE + type 286 is ASSIGN + type 287 is OROR + type 288 is ANDAND + type 289 is EQCOMPARE + type 290 is ARITHCOMPARE + type 291 is LSHIFT + type 292 is RSHIFT + type 293 is UNARY + type 294 is PLUSPLUS + type 295 is MINUSMINUS + type 296 is HYPERUNARY + type 297 is POINTSAT + + +state 0 + + $ reduce using rule 1 (program) + $default reduce using rule 3 (@1) + + extdefs go to state 1 + program go to state 513 + @1 go to state 2 + + + +state 1 + + program -> extdefs . (rule 2) + extdefs -> extdefs . @2 extdef (rule 6) + + $ reduce using rule 2 (program) + $default reduce using rule 5 (@2) + + @2 go to state 3 + + + +state 2 + + extdefs -> @1 . extdef (rule 4) + + error shift, and go to state 4 + TYPENAME shift, and go to state 5 + SCSPEC shift, and go to state 6 + TYPESPEC shift, and go to state 7 + TYPE_QUAL shift, and go to state 8 + ENUM shift, and go to state 9 + STRUCT shift, and go to state 10 + UNION shift, and go to state 11 + ASM shift, and go to state 12 + TYPEOF shift, and go to state 13 + ';' shift, and go to state 14 + + IDENTIFIER reduce using rule 93 (setspecs) + '*' [reduce using rule 93 (setspecs)] + '(' reduce using rule 93 (setspecs) + + extdef go to state 15 + datadef go to state 16 + fndef go to state 17 + setspecs go to state 18 + typed_declspecs go to state 19 + declmods go to state 20 + typespec go to state 21 + structsp go to state 22 + + + +state 3 + + extdefs -> extdefs @2 . extdef (rule 6) + + error shift, and go to state 4 + TYPENAME shift, and go to state 5 + SCSPEC shift, and go to state 6 + TYPESPEC shift, and go to state 7 + TYPE_QUAL shift, and go to state 8 + ENUM shift, and go to state 9 + STRUCT shift, and go to state 10 + UNION shift, and go to state 11 + ASM shift, and go to state 12 + TYPEOF shift, and go to state 13 + ';' shift, and go to state 14 + + IDENTIFIER reduce using rule 93 (setspecs) + '*' [reduce using rule 93 (setspecs)] + '(' reduce using rule 93 (setspecs) + + extdef go to state 23 + datadef go to state 16 + fndef go to state 17 + setspecs go to state 18 + typed_declspecs go to state 19 + declmods go to state 20 + typespec go to state 21 + structsp go to state 22 + + + +state 4 + + datadef -> error . ';' (rule 15) + datadef -> error . '}' (rule 16) + + ';' shift, and go to state 24 + '}' shift, and go to state 25 + + + +state 5 + + typespec -> TYPENAME . (rule 113) + + $default reduce using rule 113 (typespec) + + + +state 6 + + declmods -> SCSPEC . (rule 104) + + $default reduce using rule 104 (declmods) + + + +state 7 + + typespec -> TYPESPEC . (rule 111) + + $default reduce using rule 111 (typespec) + + + +state 8 + + declmods -> TYPE_QUAL . (rule 103) + + $default reduce using rule 103 (declmods) + + + +state 9 + + structsp -> ENUM . identifier '{' @14 enumlist maybecomma_warn '}' (rule 173) + structsp -> ENUM . '{' @15 enumlist maybecomma_warn '}' (rule 175) + structsp -> ENUM . identifier (rule 176) + + IDENTIFIER shift, and go to state 26 + TYPENAME shift, and go to state 27 + '{' shift, and go to state 28 + + identifier go to state 29 + + + +state 10 + + structsp -> STRUCT . identifier '{' @12 component_decl_list '}' (rule 165) + structsp -> STRUCT . '{' component_decl_list '}' (rule 166) + structsp -> STRUCT . identifier (rule 167) + + IDENTIFIER shift, and go to state 26 + TYPENAME shift, and go to state 27 + '{' shift, and go to state 30 + + identifier go to state 31 + + + +state 11 + + structsp -> UNION . identifier '{' @13 component_decl_list '}' (rule 169) + structsp -> UNION . '{' component_decl_list '}' (rule 170) + structsp -> UNION . identifier (rule 171) + + IDENTIFIER shift, and go to state 26 + TYPENAME shift, and go to state 27 + '{' shift, and go to state 32 + + identifier go to state 33 + + + +state 12 + + extdef -> ASM . '(' string ')' ';' (rule 9) + + '(' shift, and go to state 34 + + + +state 13 + + typespec -> TYPEOF . '(' expr ')' (rule 114) + typespec -> TYPEOF . '(' typename ')' (rule 115) + + '(' shift, and go to state 35 + + + +state 14 + + datadef -> ';' . (rule 17) + + $default reduce using rule 17 (datadef) + + + +state 15 + + extdefs -> @1 extdef . (rule 4) + + $default reduce using rule 4 (extdefs) + + + +state 16 + + extdef -> datadef . (rule 8) + + $default reduce using rule 8 (extdef) + + + +state 17 + + extdef -> fndef . (rule 7) + + $default reduce using rule 7 (extdef) + + + +state 18 + + datadef -> setspecs . notype_initdecls ';' (rule 10) + fndef -> setspecs . notype_declarator @7 xdecls @8 compstmt_or_error (rule 28) + fndef -> setspecs . notype_declarator error (rule 29) + + IDENTIFIER shift, and go to state 36 + '*' shift, and go to state 37 + '(' shift, and go to state 38 + + notype_initdecls go to state 39 + notype_initdcl go to state 40 + notype_declarator go to state 41 + + + +state 19 + + datadef -> typed_declspecs . setspecs initdecls ';' (rule 12) + datadef -> typed_declspecs . ';' (rule 14) + fndef -> typed_declspecs . setspecs declarator @3 xdecls @4 compstmt_or_error (rule 20) + fndef -> typed_declspecs . setspecs declarator error (rule 21) + + ';' shift, and go to state 42 + + $default reduce using rule 93 (setspecs) + + setspecs go to state 43 + + + +state 20 + + datadef -> declmods . setspecs notype_initdecls ';' (rule 11) + datadef -> declmods . ';' (rule 13) + fndef -> declmods . setspecs notype_declarator @5 xdecls @6 compstmt_or_error (rule 24) + fndef -> declmods . setspecs notype_declarator error (rule 25) + typed_declspecs -> declmods . typespec reserved_declspecs (rule 99) + declmods -> declmods . TYPE_QUAL (rule 105) + declmods -> declmods . SCSPEC (rule 106) + + TYPENAME shift, and go to state 5 + SCSPEC shift, and go to state 44 + TYPESPEC shift, and go to state 7 + TYPE_QUAL shift, and go to state 45 + ENUM shift, and go to state 9 + STRUCT shift, and go to state 10 + UNION shift, and go to state 11 + TYPEOF shift, and go to state 13 + ';' shift, and go to state 46 + + $default reduce using rule 93 (setspecs) + + setspecs go to state 47 + typespec go to state 48 + structsp go to state 22 + + + +state 21 + + typed_declspecs -> typespec . reserved_declspecs (rule 98) + + $default reduce using rule 100 (reserved_declspecs) + + reserved_declspecs go to state 49 + + + +state 22 + + typespec -> structsp . (rule 112) + + $default reduce using rule 112 (typespec) + + + +state 23 + + extdefs -> extdefs @2 extdef . (rule 6) + + $default reduce using rule 6 (extdefs) + + + +state 24 + + datadef -> error ';' . (rule 15) + + $default reduce using rule 15 (datadef) + + + +state 25 + + datadef -> error '}' . (rule 16) + + $default reduce using rule 16 (datadef) + + + +state 26 + + identifier -> IDENTIFIER . (rule 30) + + $default reduce using rule 30 (identifier) + + + +state 27 + + identifier -> TYPENAME . (rule 31) + + $default reduce using rule 31 (identifier) + + + +state 28 + + structsp -> ENUM '{' . @15 enumlist maybecomma_warn '}' (rule 175) + + $default reduce using rule 174 (@15) + + @15 go to state 50 + + + +state 29 + + structsp -> ENUM identifier . '{' @14 enumlist maybecomma_warn '}' (rule 173) + structsp -> ENUM identifier . (rule 176) + + '{' shift, and go to state 51 + + $default reduce using rule 176 (structsp) + + + +state 30 + + structsp -> STRUCT '{' . component_decl_list '}' (rule 166) + + $default reduce using rule 183 (component_decl_list2) + + component_decl_list go to state 52 + component_decl_list2 go to state 53 + + + +state 31 + + structsp -> STRUCT identifier . '{' @12 component_decl_list '}' (rule 165) + structsp -> STRUCT identifier . (rule 167) + + '{' shift, and go to state 54 + + $default reduce using rule 167 (structsp) + + + +state 32 + + structsp -> UNION '{' . component_decl_list '}' (rule 170) + + $default reduce using rule 183 (component_decl_list2) + + component_decl_list go to state 55 + component_decl_list2 go to state 53 + + + +state 33 + + structsp -> UNION identifier . '{' @13 component_decl_list '}' (rule 169) + structsp -> UNION identifier . (rule 171) + + '{' shift, and go to state 56 + + $default reduce using rule 171 (structsp) + + + +state 34 + + extdef -> ASM '(' . string ')' ';' (rule 9) + + STRING shift, and go to state 57 + + string go to state 58 + + + +state 35 + + typespec -> TYPEOF '(' . expr ')' (rule 114) + typespec -> TYPEOF '(' . typename ')' (rule 115) + + IDENTIFIER shift, and go to state 59 + TYPENAME shift, and go to state 5 + TYPESPEC shift, and go to state 7 + TYPE_QUAL shift, and go to state 60 + CONSTANT shift, and go to state 61 + STRING shift, and go to state 57 + SIZEOF shift, and go to state 62 + ENUM shift, and go to state 9 + STRUCT shift, and go to state 10 + UNION shift, and go to state 11 + TYPEOF shift, and go to state 13 + ALIGNOF shift, and go to state 63 + '&' shift, and go to state 64 + '+' shift, and go to state 65 + '-' shift, and go to state 66 + '*' shift, and go to state 67 + PLUSPLUS shift, and go to state 68 + MINUSMINUS shift, and go to state 69 + '(' shift, and go to state 70 + '~' shift, and go to state 71 + '!' shift, and go to state 72 + + unop go to state 73 + expr go to state 74 + nonnull_exprlist go to state 75 + unary_expr go to state 76 + cast_expr go to state 77 + expr_no_commas go to state 78 + primary go to state 79 + string go to state 80 + typed_typespecs go to state 81 + typespec go to state 82 + structsp go to state 22 + typename go to state 83 + nonempty_type_quals go to state 84 + + + +state 36 + + notype_declarator -> IDENTIFIER . (rule 163) + + $default reduce using rule 163 (notype_declarator) + + + +state 37 + + notype_declarator -> '*' . type_quals notype_declarator (rule 160) + + $default reduce using rule 205 (type_quals) + + type_quals go to state 85 + + + +state 38 + + notype_declarator -> '(' . notype_declarator ')' (rule 159) + + IDENTIFIER shift, and go to state 36 + '*' shift, and go to state 37 + '(' shift, and go to state 38 + + notype_declarator go to state 86 + + + +state 39 + + datadef -> setspecs notype_initdecls . ';' (rule 10) + notype_initdecls -> notype_initdecls . ',' initdcl (rule 122) + + ';' shift, and go to state 87 + ',' shift, and go to state 88 + + + +state 40 + + notype_initdecls -> notype_initdcl . (rule 121) + + $default reduce using rule 121 (notype_initdecls) + + + +state 41 + + fndef -> setspecs notype_declarator . @7 xdecls @8 compstmt_or_error (rule 28) + fndef -> setspecs notype_declarator . error (rule 29) + notype_initdcl -> notype_declarator . maybeasm maybe_attribute '=' @11 init (rule 129) + notype_initdcl -> notype_declarator . maybeasm maybe_attribute (rule 130) + notype_declarator -> notype_declarator . '(' parmlist_or_identifiers (rule 158) + notype_declarator -> notype_declarator . '[' expr ']' (rule 161) + notype_declarator -> notype_declarator . '[' ']' (rule 162) + + error shift, and go to state 89 + ASM shift, and go to state 90 + '(' shift, and go to state 91 + '[' shift, and go to state 92 + + error [reduce using rule 26 (@7)] + TYPENAME reduce using rule 26 (@7) + SCSPEC reduce using rule 26 (@7) + TYPESPEC reduce using rule 26 (@7) + TYPE_QUAL reduce using rule 26 (@7) + ENUM reduce using rule 26 (@7) + STRUCT reduce using rule 26 (@7) + UNION reduce using rule 26 (@7) + TYPEOF reduce using rule 26 (@7) + ATTRIBUTE reduce using rule 123 (maybeasm) + '=' reduce using rule 123 (maybeasm) + ';' reduce using rule 123 (maybeasm) + ',' reduce using rule 123 (maybeasm) + '{' reduce using rule 26 (@7) + + @7 go to state 93 + maybeasm go to state 94 + + + +state 42 + + datadef -> typed_declspecs ';' . (rule 14) + + $default reduce using rule 14 (datadef) + + + +state 43 + + datadef -> typed_declspecs setspecs . initdecls ';' (rule 12) + fndef -> typed_declspecs setspecs . declarator @3 xdecls @4 compstmt_or_error (rule 20) + fndef -> typed_declspecs setspecs . declarator error (rule 21) + + IDENTIFIER shift, and go to state 36 + TYPENAME shift, and go to state 95 + '*' shift, and go to state 96 + '(' shift, and go to state 97 + + initdecls go to state 98 + initdcl go to state 99 + declarator go to state 100 + after_type_declarator go to state 101 + notype_declarator go to state 102 + + + +state 44 + + declmods -> declmods SCSPEC . (rule 106) + + $default reduce using rule 106 (declmods) + + + +state 45 + + declmods -> declmods TYPE_QUAL . (rule 105) + + $default reduce using rule 105 (declmods) + + + +state 46 + + datadef -> declmods ';' . (rule 13) + + $default reduce using rule 13 (datadef) + + + +state 47 + + datadef -> declmods setspecs . notype_initdecls ';' (rule 11) + fndef -> declmods setspecs . notype_declarator @5 xdecls @6 compstmt_or_error (rule 24) + fndef -> declmods setspecs . notype_declarator error (rule 25) + + IDENTIFIER shift, and go to state 36 + '*' shift, and go to state 37 + '(' shift, and go to state 38 + + notype_initdecls go to state 103 + notype_initdcl go to state 40 + notype_declarator go to state 104 + + + +state 48 + + typed_declspecs -> declmods typespec . reserved_declspecs (rule 99) + + $default reduce using rule 100 (reserved_declspecs) + + reserved_declspecs go to state 105 + + + +state 49 + + typed_declspecs -> typespec reserved_declspecs . (rule 98) + reserved_declspecs -> reserved_declspecs . typespecqual_reserved (rule 101) + reserved_declspecs -> reserved_declspecs . SCSPEC (rule 102) + + SCSPEC shift, and go to state 106 + TYPESPEC shift, and go to state 107 + TYPE_QUAL shift, and go to state 108 + ENUM shift, and go to state 9 + STRUCT shift, and go to state 10 + UNION shift, and go to state 11 + + $default reduce using rule 98 (typed_declspecs) + + typespecqual_reserved go to state 109 + structsp go to state 110 + + + +state 50 + + structsp -> ENUM '{' @15 . enumlist maybecomma_warn '}' (rule 175) + + IDENTIFIER shift, and go to state 26 + TYPENAME shift, and go to state 27 + + identifier go to state 111 + enumlist go to state 112 + enumerator go to state 113 + + + +state 51 + + structsp -> ENUM identifier '{' . @14 enumlist maybecomma_warn '}' (rule 173) + + $default reduce using rule 172 (@14) + + @14 go to state 114 + + + +state 52 + + structsp -> STRUCT '{' component_decl_list . '}' (rule 166) + + '}' shift, and go to state 115 + + + +state 53 + + component_decl_list -> component_decl_list2 . (rule 181) + component_decl_list -> component_decl_list2 . component_decl (rule 182) + component_decl_list2 -> component_decl_list2 . component_decl ';' (rule 184) + component_decl_list2 -> component_decl_list2 . ';' (rule 185) + + error shift, and go to state 116 + TYPENAME shift, and go to state 5 + TYPESPEC shift, and go to state 7 + TYPE_QUAL shift, and go to state 60 + ENUM shift, and go to state 9 + STRUCT shift, and go to state 10 + UNION shift, and go to state 11 + TYPEOF shift, and go to state 13 + ';' shift, and go to state 117 + + '}' reduce using rule 181 (component_decl_list) + + typed_typespecs go to state 118 + typespec go to state 82 + structsp go to state 22 + component_decl go to state 119 + nonempty_type_quals go to state 120 + + + +state 54 + + structsp -> STRUCT identifier '{' . @12 component_decl_list '}' (rule 165) + + $default reduce using rule 164 (@12) + + @12 go to state 121 + + + +state 55 + + structsp -> UNION '{' component_decl_list . '}' (rule 170) + + '}' shift, and go to state 122 + + + +state 56 + + structsp -> UNION identifier '{' . @13 component_decl_list '}' (rule 169) + + $default reduce using rule 168 (@13) + + @13 go to state 123 + + + +state 57 + + string -> STRING . (rule 85) + + $default reduce using rule 85 (string) + + + +state 58 + + extdef -> ASM '(' string . ')' ';' (rule 9) + string -> string . STRING (rule 86) + + STRING shift, and go to state 124 + ')' shift, and go to state 125 + + + +state 59 + + primary -> IDENTIFIER . (rule 72) + + $default reduce using rule 72 (primary) + + + +state 60 + + nonempty_type_quals -> TYPE_QUAL . (rule 203) + + $default reduce using rule 203 (nonempty_type_quals) + + + +state 61 + + primary -> CONSTANT . (rule 73) + + $default reduce using rule 73 (primary) + + + +state 62 + + unary_expr -> SIZEOF . unary_expr (rule 47) + unary_expr -> SIZEOF . '(' typename ')' (rule 48) + + IDENTIFIER shift, and go to state 59 + CONSTANT shift, and go to state 61 + STRING shift, and go to state 57 + SIZEOF shift, and go to state 62 + ALIGNOF shift, and go to state 63 + '&' shift, and go to state 64 + '+' shift, and go to state 65 + '-' shift, and go to state 66 + '*' shift, and go to state 67 + PLUSPLUS shift, and go to state 68 + MINUSMINUS shift, and go to state 69 + '(' shift, and go to state 126 + '~' shift, and go to state 71 + '!' shift, and go to state 72 + + unop go to state 73 + unary_expr go to state 127 + primary go to state 79 + string go to state 80 + + + +state 63 + + unary_expr -> ALIGNOF . unary_expr (rule 49) + unary_expr -> ALIGNOF . '(' typename ')' (rule 50) + + IDENTIFIER shift, and go to state 59 + CONSTANT shift, and go to state 61 + STRING shift, and go to state 57 + SIZEOF shift, and go to state 62 + ALIGNOF shift, and go to state 63 + '&' shift, and go to state 64 + '+' shift, and go to state 65 + '-' shift, and go to state 66 + '*' shift, and go to state 67 + PLUSPLUS shift, and go to state 68 + MINUSMINUS shift, and go to state 69 + '(' shift, and go to state 128 + '~' shift, and go to state 71 + '!' shift, and go to state 72 + + unop go to state 73 + unary_expr go to state 129 + primary go to state 79 + string go to state 80 + + + +state 64 + + unop -> '&' . (rule 32) + + $default reduce using rule 32 (unop) + + + +state 65 + + unop -> '+' . (rule 34) + + $default reduce using rule 34 (unop) + + + +state 66 + + unop -> '-' . (rule 33) + + $default reduce using rule 33 (unop) + + + +state 67 + + unary_expr -> '*' . cast_expr (rule 45) + + IDENTIFIER shift, and go to state 59 + CONSTANT shift, and go to state 61 + STRING shift, and go to state 57 + SIZEOF shift, and go to state 62 + ALIGNOF shift, and go to state 63 + '&' shift, and go to state 64 + '+' shift, and go to state 65 + '-' shift, and go to state 66 + '*' shift, and go to state 67 + PLUSPLUS shift, and go to state 68 + MINUSMINUS shift, and go to state 69 + '(' shift, and go to state 70 + '~' shift, and go to state 71 + '!' shift, and go to state 72 + + unop go to state 73 + unary_expr go to state 76 + cast_expr go to state 130 + primary go to state 79 + string go to state 80 + + + +state 68 + + unop -> PLUSPLUS . (rule 35) + + $default reduce using rule 35 (unop) + + + +state 69 + + unop -> MINUSMINUS . (rule 36) + + $default reduce using rule 36 (unop) + + + +state 70 + + cast_expr -> '(' . typename ')' cast_expr (rule 52) + cast_expr -> '(' . typename ')' '{' initlist maybecomma '}' (rule 53) + primary -> '(' . expr ')' (rule 75) + primary -> '(' . error ')' (rule 76) + primary -> '(' . @9 compstmt ')' (rule 78) + + error shift, and go to state 131 + IDENTIFIER shift, and go to state 59 + TYPENAME shift, and go to state 5 + TYPESPEC shift, and go to state 7 + TYPE_QUAL shift, and go to state 60 + CONSTANT shift, and go to state 61 + STRING shift, and go to state 57 + SIZEOF shift, and go to state 62 + ENUM shift, and go to state 9 + STRUCT shift, and go to state 10 + UNION shift, and go to state 11 + TYPEOF shift, and go to state 13 + ALIGNOF shift, and go to state 63 + '&' shift, and go to state 64 + '+' shift, and go to state 65 + '-' shift, and go to state 66 + '*' shift, and go to state 67 + PLUSPLUS shift, and go to state 68 + MINUSMINUS shift, and go to state 69 + '(' shift, and go to state 70 + '~' shift, and go to state 71 + '!' shift, and go to state 72 + + '{' reduce using rule 77 (@9) + + unop go to state 73 + expr go to state 132 + nonnull_exprlist go to state 75 + unary_expr go to state 76 + cast_expr go to state 77 + expr_no_commas go to state 78 + primary go to state 79 + @9 go to state 133 + string go to state 80 + typed_typespecs go to state 81 + typespec go to state 82 + structsp go to state 22 + typename go to state 134 + nonempty_type_quals go to state 84 + + + +state 71 + + unop -> '~' . (rule 37) + + $default reduce using rule 37 (unop) + + + +state 72 + + unop -> '!' . (rule 38) + + $default reduce using rule 38 (unop) + + + +state 73 + + unary_expr -> unop . cast_expr (rule 46) + + IDENTIFIER shift, and go to state 59 + CONSTANT shift, and go to state 61 + STRING shift, and go to state 57 + SIZEOF shift, and go to state 62 + ALIGNOF shift, and go to state 63 + '&' shift, and go to state 64 + '+' shift, and go to state 65 + '-' shift, and go to state 66 + '*' shift, and go to state 67 + PLUSPLUS shift, and go to state 68 + MINUSMINUS shift, and go to state 69 + '(' shift, and go to state 70 + '~' shift, and go to state 71 + '!' shift, and go to state 72 + + unop go to state 73 + unary_expr go to state 76 + cast_expr go to state 135 + primary go to state 79 + string go to state 80 + + + +state 74 + + typespec -> TYPEOF '(' expr . ')' (rule 114) + + ')' shift, and go to state 136 + + + +state 75 + + expr -> nonnull_exprlist . (rule 39) + nonnull_exprlist -> nonnull_exprlist . ',' expr_no_commas (rule 43) + + ',' shift, and go to state 137 + + $default reduce using rule 39 (expr) + + + +state 76 + + cast_expr -> unary_expr . (rule 51) + + $default reduce using rule 51 (cast_expr) + + + +state 77 + + expr_no_commas -> cast_expr . (rule 54) + + $default reduce using rule 54 (expr_no_commas) + + + +state 78 + + nonnull_exprlist -> expr_no_commas . (rule 42) + expr_no_commas -> expr_no_commas . '+' expr_no_commas (rule 55) + expr_no_commas -> expr_no_commas . '-' expr_no_commas (rule 56) + expr_no_commas -> expr_no_commas . '*' expr_no_commas (rule 57) + expr_no_commas -> expr_no_commas . '/' expr_no_commas (rule 58) + expr_no_commas -> expr_no_commas . '%' expr_no_commas (rule 59) + expr_no_commas -> expr_no_commas . LSHIFT expr_no_commas (rule 60) + expr_no_commas -> expr_no_commas . RSHIFT expr_no_commas (rule 61) + expr_no_commas -> expr_no_commas . ARITHCOMPARE expr_no_commas (rule 62) + expr_no_commas -> expr_no_commas . EQCOMPARE expr_no_commas (rule 63) + expr_no_commas -> expr_no_commas . '&' expr_no_commas (rule 64) + expr_no_commas -> expr_no_commas . '|' expr_no_commas (rule 65) + expr_no_commas -> expr_no_commas . '^' expr_no_commas (rule 66) + expr_no_commas -> expr_no_commas . ANDAND expr_no_commas (rule 67) + expr_no_commas -> expr_no_commas . OROR expr_no_commas (rule 68) + expr_no_commas -> expr_no_commas . '?' xexpr ':' expr_no_commas (rule 69) + expr_no_commas -> expr_no_commas . '=' expr_no_commas (rule 70) + expr_no_commas -> expr_no_commas . ASSIGN expr_no_commas (rule 71) + + ASSIGN shift, and go to state 138 + '=' shift, and go to state 139 + '?' shift, and go to state 140 + OROR shift, and go to state 141 + ANDAND shift, and go to state 142 + '|' shift, and go to state 143 + '^' shift, and go to state 144 + '&' shift, and go to state 145 + EQCOMPARE shift, and go to state 146 + ARITHCOMPARE shift, and go to state 147 + LSHIFT shift, and go to state 148 + RSHIFT shift, and go to state 149 + '+' shift, and go to state 150 + '-' shift, and go to state 151 + '*' shift, and go to state 152 + '/' shift, and go to state 153 + '%' shift, and go to state 154 + + $default reduce using rule 42 (nonnull_exprlist) + + + +state 79 + + unary_expr -> primary . (rule 44) + primary -> primary . '(' exprlist ')' (rule 79) + primary -> primary . '[' expr ']' (rule 80) + primary -> primary . '.' identifier (rule 81) + primary -> primary . POINTSAT identifier (rule 82) + primary -> primary . PLUSPLUS (rule 83) + primary -> primary . MINUSMINUS (rule 84) + + PLUSPLUS shift, and go to state 155 + MINUSMINUS shift, and go to state 156 + POINTSAT shift, and go to state 157 + '.' shift, and go to state 158 + '(' shift, and go to state 159 + '[' shift, and go to state 160 + + $default reduce using rule 44 (unary_expr) + + + +state 80 + + primary -> string . (rule 74) + string -> string . STRING (rule 86) + + STRING shift, and go to state 124 + + $default reduce using rule 74 (primary) + + + +state 81 + + typename -> typed_typespecs . absdcl (rule 199) + + '*' shift, and go to state 161 + '(' shift, and go to state 162 + '[' shift, and go to state 163 + + $default reduce using rule 201 (absdcl) + + absdcl go to state 164 + absdcl1 go to state 165 + + + +state 82 + + typed_typespecs -> typespec . reserved_typespecquals (rule 107) + + $default reduce using rule 109 (reserved_typespecquals) + + reserved_typespecquals go to state 166 + + + +state 83 + + typespec -> TYPEOF '(' typename . ')' (rule 115) + + ')' shift, and go to state 167 + + + +state 84 + + typed_typespecs -> nonempty_type_quals . typespec reserved_typespecquals (rule 108) + typename -> nonempty_type_quals . absdcl (rule 200) + nonempty_type_quals -> nonempty_type_quals . TYPE_QUAL (rule 204) + + TYPENAME shift, and go to state 5 + TYPESPEC shift, and go to state 7 + TYPE_QUAL shift, and go to state 168 + ENUM shift, and go to state 9 + STRUCT shift, and go to state 10 + UNION shift, and go to state 11 + TYPEOF shift, and go to state 13 + '*' shift, and go to state 161 + '(' shift, and go to state 162 + '[' shift, and go to state 163 + + $default reduce using rule 201 (absdcl) + + typespec go to state 169 + structsp go to state 22 + absdcl go to state 170 + absdcl1 go to state 165 + + + +state 85 + + notype_declarator -> '*' type_quals . notype_declarator (rule 160) + type_quals -> type_quals . TYPE_QUAL (rule 206) + + IDENTIFIER shift, and go to state 36 + TYPE_QUAL shift, and go to state 171 + '*' shift, and go to state 37 + '(' shift, and go to state 38 + + notype_declarator go to state 172 + + + +state 86 + + notype_declarator -> notype_declarator . '(' parmlist_or_identifiers (rule 158) + notype_declarator -> '(' notype_declarator . ')' (rule 159) + notype_declarator -> notype_declarator . '[' expr ']' (rule 161) + notype_declarator -> notype_declarator . '[' ']' (rule 162) + + '(' shift, and go to state 91 + '[' shift, and go to state 92 + ')' shift, and go to state 173 + + + +state 87 + + datadef -> setspecs notype_initdecls ';' . (rule 10) + + $default reduce using rule 10 (datadef) + + + +state 88 + + notype_initdecls -> notype_initdecls ',' . initdcl (rule 122) + + IDENTIFIER shift, and go to state 36 + TYPENAME shift, and go to state 95 + '*' shift, and go to state 96 + '(' shift, and go to state 97 + + initdcl go to state 174 + declarator go to state 175 + after_type_declarator go to state 101 + notype_declarator go to state 102 + + + +state 89 + + fndef -> setspecs notype_declarator error . (rule 29) + + $default reduce using rule 29 (fndef) + + + +state 90 + + maybeasm -> ASM . '(' string ')' (rule 124) + + '(' shift, and go to state 176 + + + +state 91 + + notype_declarator -> notype_declarator '(' . parmlist_or_identifiers (rule 158) + + $default reduce using rule 277 (@30) + + parmlist_or_identifiers go to state 177 + @30 go to state 178 + + + +state 92 + + notype_declarator -> notype_declarator '[' . expr ']' (rule 161) + notype_declarator -> notype_declarator '[' . ']' (rule 162) + + IDENTIFIER shift, and go to state 59 + CONSTANT shift, and go to state 61 + STRING shift, and go to state 57 + SIZEOF shift, and go to state 62 + ALIGNOF shift, and go to state 63 + '&' shift, and go to state 64 + '+' shift, and go to state 65 + '-' shift, and go to state 66 + '*' shift, and go to state 67 + PLUSPLUS shift, and go to state 68 + MINUSMINUS shift, and go to state 69 + '(' shift, and go to state 70 + '~' shift, and go to state 71 + '!' shift, and go to state 72 + ']' shift, and go to state 179 + + unop go to state 73 + expr go to state 180 + nonnull_exprlist go to state 75 + unary_expr go to state 76 + cast_expr go to state 77 + expr_no_commas go to state 78 + primary go to state 79 + string go to state 80 + + + +state 93 + + fndef -> setspecs notype_declarator @7 . xdecls @8 compstmt_or_error (rule 28) + + error shift, and go to state 181 + TYPENAME shift, and go to state 5 + SCSPEC shift, and go to state 6 + TYPESPEC shift, and go to state 7 + TYPE_QUAL shift, and go to state 8 + ENUM shift, and go to state 9 + STRUCT shift, and go to state 10 + UNION shift, and go to state 11 + TYPEOF shift, and go to state 13 + + error [reduce using rule 87 (xdecls)] + '{' reduce using rule 87 (xdecls) + + xdecls go to state 182 + decls go to state 183 + decl go to state 184 + typed_declspecs go to state 185 + declmods go to state 186 + typespec go to state 21 + structsp go to state 22 + errstmt go to state 187 + + + +state 94 + + notype_initdcl -> notype_declarator maybeasm . maybe_attribute '=' @11 init (rule 129) + notype_initdcl -> notype_declarator maybeasm . maybe_attribute (rule 130) + + ATTRIBUTE shift, and go to state 188 + + $default reduce using rule 131 (maybe_attribute) + + maybe_attribute go to state 189 + + + +state 95 + + after_type_declarator -> TYPENAME . (rule 152) + + $default reduce using rule 152 (after_type_declarator) + + + +state 96 + + after_type_declarator -> '*' . type_quals after_type_declarator (rule 151) + notype_declarator -> '*' . type_quals notype_declarator (rule 160) + + $default reduce using rule 205 (type_quals) + + type_quals go to state 190 + + + +state 97 + + after_type_declarator -> '(' . after_type_declarator ')' (rule 147) + notype_declarator -> '(' . notype_declarator ')' (rule 159) + + IDENTIFIER shift, and go to state 36 + TYPENAME shift, and go to state 95 + '*' shift, and go to state 96 + '(' shift, and go to state 97 + + after_type_declarator go to state 191 + notype_declarator go to state 86 + + + +state 98 + + datadef -> typed_declspecs setspecs initdecls . ';' (rule 12) + initdecls -> initdecls . ',' initdcl (rule 120) + + ';' shift, and go to state 192 + ',' shift, and go to state 193 + + + +state 99 + + initdecls -> initdcl . (rule 119) + + $default reduce using rule 119 (initdecls) + + + +state 100 + + fndef -> typed_declspecs setspecs declarator . @3 xdecls @4 compstmt_or_error (rule 20) + fndef -> typed_declspecs setspecs declarator . error (rule 21) + initdcl -> declarator . maybeasm maybe_attribute '=' @10 init (rule 126) + initdcl -> declarator . maybeasm maybe_attribute (rule 127) + + error shift, and go to state 194 + ASM shift, and go to state 90 + + error [reduce using rule 18 (@3)] + TYPENAME reduce using rule 18 (@3) + SCSPEC reduce using rule 18 (@3) + TYPESPEC reduce using rule 18 (@3) + TYPE_QUAL reduce using rule 18 (@3) + ENUM reduce using rule 18 (@3) + STRUCT reduce using rule 18 (@3) + UNION reduce using rule 18 (@3) + TYPEOF reduce using rule 18 (@3) + ATTRIBUTE reduce using rule 123 (maybeasm) + '=' reduce using rule 123 (maybeasm) + ';' reduce using rule 123 (maybeasm) + ',' reduce using rule 123 (maybeasm) + '{' reduce using rule 18 (@3) + + @3 go to state 195 + maybeasm go to state 196 + + + +state 101 + + declarator -> after_type_declarator . (rule 145) + after_type_declarator -> after_type_declarator . '(' parmlist_or_identifiers (rule 148) + after_type_declarator -> after_type_declarator . '[' expr ']' (rule 149) + after_type_declarator -> after_type_declarator . '[' ']' (rule 150) + + '(' shift, and go to state 197 + '[' shift, and go to state 198 + + $default reduce using rule 145 (declarator) + + + +state 102 + + declarator -> notype_declarator . (rule 146) + notype_declarator -> notype_declarator . '(' parmlist_or_identifiers (rule 158) + notype_declarator -> notype_declarator . '[' expr ']' (rule 161) + notype_declarator -> notype_declarator . '[' ']' (rule 162) + + '(' shift, and go to state 91 + '[' shift, and go to state 92 + + $default reduce using rule 146 (declarator) + + + +state 103 + + datadef -> declmods setspecs notype_initdecls . ';' (rule 11) + notype_initdecls -> notype_initdecls . ',' initdcl (rule 122) + + ';' shift, and go to state 199 + ',' shift, and go to state 88 + + + +state 104 + + fndef -> declmods setspecs notype_declarator . @5 xdecls @6 compstmt_or_error (rule 24) + fndef -> declmods setspecs notype_declarator . error (rule 25) + notype_initdcl -> notype_declarator . maybeasm maybe_attribute '=' @11 init (rule 129) + notype_initdcl -> notype_declarator . maybeasm maybe_attribute (rule 130) + notype_declarator -> notype_declarator . '(' parmlist_or_identifiers (rule 158) + notype_declarator -> notype_declarator . '[' expr ']' (rule 161) + notype_declarator -> notype_declarator . '[' ']' (rule 162) + + error shift, and go to state 200 + ASM shift, and go to state 90 + '(' shift, and go to state 91 + '[' shift, and go to state 92 + + error [reduce using rule 22 (@5)] + TYPENAME reduce using rule 22 (@5) + SCSPEC reduce using rule 22 (@5) + TYPESPEC reduce using rule 22 (@5) + TYPE_QUAL reduce using rule 22 (@5) + ENUM reduce using rule 22 (@5) + STRUCT reduce using rule 22 (@5) + UNION reduce using rule 22 (@5) + TYPEOF reduce using rule 22 (@5) + ATTRIBUTE reduce using rule 123 (maybeasm) + '=' reduce using rule 123 (maybeasm) + ';' reduce using rule 123 (maybeasm) + ',' reduce using rule 123 (maybeasm) + '{' reduce using rule 22 (@5) + + @5 go to state 201 + maybeasm go to state 94 + + + +state 105 + + typed_declspecs -> declmods typespec reserved_declspecs . (rule 99) + reserved_declspecs -> reserved_declspecs . typespecqual_reserved (rule 101) + reserved_declspecs -> reserved_declspecs . SCSPEC (rule 102) + + SCSPEC shift, and go to state 106 + TYPESPEC shift, and go to state 107 + TYPE_QUAL shift, and go to state 108 + ENUM shift, and go to state 9 + STRUCT shift, and go to state 10 + UNION shift, and go to state 11 + + $default reduce using rule 99 (typed_declspecs) + + typespecqual_reserved go to state 109 + structsp go to state 110 + + + +state 106 + + reserved_declspecs -> reserved_declspecs SCSPEC . (rule 102) + + $default reduce using rule 102 (reserved_declspecs) + + + +state 107 + + typespecqual_reserved -> TYPESPEC . (rule 116) + + $default reduce using rule 116 (typespecqual_reserved) + + + +state 108 + + typespecqual_reserved -> TYPE_QUAL . (rule 117) + + $default reduce using rule 117 (typespecqual_reserved) + + + +state 109 + + reserved_declspecs -> reserved_declspecs typespecqual_reserved . (rule 101) + + $default reduce using rule 101 (reserved_declspecs) + + + +state 110 + + typespecqual_reserved -> structsp . (rule 118) + + $default reduce using rule 118 (typespecqual_reserved) + + + +state 111 + + enumerator -> identifier . (rule 197) + enumerator -> identifier . '=' expr_no_commas (rule 198) + + '=' shift, and go to state 202 + + $default reduce using rule 197 (enumerator) + + + +state 112 + + structsp -> ENUM '{' @15 enumlist . maybecomma_warn '}' (rule 175) + enumlist -> enumlist . ',' enumerator (rule 196) + + ',' shift, and go to state 203 + + $default reduce using rule 179 (maybecomma_warn) + + maybecomma_warn go to state 204 + + + +state 113 + + enumlist -> enumerator . (rule 195) + + $default reduce using rule 195 (enumlist) + + + +state 114 + + structsp -> ENUM identifier '{' @14 . enumlist maybecomma_warn '}' (rule 173) + + IDENTIFIER shift, and go to state 26 + TYPENAME shift, and go to state 27 + + identifier go to state 111 + enumlist go to state 205 + enumerator go to state 113 + + + +state 115 + + structsp -> STRUCT '{' component_decl_list '}' . (rule 166) + + $default reduce using rule 166 (structsp) + + + +state 116 + + component_decl -> error . (rule 188) + + $default reduce using rule 188 (component_decl) + + + +state 117 + + component_decl_list2 -> component_decl_list2 ';' . (rule 185) + + $default reduce using rule 185 (component_decl_list2) + + + +state 118 + + component_decl -> typed_typespecs . setspecs components (rule 186) + + $default reduce using rule 93 (setspecs) + + setspecs go to state 206 + + + +state 119 + + component_decl_list -> component_decl_list2 component_decl . (rule 182) + component_decl_list2 -> component_decl_list2 component_decl . ';' (rule 184) + + ';' shift, and go to state 207 + + $default reduce using rule 182 (component_decl_list) + + + +state 120 + + typed_typespecs -> nonempty_type_quals . typespec reserved_typespecquals (rule 108) + component_decl -> nonempty_type_quals . setspecs components (rule 187) + nonempty_type_quals -> nonempty_type_quals . TYPE_QUAL (rule 204) + + TYPENAME shift, and go to state 5 + TYPESPEC shift, and go to state 7 + TYPE_QUAL shift, and go to state 168 + ENUM shift, and go to state 9 + STRUCT shift, and go to state 10 + UNION shift, and go to state 11 + TYPEOF shift, and go to state 13 + + TYPENAME [reduce using rule 93 (setspecs)] + $default reduce using rule 93 (setspecs) + + setspecs go to state 208 + typespec go to state 169 + structsp go to state 22 + + + +state 121 + + structsp -> STRUCT identifier '{' @12 . component_decl_list '}' (rule 165) + + $default reduce using rule 183 (component_decl_list2) + + component_decl_list go to state 209 + component_decl_list2 go to state 53 + + + +state 122 + + structsp -> UNION '{' component_decl_list '}' . (rule 170) + + $default reduce using rule 170 (structsp) + + + +state 123 + + structsp -> UNION identifier '{' @13 . component_decl_list '}' (rule 169) + + $default reduce using rule 183 (component_decl_list2) + + component_decl_list go to state 210 + component_decl_list2 go to state 53 + + + +state 124 + + string -> string STRING . (rule 86) + + $default reduce using rule 86 (string) + + + +state 125 + + extdef -> ASM '(' string ')' . ';' (rule 9) + + ';' shift, and go to state 211 + + + +state 126 + + unary_expr -> SIZEOF '(' . typename ')' (rule 48) + primary -> '(' . expr ')' (rule 75) + primary -> '(' . error ')' (rule 76) + primary -> '(' . @9 compstmt ')' (rule 78) + + error shift, and go to state 131 + IDENTIFIER shift, and go to state 59 + TYPENAME shift, and go to state 5 + TYPESPEC shift, and go to state 7 + TYPE_QUAL shift, and go to state 60 + CONSTANT shift, and go to state 61 + STRING shift, and go to state 57 + SIZEOF shift, and go to state 62 + ENUM shift, and go to state 9 + STRUCT shift, and go to state 10 + UNION shift, and go to state 11 + TYPEOF shift, and go to state 13 + ALIGNOF shift, and go to state 63 + '&' shift, and go to state 64 + '+' shift, and go to state 65 + '-' shift, and go to state 66 + '*' shift, and go to state 67 + PLUSPLUS shift, and go to state 68 + MINUSMINUS shift, and go to state 69 + '(' shift, and go to state 70 + '~' shift, and go to state 71 + '!' shift, and go to state 72 + + '{' reduce using rule 77 (@9) + + unop go to state 73 + expr go to state 132 + nonnull_exprlist go to state 75 + unary_expr go to state 76 + cast_expr go to state 77 + expr_no_commas go to state 78 + primary go to state 79 + @9 go to state 133 + string go to state 80 + typed_typespecs go to state 81 + typespec go to state 82 + structsp go to state 22 + typename go to state 212 + nonempty_type_quals go to state 84 + + + +state 127 + + unary_expr -> SIZEOF unary_expr . (rule 47) + + $default reduce using rule 47 (unary_expr) + + + +state 128 + + unary_expr -> ALIGNOF '(' . typename ')' (rule 50) + primary -> '(' . expr ')' (rule 75) + primary -> '(' . error ')' (rule 76) + primary -> '(' . @9 compstmt ')' (rule 78) + + error shift, and go to state 131 + IDENTIFIER shift, and go to state 59 + TYPENAME shift, and go to state 5 + TYPESPEC shift, and go to state 7 + TYPE_QUAL shift, and go to state 60 + CONSTANT shift, and go to state 61 + STRING shift, and go to state 57 + SIZEOF shift, and go to state 62 + ENUM shift, and go to state 9 + STRUCT shift, and go to state 10 + UNION shift, and go to state 11 + TYPEOF shift, and go to state 13 + ALIGNOF shift, and go to state 63 + '&' shift, and go to state 64 + '+' shift, and go to state 65 + '-' shift, and go to state 66 + '*' shift, and go to state 67 + PLUSPLUS shift, and go to state 68 + MINUSMINUS shift, and go to state 69 + '(' shift, and go to state 70 + '~' shift, and go to state 71 + '!' shift, and go to state 72 + + '{' reduce using rule 77 (@9) + + unop go to state 73 + expr go to state 132 + nonnull_exprlist go to state 75 + unary_expr go to state 76 + cast_expr go to state 77 + expr_no_commas go to state 78 + primary go to state 79 + @9 go to state 133 + string go to state 80 + typed_typespecs go to state 81 + typespec go to state 82 + structsp go to state 22 + typename go to state 213 + nonempty_type_quals go to state 84 + + + +state 129 + + unary_expr -> ALIGNOF unary_expr . (rule 49) + + $default reduce using rule 49 (unary_expr) + + + +state 130 + + unary_expr -> '*' cast_expr . (rule 45) + + $default reduce using rule 45 (unary_expr) + + + +state 131 + + primary -> '(' error . ')' (rule 76) + + ')' shift, and go to state 214 + + + +state 132 + + primary -> '(' expr . ')' (rule 75) + + ')' shift, and go to state 215 + + + +state 133 + + primary -> '(' @9 . compstmt ')' (rule 78) + + '{' shift, and go to state 216 + + compstmt go to state 217 + + + +state 134 + + cast_expr -> '(' typename . ')' cast_expr (rule 52) + cast_expr -> '(' typename . ')' '{' initlist maybecomma '}' (rule 53) + + ')' shift, and go to state 218 + + + +state 135 + + unary_expr -> unop cast_expr . (rule 46) + + $default reduce using rule 46 (unary_expr) + + + +state 136 + + typespec -> TYPEOF '(' expr ')' . (rule 114) + + $default reduce using rule 114 (typespec) + + + +state 137 + + nonnull_exprlist -> nonnull_exprlist ',' . expr_no_commas (rule 43) + + IDENTIFIER shift, and go to state 59 + CONSTANT shift, and go to state 61 + STRING shift, and go to state 57 + SIZEOF shift, and go to state 62 + ALIGNOF shift, and go to state 63 + '&' shift, and go to state 64 + '+' shift, and go to state 65 + '-' shift, and go to state 66 + '*' shift, and go to state 67 + PLUSPLUS shift, and go to state 68 + MINUSMINUS shift, and go to state 69 + '(' shift, and go to state 70 + '~' shift, and go to state 71 + '!' shift, and go to state 72 + + unop go to state 73 + unary_expr go to state 76 + cast_expr go to state 77 + expr_no_commas go to state 219 + primary go to state 79 + string go to state 80 + + + +state 138 + + expr_no_commas -> expr_no_commas ASSIGN . expr_no_commas (rule 71) + + IDENTIFIER shift, and go to state 59 + CONSTANT shift, and go to state 61 + STRING shift, and go to state 57 + SIZEOF shift, and go to state 62 + ALIGNOF shift, and go to state 63 + '&' shift, and go to state 64 + '+' shift, and go to state 65 + '-' shift, and go to state 66 + '*' shift, and go to state 67 + PLUSPLUS shift, and go to state 68 + MINUSMINUS shift, and go to state 69 + '(' shift, and go to state 70 + '~' shift, and go to state 71 + '!' shift, and go to state 72 + + unop go to state 73 + unary_expr go to state 76 + cast_expr go to state 77 + expr_no_commas go to state 220 + primary go to state 79 + string go to state 80 + + + +state 139 + + expr_no_commas -> expr_no_commas '=' . expr_no_commas (rule 70) + + IDENTIFIER shift, and go to state 59 + CONSTANT shift, and go to state 61 + STRING shift, and go to state 57 + SIZEOF shift, and go to state 62 + ALIGNOF shift, and go to state 63 + '&' shift, and go to state 64 + '+' shift, and go to state 65 + '-' shift, and go to state 66 + '*' shift, and go to state 67 + PLUSPLUS shift, and go to state 68 + MINUSMINUS shift, and go to state 69 + '(' shift, and go to state 70 + '~' shift, and go to state 71 + '!' shift, and go to state 72 + + unop go to state 73 + unary_expr go to state 76 + cast_expr go to state 77 + expr_no_commas go to state 221 + primary go to state 79 + string go to state 80 + + + +state 140 + + expr_no_commas -> expr_no_commas '?' . xexpr ':' expr_no_commas (rule 69) + + IDENTIFIER shift, and go to state 59 + CONSTANT shift, and go to state 61 + STRING shift, and go to state 57 + SIZEOF shift, and go to state 62 + ALIGNOF shift, and go to state 63 + '&' shift, and go to state 64 + '+' shift, and go to state 65 + '-' shift, and go to state 66 + '*' shift, and go to state 67 + PLUSPLUS shift, and go to state 68 + MINUSMINUS shift, and go to state 69 + '(' shift, and go to state 70 + '~' shift, and go to state 71 + '!' shift, and go to state 72 + + $default reduce using rule 266 (xexpr) + + unop go to state 73 + expr go to state 222 + nonnull_exprlist go to state 75 + unary_expr go to state 76 + cast_expr go to state 77 + expr_no_commas go to state 78 + primary go to state 79 + string go to state 80 + xexpr go to state 223 + + + +state 141 + + expr_no_commas -> expr_no_commas OROR . expr_no_commas (rule 68) + + IDENTIFIER shift, and go to state 59 + CONSTANT shift, and go to state 61 + STRING shift, and go to state 57 + SIZEOF shift, and go to state 62 + ALIGNOF shift, and go to state 63 + '&' shift, and go to state 64 + '+' shift, and go to state 65 + '-' shift, and go to state 66 + '*' shift, and go to state 67 + PLUSPLUS shift, and go to state 68 + MINUSMINUS shift, and go to state 69 + '(' shift, and go to state 70 + '~' shift, and go to state 71 + '!' shift, and go to state 72 + + unop go to state 73 + unary_expr go to state 76 + cast_expr go to state 77 + expr_no_commas go to state 224 + primary go to state 79 + string go to state 80 + + + +state 142 + + expr_no_commas -> expr_no_commas ANDAND . expr_no_commas (rule 67) + + IDENTIFIER shift, and go to state 59 + CONSTANT shift, and go to state 61 + STRING shift, and go to state 57 + SIZEOF shift, and go to state 62 + ALIGNOF shift, and go to state 63 + '&' shift, and go to state 64 + '+' shift, and go to state 65 + '-' shift, and go to state 66 + '*' shift, and go to state 67 + PLUSPLUS shift, and go to state 68 + MINUSMINUS shift, and go to state 69 + '(' shift, and go to state 70 + '~' shift, and go to state 71 + '!' shift, and go to state 72 + + unop go to state 73 + unary_expr go to state 76 + cast_expr go to state 77 + expr_no_commas go to state 225 + primary go to state 79 + string go to state 80 + + + +state 143 + + expr_no_commas -> expr_no_commas '|' . expr_no_commas (rule 65) + + IDENTIFIER shift, and go to state 59 + CONSTANT shift, and go to state 61 + STRING shift, and go to state 57 + SIZEOF shift, and go to state 62 + ALIGNOF shift, and go to state 63 + '&' shift, and go to state 64 + '+' shift, and go to state 65 + '-' shift, and go to state 66 + '*' shift, and go to state 67 + PLUSPLUS shift, and go to state 68 + MINUSMINUS shift, and go to state 69 + '(' shift, and go to state 70 + '~' shift, and go to state 71 + '!' shift, and go to state 72 + + unop go to state 73 + unary_expr go to state 76 + cast_expr go to state 77 + expr_no_commas go to state 226 + primary go to state 79 + string go to state 80 + + + +state 144 + + expr_no_commas -> expr_no_commas '^' . expr_no_commas (rule 66) + + IDENTIFIER shift, and go to state 59 + CONSTANT shift, and go to state 61 + STRING shift, and go to state 57 + SIZEOF shift, and go to state 62 + ALIGNOF shift, and go to state 63 + '&' shift, and go to state 64 + '+' shift, and go to state 65 + '-' shift, and go to state 66 + '*' shift, and go to state 67 + PLUSPLUS shift, and go to state 68 + MINUSMINUS shift, and go to state 69 + '(' shift, and go to state 70 + '~' shift, and go to state 71 + '!' shift, and go to state 72 + + unop go to state 73 + unary_expr go to state 76 + cast_expr go to state 77 + expr_no_commas go to state 227 + primary go to state 79 + string go to state 80 + + + +state 145 + + expr_no_commas -> expr_no_commas '&' . expr_no_commas (rule 64) + + IDENTIFIER shift, and go to state 59 + CONSTANT shift, and go to state 61 + STRING shift, and go to state 57 + SIZEOF shift, and go to state 62 + ALIGNOF shift, and go to state 63 + '&' shift, and go to state 64 + '+' shift, and go to state 65 + '-' shift, and go to state 66 + '*' shift, and go to state 67 + PLUSPLUS shift, and go to state 68 + MINUSMINUS shift, and go to state 69 + '(' shift, and go to state 70 + '~' shift, and go to state 71 + '!' shift, and go to state 72 + + unop go to state 73 + unary_expr go to state 76 + cast_expr go to state 77 + expr_no_commas go to state 228 + primary go to state 79 + string go to state 80 + + + +state 146 + + expr_no_commas -> expr_no_commas EQCOMPARE . expr_no_commas (rule 63) + + IDENTIFIER shift, and go to state 59 + CONSTANT shift, and go to state 61 + STRING shift, and go to state 57 + SIZEOF shift, and go to state 62 + ALIGNOF shift, and go to state 63 + '&' shift, and go to state 64 + '+' shift, and go to state 65 + '-' shift, and go to state 66 + '*' shift, and go to state 67 + PLUSPLUS shift, and go to state 68 + MINUSMINUS shift, and go to state 69 + '(' shift, and go to state 70 + '~' shift, and go to state 71 + '!' shift, and go to state 72 + + unop go to state 73 + unary_expr go to state 76 + cast_expr go to state 77 + expr_no_commas go to state 229 + primary go to state 79 + string go to state 80 + + + +state 147 + + expr_no_commas -> expr_no_commas ARITHCOMPARE . expr_no_commas (rule 62) + + IDENTIFIER shift, and go to state 59 + CONSTANT shift, and go to state 61 + STRING shift, and go to state 57 + SIZEOF shift, and go to state 62 + ALIGNOF shift, and go to state 63 + '&' shift, and go to state 64 + '+' shift, and go to state 65 + '-' shift, and go to state 66 + '*' shift, and go to state 67 + PLUSPLUS shift, and go to state 68 + MINUSMINUS shift, and go to state 69 + '(' shift, and go to state 70 + '~' shift, and go to state 71 + '!' shift, and go to state 72 + + unop go to state 73 + unary_expr go to state 76 + cast_expr go to state 77 + expr_no_commas go to state 230 + primary go to state 79 + string go to state 80 + + + +state 148 + + expr_no_commas -> expr_no_commas LSHIFT . expr_no_commas (rule 60) + + IDENTIFIER shift, and go to state 59 + CONSTANT shift, and go to state 61 + STRING shift, and go to state 57 + SIZEOF shift, and go to state 62 + ALIGNOF shift, and go to state 63 + '&' shift, and go to state 64 + '+' shift, and go to state 65 + '-' shift, and go to state 66 + '*' shift, and go to state 67 + PLUSPLUS shift, and go to state 68 + MINUSMINUS shift, and go to state 69 + '(' shift, and go to state 70 + '~' shift, and go to state 71 + '!' shift, and go to state 72 + + unop go to state 73 + unary_expr go to state 76 + cast_expr go to state 77 + expr_no_commas go to state 231 + primary go to state 79 + string go to state 80 + + + +state 149 + + expr_no_commas -> expr_no_commas RSHIFT . expr_no_commas (rule 61) + + IDENTIFIER shift, and go to state 59 + CONSTANT shift, and go to state 61 + STRING shift, and go to state 57 + SIZEOF shift, and go to state 62 + ALIGNOF shift, and go to state 63 + '&' shift, and go to state 64 + '+' shift, and go to state 65 + '-' shift, and go to state 66 + '*' shift, and go to state 67 + PLUSPLUS shift, and go to state 68 + MINUSMINUS shift, and go to state 69 + '(' shift, and go to state 70 + '~' shift, and go to state 71 + '!' shift, and go to state 72 + + unop go to state 73 + unary_expr go to state 76 + cast_expr go to state 77 + expr_no_commas go to state 232 + primary go to state 79 + string go to state 80 + + + +state 150 + + expr_no_commas -> expr_no_commas '+' . expr_no_commas (rule 55) + + IDENTIFIER shift, and go to state 59 + CONSTANT shift, and go to state 61 + STRING shift, and go to state 57 + SIZEOF shift, and go to state 62 + ALIGNOF shift, and go to state 63 + '&' shift, and go to state 64 + '+' shift, and go to state 65 + '-' shift, and go to state 66 + '*' shift, and go to state 67 + PLUSPLUS shift, and go to state 68 + MINUSMINUS shift, and go to state 69 + '(' shift, and go to state 70 + '~' shift, and go to state 71 + '!' shift, and go to state 72 + + unop go to state 73 + unary_expr go to state 76 + cast_expr go to state 77 + expr_no_commas go to state 233 + primary go to state 79 + string go to state 80 + + + +state 151 + + expr_no_commas -> expr_no_commas '-' . expr_no_commas (rule 56) + + IDENTIFIER shift, and go to state 59 + CONSTANT shift, and go to state 61 + STRING shift, and go to state 57 + SIZEOF shift, and go to state 62 + ALIGNOF shift, and go to state 63 + '&' shift, and go to state 64 + '+' shift, and go to state 65 + '-' shift, and go to state 66 + '*' shift, and go to state 67 + PLUSPLUS shift, and go to state 68 + MINUSMINUS shift, and go to state 69 + '(' shift, and go to state 70 + '~' shift, and go to state 71 + '!' shift, and go to state 72 + + unop go to state 73 + unary_expr go to state 76 + cast_expr go to state 77 + expr_no_commas go to state 234 + primary go to state 79 + string go to state 80 + + + +state 152 + + expr_no_commas -> expr_no_commas '*' . expr_no_commas (rule 57) + + IDENTIFIER shift, and go to state 59 + CONSTANT shift, and go to state 61 + STRING shift, and go to state 57 + SIZEOF shift, and go to state 62 + ALIGNOF shift, and go to state 63 + '&' shift, and go to state 64 + '+' shift, and go to state 65 + '-' shift, and go to state 66 + '*' shift, and go to state 67 + PLUSPLUS shift, and go to state 68 + MINUSMINUS shift, and go to state 69 + '(' shift, and go to state 70 + '~' shift, and go to state 71 + '!' shift, and go to state 72 + + unop go to state 73 + unary_expr go to state 76 + cast_expr go to state 77 + expr_no_commas go to state 235 + primary go to state 79 + string go to state 80 + + + +state 153 + + expr_no_commas -> expr_no_commas '/' . expr_no_commas (rule 58) + + IDENTIFIER shift, and go to state 59 + CONSTANT shift, and go to state 61 + STRING shift, and go to state 57 + SIZEOF shift, and go to state 62 + ALIGNOF shift, and go to state 63 + '&' shift, and go to state 64 + '+' shift, and go to state 65 + '-' shift, and go to state 66 + '*' shift, and go to state 67 + PLUSPLUS shift, and go to state 68 + MINUSMINUS shift, and go to state 69 + '(' shift, and go to state 70 + '~' shift, and go to state 71 + '!' shift, and go to state 72 + + unop go to state 73 + unary_expr go to state 76 + cast_expr go to state 77 + expr_no_commas go to state 236 + primary go to state 79 + string go to state 80 + + + +state 154 + + expr_no_commas -> expr_no_commas '%' . expr_no_commas (rule 59) + + IDENTIFIER shift, and go to state 59 + CONSTANT shift, and go to state 61 + STRING shift, and go to state 57 + SIZEOF shift, and go to state 62 + ALIGNOF shift, and go to state 63 + '&' shift, and go to state 64 + '+' shift, and go to state 65 + '-' shift, and go to state 66 + '*' shift, and go to state 67 + PLUSPLUS shift, and go to state 68 + MINUSMINUS shift, and go to state 69 + '(' shift, and go to state 70 + '~' shift, and go to state 71 + '!' shift, and go to state 72 + + unop go to state 73 + unary_expr go to state 76 + cast_expr go to state 77 + expr_no_commas go to state 237 + primary go to state 79 + string go to state 80 + + + +state 155 + + primary -> primary PLUSPLUS . (rule 83) + + $default reduce using rule 83 (primary) + + + +state 156 + + primary -> primary MINUSMINUS . (rule 84) + + $default reduce using rule 84 (primary) + + + +state 157 + + primary -> primary POINTSAT . identifier (rule 82) + + IDENTIFIER shift, and go to state 26 + TYPENAME shift, and go to state 27 + + identifier go to state 238 + + + +state 158 + + primary -> primary '.' . identifier (rule 81) + + IDENTIFIER shift, and go to state 26 + TYPENAME shift, and go to state 27 + + identifier go to state 239 + + + +state 159 + + primary -> primary '(' . exprlist ')' (rule 79) + + IDENTIFIER shift, and go to state 59 + CONSTANT shift, and go to state 61 + STRING shift, and go to state 57 + SIZEOF shift, and go to state 62 + ALIGNOF shift, and go to state 63 + '&' shift, and go to state 64 + '+' shift, and go to state 65 + '-' shift, and go to state 66 + '*' shift, and go to state 67 + PLUSPLUS shift, and go to state 68 + MINUSMINUS shift, and go to state 69 + '(' shift, and go to state 70 + '~' shift, and go to state 71 + '!' shift, and go to state 72 + + $default reduce using rule 40 (exprlist) + + unop go to state 73 + exprlist go to state 240 + nonnull_exprlist go to state 241 + unary_expr go to state 76 + cast_expr go to state 77 + expr_no_commas go to state 78 + primary go to state 79 + string go to state 80 + + + +state 160 + + primary -> primary '[' . expr ']' (rule 80) + + IDENTIFIER shift, and go to state 59 + CONSTANT shift, and go to state 61 + STRING shift, and go to state 57 + SIZEOF shift, and go to state 62 + ALIGNOF shift, and go to state 63 + '&' shift, and go to state 64 + '+' shift, and go to state 65 + '-' shift, and go to state 66 + '*' shift, and go to state 67 + PLUSPLUS shift, and go to state 68 + MINUSMINUS shift, and go to state 69 + '(' shift, and go to state 70 + '~' shift, and go to state 71 + '!' shift, and go to state 72 + + unop go to state 73 + expr go to state 242 + nonnull_exprlist go to state 75 + unary_expr go to state 76 + cast_expr go to state 77 + expr_no_commas go to state 78 + primary go to state 79 + string go to state 80 + + + +state 161 + + absdcl1 -> '*' . type_quals absdcl1 (rule 208) + absdcl1 -> '*' . type_quals (rule 209) + + $default reduce using rule 205 (type_quals) + + type_quals go to state 243 + + + +state 162 + + absdcl1 -> '(' . absdcl1 ')' (rule 207) + absdcl1 -> '(' . parmlist (rule 213) + + '*' shift, and go to state 161 + '(' shift, and go to state 162 + '[' shift, and go to state 163 + + $default reduce using rule 275 (@29) + + absdcl1 go to state 244 + parmlist go to state 245 + @29 go to state 246 + + + +state 163 + + absdcl1 -> '[' . expr ']' (rule 214) + absdcl1 -> '[' . ']' (rule 215) + + IDENTIFIER shift, and go to state 59 + CONSTANT shift, and go to state 61 + STRING shift, and go to state 57 + SIZEOF shift, and go to state 62 + ALIGNOF shift, and go to state 63 + '&' shift, and go to state 64 + '+' shift, and go to state 65 + '-' shift, and go to state 66 + '*' shift, and go to state 67 + PLUSPLUS shift, and go to state 68 + MINUSMINUS shift, and go to state 69 + '(' shift, and go to state 70 + '~' shift, and go to state 71 + '!' shift, and go to state 72 + ']' shift, and go to state 247 + + unop go to state 73 + expr go to state 248 + nonnull_exprlist go to state 75 + unary_expr go to state 76 + cast_expr go to state 77 + expr_no_commas go to state 78 + primary go to state 79 + string go to state 80 + + + +state 164 + + typename -> typed_typespecs absdcl . (rule 199) + + $default reduce using rule 199 (typename) + + + +state 165 + + absdcl -> absdcl1 . (rule 202) + absdcl1 -> absdcl1 . '(' parmlist (rule 210) + absdcl1 -> absdcl1 . '[' expr ']' (rule 211) + absdcl1 -> absdcl1 . '[' ']' (rule 212) + + '(' shift, and go to state 249 + '[' shift, and go to state 250 + + $default reduce using rule 202 (absdcl) + + + +state 166 + + typed_typespecs -> typespec reserved_typespecquals . (rule 107) + reserved_typespecquals -> reserved_typespecquals . typespecqual_reserved (rule 110) + + TYPESPEC shift, and go to state 107 + TYPE_QUAL shift, and go to state 108 + ENUM shift, and go to state 9 + STRUCT shift, and go to state 10 + UNION shift, and go to state 11 + + $default reduce using rule 107 (typed_typespecs) + + typespecqual_reserved go to state 251 + structsp go to state 110 + + + +state 167 + + typespec -> TYPEOF '(' typename ')' . (rule 115) + + $default reduce using rule 115 (typespec) + + + +state 168 + + nonempty_type_quals -> nonempty_type_quals TYPE_QUAL . (rule 204) + + $default reduce using rule 204 (nonempty_type_quals) + + + +state 169 + + typed_typespecs -> nonempty_type_quals typespec . reserved_typespecquals (rule 108) + + $default reduce using rule 109 (reserved_typespecquals) + + reserved_typespecquals go to state 252 + + + +state 170 + + typename -> nonempty_type_quals absdcl . (rule 200) + + $default reduce using rule 200 (typename) + + + +state 171 + + type_quals -> type_quals TYPE_QUAL . (rule 206) + + $default reduce using rule 206 (type_quals) + + + +state 172 + + notype_declarator -> notype_declarator . '(' parmlist_or_identifiers (rule 158) + notype_declarator -> '*' type_quals notype_declarator . (rule 160) + notype_declarator -> notype_declarator . '[' expr ']' (rule 161) + notype_declarator -> notype_declarator . '[' ']' (rule 162) + + '(' shift, and go to state 91 + '[' shift, and go to state 92 + + $default reduce using rule 160 (notype_declarator) + + + +state 173 + + notype_declarator -> '(' notype_declarator ')' . (rule 159) + + $default reduce using rule 159 (notype_declarator) + + + +state 174 + + notype_initdecls -> notype_initdecls ',' initdcl . (rule 122) + + $default reduce using rule 122 (notype_initdecls) + + + +state 175 + + initdcl -> declarator . maybeasm maybe_attribute '=' @10 init (rule 126) + initdcl -> declarator . maybeasm maybe_attribute (rule 127) + + ASM shift, and go to state 90 + + $default reduce using rule 123 (maybeasm) + + maybeasm go to state 196 + + + +state 176 + + maybeasm -> ASM '(' . string ')' (rule 124) + + STRING shift, and go to state 57 + + string go to state 253 + + + +state 177 + + notype_declarator -> notype_declarator '(' parmlist_or_identifiers . (rule 158) + + $default reduce using rule 158 (notype_declarator) + + + +state 178 + + parmlist_or_identifiers -> @30 . parmlist_or_identifiers_1 (rule 278) + + error shift, and go to state 254 + IDENTIFIER shift, and go to state 255 + TYPENAME shift, and go to state 5 + SCSPEC shift, and go to state 6 + TYPESPEC shift, and go to state 7 + TYPE_QUAL shift, and go to state 8 + ENUM shift, and go to state 9 + STRUCT shift, and go to state 10 + UNION shift, and go to state 11 + TYPEOF shift, and go to state 13 + + ')' reduce using rule 284 (parmlist_2) + + typed_declspecs go to state 256 + declmods go to state 257 + typespec go to state 21 + structsp go to state 22 + parmlist_or_identifiers_1 go to state 258 + parmlist_2 go to state 259 + parms go to state 260 + parm go to state 261 + identifiers go to state 262 + + + +state 179 + + notype_declarator -> notype_declarator '[' ']' . (rule 162) + + $default reduce using rule 162 (notype_declarator) + + + +state 180 + + notype_declarator -> notype_declarator '[' expr . ']' (rule 161) + + ']' shift, and go to state 263 + + + +state 181 + + errstmt -> error . ';' (rule 221) + + ';' shift, and go to state 264 + + + +state 182 + + fndef -> setspecs notype_declarator @7 xdecls . @8 compstmt_or_error (rule 28) + + $default reduce using rule 27 (@8) + + @8 go to state 265 + + + +state 183 + + xdecls -> decls . (rule 88) + decls -> decls . decl (rule 91) + + TYPENAME shift, and go to state 5 + SCSPEC shift, and go to state 6 + TYPESPEC shift, and go to state 7 + TYPE_QUAL shift, and go to state 8 + ENUM shift, and go to state 9 + STRUCT shift, and go to state 10 + UNION shift, and go to state 11 + TYPEOF shift, and go to state 13 + + $default reduce using rule 88 (xdecls) + + decl go to state 266 + typed_declspecs go to state 185 + declmods go to state 186 + typespec go to state 21 + structsp go to state 22 + + + +state 184 + + decls -> decl . (rule 89) + decls -> decl . errstmt (rule 92) + + error shift, and go to state 181 + + error [reduce using rule 89 (decls)] + IDENTIFIER reduce using rule 89 (decls) + TYPENAME reduce using rule 89 (decls) + SCSPEC reduce using rule 89 (decls) + TYPESPEC reduce using rule 89 (decls) + TYPE_QUAL reduce using rule 89 (decls) + CONSTANT reduce using rule 89 (decls) + STRING reduce using rule 89 (decls) + SIZEOF reduce using rule 89 (decls) + ENUM reduce using rule 89 (decls) + STRUCT reduce using rule 89 (decls) + UNION reduce using rule 89 (decls) + IF reduce using rule 89 (decls) + WHILE reduce using rule 89 (decls) + DO reduce using rule 89 (decls) + FOR reduce using rule 89 (decls) + SWITCH reduce using rule 89 (decls) + CASE reduce using rule 89 (decls) + DEFAULT reduce using rule 89 (decls) + BREAK reduce using rule 89 (decls) + CONTINUE reduce using rule 89 (decls) + RETURN reduce using rule 89 (decls) + GOTO reduce using rule 89 (decls) + ASM reduce using rule 89 (decls) + TYPEOF reduce using rule 89 (decls) + ALIGNOF reduce using rule 89 (decls) + '&' reduce using rule 89 (decls) + '+' reduce using rule 89 (decls) + '-' reduce using rule 89 (decls) + '*' reduce using rule 89 (decls) + PLUSPLUS reduce using rule 89 (decls) + MINUSMINUS reduce using rule 89 (decls) + '(' reduce using rule 89 (decls) + ';' reduce using rule 89 (decls) + '}' reduce using rule 89 (decls) + '~' reduce using rule 89 (decls) + '!' reduce using rule 89 (decls) + '{' reduce using rule 89 (decls) + + errstmt go to state 267 + + + +state 185 + + decl -> typed_declspecs . setspecs initdecls ';' (rule 94) + decl -> typed_declspecs . ';' (rule 96) + + ';' shift, and go to state 268 + + $default reduce using rule 93 (setspecs) + + setspecs go to state 269 + + + +state 186 + + decl -> declmods . setspecs notype_initdecls ';' (rule 95) + decl -> declmods . ';' (rule 97) + typed_declspecs -> declmods . typespec reserved_declspecs (rule 99) + declmods -> declmods . TYPE_QUAL (rule 105) + declmods -> declmods . SCSPEC (rule 106) + + TYPENAME shift, and go to state 5 + SCSPEC shift, and go to state 44 + TYPESPEC shift, and go to state 7 + TYPE_QUAL shift, and go to state 45 + ENUM shift, and go to state 9 + STRUCT shift, and go to state 10 + UNION shift, and go to state 11 + TYPEOF shift, and go to state 13 + ';' shift, and go to state 270 + + $default reduce using rule 93 (setspecs) + + setspecs go to state 271 + typespec go to state 48 + structsp go to state 22 + + + +state 187 + + decls -> errstmt . (rule 90) + + $default reduce using rule 90 (decls) + + + +state 188 + + maybe_attribute -> ATTRIBUTE . '(' '(' attribute_list ')' ')' (rule 132) + + '(' shift, and go to state 272 + + + +state 189 + + notype_initdcl -> notype_declarator maybeasm maybe_attribute . '=' @11 init (rule 129) + notype_initdcl -> notype_declarator maybeasm maybe_attribute . (rule 130) + + '=' shift, and go to state 273 + + $default reduce using rule 130 (notype_initdcl) + + + +state 190 + + after_type_declarator -> '*' type_quals . after_type_declarator (rule 151) + notype_declarator -> '*' type_quals . notype_declarator (rule 160) + type_quals -> type_quals . TYPE_QUAL (rule 206) + + IDENTIFIER shift, and go to state 36 + TYPENAME shift, and go to state 95 + TYPE_QUAL shift, and go to state 171 + '*' shift, and go to state 96 + '(' shift, and go to state 97 + + after_type_declarator go to state 274 + notype_declarator go to state 172 + + + +state 191 + + after_type_declarator -> '(' after_type_declarator . ')' (rule 147) + after_type_declarator -> after_type_declarator . '(' parmlist_or_identifiers (rule 148) + after_type_declarator -> after_type_declarator . '[' expr ']' (rule 149) + after_type_declarator -> after_type_declarator . '[' ']' (rule 150) + + '(' shift, and go to state 197 + '[' shift, and go to state 198 + ')' shift, and go to state 275 + + + +state 192 + + datadef -> typed_declspecs setspecs initdecls ';' . (rule 12) + + $default reduce using rule 12 (datadef) + + + +state 193 + + initdecls -> initdecls ',' . initdcl (rule 120) + + IDENTIFIER shift, and go to state 36 + TYPENAME shift, and go to state 95 + '*' shift, and go to state 96 + '(' shift, and go to state 97 + + initdcl go to state 276 + declarator go to state 175 + after_type_declarator go to state 101 + notype_declarator go to state 102 + + + +state 194 + + fndef -> typed_declspecs setspecs declarator error . (rule 21) + + $default reduce using rule 21 (fndef) + + + +state 195 + + fndef -> typed_declspecs setspecs declarator @3 . xdecls @4 compstmt_or_error (rule 20) + + error shift, and go to state 181 + TYPENAME shift, and go to state 5 + SCSPEC shift, and go to state 6 + TYPESPEC shift, and go to state 7 + TYPE_QUAL shift, and go to state 8 + ENUM shift, and go to state 9 + STRUCT shift, and go to state 10 + UNION shift, and go to state 11 + TYPEOF shift, and go to state 13 + + error [reduce using rule 87 (xdecls)] + '{' reduce using rule 87 (xdecls) + + xdecls go to state 277 + decls go to state 183 + decl go to state 184 + typed_declspecs go to state 185 + declmods go to state 186 + typespec go to state 21 + structsp go to state 22 + errstmt go to state 187 + + + +state 196 + + initdcl -> declarator maybeasm . maybe_attribute '=' @10 init (rule 126) + initdcl -> declarator maybeasm . maybe_attribute (rule 127) + + ATTRIBUTE shift, and go to state 188 + + $default reduce using rule 131 (maybe_attribute) + + maybe_attribute go to state 278 + + + +state 197 + + after_type_declarator -> after_type_declarator '(' . parmlist_or_identifiers (rule 148) + + $default reduce using rule 277 (@30) + + parmlist_or_identifiers go to state 279 + @30 go to state 178 + + + +state 198 + + after_type_declarator -> after_type_declarator '[' . expr ']' (rule 149) + after_type_declarator -> after_type_declarator '[' . ']' (rule 150) + + IDENTIFIER shift, and go to state 59 + CONSTANT shift, and go to state 61 + STRING shift, and go to state 57 + SIZEOF shift, and go to state 62 + ALIGNOF shift, and go to state 63 + '&' shift, and go to state 64 + '+' shift, and go to state 65 + '-' shift, and go to state 66 + '*' shift, and go to state 67 + PLUSPLUS shift, and go to state 68 + MINUSMINUS shift, and go to state 69 + '(' shift, and go to state 70 + '~' shift, and go to state 71 + '!' shift, and go to state 72 + ']' shift, and go to state 280 + + unop go to state 73 + expr go to state 281 + nonnull_exprlist go to state 75 + unary_expr go to state 76 + cast_expr go to state 77 + expr_no_commas go to state 78 + primary go to state 79 + string go to state 80 + + + +state 199 + + datadef -> declmods setspecs notype_initdecls ';' . (rule 11) + + $default reduce using rule 11 (datadef) + + + +state 200 + + fndef -> declmods setspecs notype_declarator error . (rule 25) + + $default reduce using rule 25 (fndef) + + + +state 201 + + fndef -> declmods setspecs notype_declarator @5 . xdecls @6 compstmt_or_error (rule 24) + + error shift, and go to state 181 + TYPENAME shift, and go to state 5 + SCSPEC shift, and go to state 6 + TYPESPEC shift, and go to state 7 + TYPE_QUAL shift, and go to state 8 + ENUM shift, and go to state 9 + STRUCT shift, and go to state 10 + UNION shift, and go to state 11 + TYPEOF shift, and go to state 13 + + error [reduce using rule 87 (xdecls)] + '{' reduce using rule 87 (xdecls) + + xdecls go to state 282 + decls go to state 183 + decl go to state 184 + typed_declspecs go to state 185 + declmods go to state 186 + typespec go to state 21 + structsp go to state 22 + errstmt go to state 187 + + + +state 202 + + enumerator -> identifier '=' . expr_no_commas (rule 198) + + IDENTIFIER shift, and go to state 59 + CONSTANT shift, and go to state 61 + STRING shift, and go to state 57 + SIZEOF shift, and go to state 62 + ALIGNOF shift, and go to state 63 + '&' shift, and go to state 64 + '+' shift, and go to state 65 + '-' shift, and go to state 66 + '*' shift, and go to state 67 + PLUSPLUS shift, and go to state 68 + MINUSMINUS shift, and go to state 69 + '(' shift, and go to state 70 + '~' shift, and go to state 71 + '!' shift, and go to state 72 + + unop go to state 73 + unary_expr go to state 76 + cast_expr go to state 77 + expr_no_commas go to state 283 + primary go to state 79 + string go to state 80 + + + +state 203 + + maybecomma_warn -> ',' . (rule 180) + enumlist -> enumlist ',' . enumerator (rule 196) + + IDENTIFIER shift, and go to state 26 + TYPENAME shift, and go to state 27 + + $default reduce using rule 180 (maybecomma_warn) + + identifier go to state 111 + enumerator go to state 284 + + + +state 204 + + structsp -> ENUM '{' @15 enumlist maybecomma_warn . '}' (rule 175) + + '}' shift, and go to state 285 + + + +state 205 + + structsp -> ENUM identifier '{' @14 enumlist . maybecomma_warn '}' (rule 173) + enumlist -> enumlist . ',' enumerator (rule 196) + + ',' shift, and go to state 203 + + $default reduce using rule 179 (maybecomma_warn) + + maybecomma_warn go to state 286 + + + +state 206 + + component_decl -> typed_typespecs setspecs . components (rule 186) + + IDENTIFIER shift, and go to state 36 + TYPENAME shift, and go to state 95 + ':' shift, and go to state 287 + '*' shift, and go to state 96 + '(' shift, and go to state 97 + + $default reduce using rule 189 (components) + + declarator go to state 288 + after_type_declarator go to state 101 + notype_declarator go to state 102 + components go to state 289 + component_declarator go to state 290 + + + +state 207 + + component_decl_list2 -> component_decl_list2 component_decl ';' . (rule 184) + + $default reduce using rule 184 (component_decl_list2) + + + +state 208 + + component_decl -> nonempty_type_quals setspecs . components (rule 187) + + IDENTIFIER shift, and go to state 36 + TYPENAME shift, and go to state 95 + ':' shift, and go to state 287 + '*' shift, and go to state 96 + '(' shift, and go to state 97 + + $default reduce using rule 189 (components) + + declarator go to state 288 + after_type_declarator go to state 101 + notype_declarator go to state 102 + components go to state 291 + component_declarator go to state 290 + + + +state 209 + + structsp -> STRUCT identifier '{' @12 component_decl_list . '}' (rule 165) + + '}' shift, and go to state 292 + + + +state 210 + + structsp -> UNION identifier '{' @13 component_decl_list . '}' (rule 169) + + '}' shift, and go to state 293 + + + +state 211 + + extdef -> ASM '(' string ')' ';' . (rule 9) + + $default reduce using rule 9 (extdef) + + + +state 212 + + unary_expr -> SIZEOF '(' typename . ')' (rule 48) + + ')' shift, and go to state 294 + + + +state 213 + + unary_expr -> ALIGNOF '(' typename . ')' (rule 50) + + ')' shift, and go to state 295 + + + +state 214 + + primary -> '(' error ')' . (rule 76) + + $default reduce using rule 76 (primary) + + + +state 215 + + primary -> '(' expr ')' . (rule 75) + + $default reduce using rule 75 (primary) + + + +state 216 + + compstmt -> '{' . '}' (rule 225) + compstmt -> '{' . pushlevel decls xstmts '}' (rule 226) + compstmt -> '{' . pushlevel error '}' (rule 227) + compstmt -> '{' . pushlevel stmts '}' (rule 228) + + '}' shift, and go to state 296 + + $default reduce using rule 222 (pushlevel) + + pushlevel go to state 297 + + + +state 217 + + primary -> '(' @9 compstmt . ')' (rule 78) + + ')' shift, and go to state 298 + + + +state 218 + + cast_expr -> '(' typename ')' . cast_expr (rule 52) + cast_expr -> '(' typename ')' . '{' initlist maybecomma '}' (rule 53) + + IDENTIFIER shift, and go to state 59 + CONSTANT shift, and go to state 61 + STRING shift, and go to state 57 + SIZEOF shift, and go to state 62 + ALIGNOF shift, and go to state 63 + '&' shift, and go to state 64 + '+' shift, and go to state 65 + '-' shift, and go to state 66 + '*' shift, and go to state 67 + PLUSPLUS shift, and go to state 68 + MINUSMINUS shift, and go to state 69 + '(' shift, and go to state 70 + '~' shift, and go to state 71 + '!' shift, and go to state 72 + '{' shift, and go to state 299 + + unop go to state 73 + unary_expr go to state 76 + cast_expr go to state 300 + primary go to state 79 + string go to state 80 + + + +state 219 + + nonnull_exprlist -> nonnull_exprlist ',' expr_no_commas . (rule 43) + expr_no_commas -> expr_no_commas . '+' expr_no_commas (rule 55) + expr_no_commas -> expr_no_commas . '-' expr_no_commas (rule 56) + expr_no_commas -> expr_no_commas . '*' expr_no_commas (rule 57) + expr_no_commas -> expr_no_commas . '/' expr_no_commas (rule 58) + expr_no_commas -> expr_no_commas . '%' expr_no_commas (rule 59) + expr_no_commas -> expr_no_commas . LSHIFT expr_no_commas (rule 60) + expr_no_commas -> expr_no_commas . RSHIFT expr_no_commas (rule 61) + expr_no_commas -> expr_no_commas . ARITHCOMPARE expr_no_commas (rule 62) + expr_no_commas -> expr_no_commas . EQCOMPARE expr_no_commas (rule 63) + expr_no_commas -> expr_no_commas . '&' expr_no_commas (rule 64) + expr_no_commas -> expr_no_commas . '|' expr_no_commas (rule 65) + expr_no_commas -> expr_no_commas . '^' expr_no_commas (rule 66) + expr_no_commas -> expr_no_commas . ANDAND expr_no_commas (rule 67) + expr_no_commas -> expr_no_commas . OROR expr_no_commas (rule 68) + expr_no_commas -> expr_no_commas . '?' xexpr ':' expr_no_commas (rule 69) + expr_no_commas -> expr_no_commas . '=' expr_no_commas (rule 70) + expr_no_commas -> expr_no_commas . ASSIGN expr_no_commas (rule 71) + + ASSIGN shift, and go to state 138 + '=' shift, and go to state 139 + '?' shift, and go to state 140 + OROR shift, and go to state 141 + ANDAND shift, and go to state 142 + '|' shift, and go to state 143 + '^' shift, and go to state 144 + '&' shift, and go to state 145 + EQCOMPARE shift, and go to state 146 + ARITHCOMPARE shift, and go to state 147 + LSHIFT shift, and go to state 148 + RSHIFT shift, and go to state 149 + '+' shift, and go to state 150 + '-' shift, and go to state 151 + '*' shift, and go to state 152 + '/' shift, and go to state 153 + '%' shift, and go to state 154 + + $default reduce using rule 43 (nonnull_exprlist) + + + +state 220 + + expr_no_commas -> expr_no_commas . '+' expr_no_commas (rule 55) + expr_no_commas -> expr_no_commas . '-' expr_no_commas (rule 56) + expr_no_commas -> expr_no_commas . '*' expr_no_commas (rule 57) + expr_no_commas -> expr_no_commas . '/' expr_no_commas (rule 58) + expr_no_commas -> expr_no_commas . '%' expr_no_commas (rule 59) + expr_no_commas -> expr_no_commas . LSHIFT expr_no_commas (rule 60) + expr_no_commas -> expr_no_commas . RSHIFT expr_no_commas (rule 61) + expr_no_commas -> expr_no_commas . ARITHCOMPARE expr_no_commas (rule 62) + expr_no_commas -> expr_no_commas . EQCOMPARE expr_no_commas (rule 63) + expr_no_commas -> expr_no_commas . '&' expr_no_commas (rule 64) + expr_no_commas -> expr_no_commas . '|' expr_no_commas (rule 65) + expr_no_commas -> expr_no_commas . '^' expr_no_commas (rule 66) + expr_no_commas -> expr_no_commas . ANDAND expr_no_commas (rule 67) + expr_no_commas -> expr_no_commas . OROR expr_no_commas (rule 68) + expr_no_commas -> expr_no_commas . '?' xexpr ':' expr_no_commas (rule 69) + expr_no_commas -> expr_no_commas . '=' expr_no_commas (rule 70) + expr_no_commas -> expr_no_commas . ASSIGN expr_no_commas (rule 71) + expr_no_commas -> expr_no_commas ASSIGN expr_no_commas . (rule 71) + + ASSIGN shift, and go to state 138 + '=' shift, and go to state 139 + '?' shift, and go to state 140 + OROR shift, and go to state 141 + ANDAND shift, and go to state 142 + '|' shift, and go to state 143 + '^' shift, and go to state 144 + '&' shift, and go to state 145 + EQCOMPARE shift, and go to state 146 + ARITHCOMPARE shift, and go to state 147 + LSHIFT shift, and go to state 148 + RSHIFT shift, and go to state 149 + '+' shift, and go to state 150 + '-' shift, and go to state 151 + '*' shift, and go to state 152 + '/' shift, and go to state 153 + '%' shift, and go to state 154 + + $default reduce using rule 71 (expr_no_commas) + + + +state 221 + + expr_no_commas -> expr_no_commas . '+' expr_no_commas (rule 55) + expr_no_commas -> expr_no_commas . '-' expr_no_commas (rule 56) + expr_no_commas -> expr_no_commas . '*' expr_no_commas (rule 57) + expr_no_commas -> expr_no_commas . '/' expr_no_commas (rule 58) + expr_no_commas -> expr_no_commas . '%' expr_no_commas (rule 59) + expr_no_commas -> expr_no_commas . LSHIFT expr_no_commas (rule 60) + expr_no_commas -> expr_no_commas . RSHIFT expr_no_commas (rule 61) + expr_no_commas -> expr_no_commas . ARITHCOMPARE expr_no_commas (rule 62) + expr_no_commas -> expr_no_commas . EQCOMPARE expr_no_commas (rule 63) + expr_no_commas -> expr_no_commas . '&' expr_no_commas (rule 64) + expr_no_commas -> expr_no_commas . '|' expr_no_commas (rule 65) + expr_no_commas -> expr_no_commas . '^' expr_no_commas (rule 66) + expr_no_commas -> expr_no_commas . ANDAND expr_no_commas (rule 67) + expr_no_commas -> expr_no_commas . OROR expr_no_commas (rule 68) + expr_no_commas -> expr_no_commas . '?' xexpr ':' expr_no_commas (rule 69) + expr_no_commas -> expr_no_commas . '=' expr_no_commas (rule 70) + expr_no_commas -> expr_no_commas '=' expr_no_commas . (rule 70) + expr_no_commas -> expr_no_commas . ASSIGN expr_no_commas (rule 71) + + ASSIGN shift, and go to state 138 + '=' shift, and go to state 139 + '?' shift, and go to state 140 + OROR shift, and go to state 141 + ANDAND shift, and go to state 142 + '|' shift, and go to state 143 + '^' shift, and go to state 144 + '&' shift, and go to state 145 + EQCOMPARE shift, and go to state 146 + ARITHCOMPARE shift, and go to state 147 + LSHIFT shift, and go to state 148 + RSHIFT shift, and go to state 149 + '+' shift, and go to state 150 + '-' shift, and go to state 151 + '*' shift, and go to state 152 + '/' shift, and go to state 153 + '%' shift, and go to state 154 + + $default reduce using rule 70 (expr_no_commas) + + + +state 222 + + xexpr -> expr . (rule 267) + + $default reduce using rule 267 (xexpr) + + + +state 223 + + expr_no_commas -> expr_no_commas '?' xexpr . ':' expr_no_commas (rule 69) + + ':' shift, and go to state 301 + + + +state 224 + + expr_no_commas -> expr_no_commas . '+' expr_no_commas (rule 55) + expr_no_commas -> expr_no_commas . '-' expr_no_commas (rule 56) + expr_no_commas -> expr_no_commas . '*' expr_no_commas (rule 57) + expr_no_commas -> expr_no_commas . '/' expr_no_commas (rule 58) + expr_no_commas -> expr_no_commas . '%' expr_no_commas (rule 59) + expr_no_commas -> expr_no_commas . LSHIFT expr_no_commas (rule 60) + expr_no_commas -> expr_no_commas . RSHIFT expr_no_commas (rule 61) + expr_no_commas -> expr_no_commas . ARITHCOMPARE expr_no_commas (rule 62) + expr_no_commas -> expr_no_commas . EQCOMPARE expr_no_commas (rule 63) + expr_no_commas -> expr_no_commas . '&' expr_no_commas (rule 64) + expr_no_commas -> expr_no_commas . '|' expr_no_commas (rule 65) + expr_no_commas -> expr_no_commas . '^' expr_no_commas (rule 66) + expr_no_commas -> expr_no_commas . ANDAND expr_no_commas (rule 67) + expr_no_commas -> expr_no_commas . OROR expr_no_commas (rule 68) + expr_no_commas -> expr_no_commas OROR expr_no_commas . (rule 68) + expr_no_commas -> expr_no_commas . '?' xexpr ':' expr_no_commas (rule 69) + expr_no_commas -> expr_no_commas . '=' expr_no_commas (rule 70) + expr_no_commas -> expr_no_commas . ASSIGN expr_no_commas (rule 71) + + ANDAND shift, and go to state 142 + '|' shift, and go to state 143 + '^' shift, and go to state 144 + '&' shift, and go to state 145 + EQCOMPARE shift, and go to state 146 + ARITHCOMPARE shift, and go to state 147 + LSHIFT shift, and go to state 148 + RSHIFT shift, and go to state 149 + '+' shift, and go to state 150 + '-' shift, and go to state 151 + '*' shift, and go to state 152 + '/' shift, and go to state 153 + '%' shift, and go to state 154 + + $default reduce using rule 68 (expr_no_commas) + + + +state 225 + + expr_no_commas -> expr_no_commas . '+' expr_no_commas (rule 55) + expr_no_commas -> expr_no_commas . '-' expr_no_commas (rule 56) + expr_no_commas -> expr_no_commas . '*' expr_no_commas (rule 57) + expr_no_commas -> expr_no_commas . '/' expr_no_commas (rule 58) + expr_no_commas -> expr_no_commas . '%' expr_no_commas (rule 59) + expr_no_commas -> expr_no_commas . LSHIFT expr_no_commas (rule 60) + expr_no_commas -> expr_no_commas . RSHIFT expr_no_commas (rule 61) + expr_no_commas -> expr_no_commas . ARITHCOMPARE expr_no_commas (rule 62) + expr_no_commas -> expr_no_commas . EQCOMPARE expr_no_commas (rule 63) + expr_no_commas -> expr_no_commas . '&' expr_no_commas (rule 64) + expr_no_commas -> expr_no_commas . '|' expr_no_commas (rule 65) + expr_no_commas -> expr_no_commas . '^' expr_no_commas (rule 66) + expr_no_commas -> expr_no_commas . ANDAND expr_no_commas (rule 67) + expr_no_commas -> expr_no_commas ANDAND expr_no_commas . (rule 67) + expr_no_commas -> expr_no_commas . OROR expr_no_commas (rule 68) + expr_no_commas -> expr_no_commas . '?' xexpr ':' expr_no_commas (rule 69) + expr_no_commas -> expr_no_commas . '=' expr_no_commas (rule 70) + expr_no_commas -> expr_no_commas . ASSIGN expr_no_commas (rule 71) + + '|' shift, and go to state 143 + '^' shift, and go to state 144 + '&' shift, and go to state 145 + EQCOMPARE shift, and go to state 146 + ARITHCOMPARE shift, and go to state 147 + LSHIFT shift, and go to state 148 + RSHIFT shift, and go to state 149 + '+' shift, and go to state 150 + '-' shift, and go to state 151 + '*' shift, and go to state 152 + '/' shift, and go to state 153 + '%' shift, and go to state 154 + + $default reduce using rule 67 (expr_no_commas) + + + +state 226 + + expr_no_commas -> expr_no_commas . '+' expr_no_commas (rule 55) + expr_no_commas -> expr_no_commas . '-' expr_no_commas (rule 56) + expr_no_commas -> expr_no_commas . '*' expr_no_commas (rule 57) + expr_no_commas -> expr_no_commas . '/' expr_no_commas (rule 58) + expr_no_commas -> expr_no_commas . '%' expr_no_commas (rule 59) + expr_no_commas -> expr_no_commas . LSHIFT expr_no_commas (rule 60) + expr_no_commas -> expr_no_commas . RSHIFT expr_no_commas (rule 61) + expr_no_commas -> expr_no_commas . ARITHCOMPARE expr_no_commas (rule 62) + expr_no_commas -> expr_no_commas . EQCOMPARE expr_no_commas (rule 63) + expr_no_commas -> expr_no_commas . '&' expr_no_commas (rule 64) + expr_no_commas -> expr_no_commas . '|' expr_no_commas (rule 65) + expr_no_commas -> expr_no_commas '|' expr_no_commas . (rule 65) + expr_no_commas -> expr_no_commas . '^' expr_no_commas (rule 66) + expr_no_commas -> expr_no_commas . ANDAND expr_no_commas (rule 67) + expr_no_commas -> expr_no_commas . OROR expr_no_commas (rule 68) + expr_no_commas -> expr_no_commas . '?' xexpr ':' expr_no_commas (rule 69) + expr_no_commas -> expr_no_commas . '=' expr_no_commas (rule 70) + expr_no_commas -> expr_no_commas . ASSIGN expr_no_commas (rule 71) + + '^' shift, and go to state 144 + '&' shift, and go to state 145 + EQCOMPARE shift, and go to state 146 + ARITHCOMPARE shift, and go to state 147 + LSHIFT shift, and go to state 148 + RSHIFT shift, and go to state 149 + '+' shift, and go to state 150 + '-' shift, and go to state 151 + '*' shift, and go to state 152 + '/' shift, and go to state 153 + '%' shift, and go to state 154 + + $default reduce using rule 65 (expr_no_commas) + + + +state 227 + + expr_no_commas -> expr_no_commas . '+' expr_no_commas (rule 55) + expr_no_commas -> expr_no_commas . '-' expr_no_commas (rule 56) + expr_no_commas -> expr_no_commas . '*' expr_no_commas (rule 57) + expr_no_commas -> expr_no_commas . '/' expr_no_commas (rule 58) + expr_no_commas -> expr_no_commas . '%' expr_no_commas (rule 59) + expr_no_commas -> expr_no_commas . LSHIFT expr_no_commas (rule 60) + expr_no_commas -> expr_no_commas . RSHIFT expr_no_commas (rule 61) + expr_no_commas -> expr_no_commas . ARITHCOMPARE expr_no_commas (rule 62) + expr_no_commas -> expr_no_commas . EQCOMPARE expr_no_commas (rule 63) + expr_no_commas -> expr_no_commas . '&' expr_no_commas (rule 64) + expr_no_commas -> expr_no_commas . '|' expr_no_commas (rule 65) + expr_no_commas -> expr_no_commas . '^' expr_no_commas (rule 66) + expr_no_commas -> expr_no_commas '^' expr_no_commas . (rule 66) + expr_no_commas -> expr_no_commas . ANDAND expr_no_commas (rule 67) + expr_no_commas -> expr_no_commas . OROR expr_no_commas (rule 68) + expr_no_commas -> expr_no_commas . '?' xexpr ':' expr_no_commas (rule 69) + expr_no_commas -> expr_no_commas . '=' expr_no_commas (rule 70) + expr_no_commas -> expr_no_commas . ASSIGN expr_no_commas (rule 71) + + '&' shift, and go to state 145 + EQCOMPARE shift, and go to state 146 + ARITHCOMPARE shift, and go to state 147 + LSHIFT shift, and go to state 148 + RSHIFT shift, and go to state 149 + '+' shift, and go to state 150 + '-' shift, and go to state 151 + '*' shift, and go to state 152 + '/' shift, and go to state 153 + '%' shift, and go to state 154 + + $default reduce using rule 66 (expr_no_commas) + + + +state 228 + + expr_no_commas -> expr_no_commas . '+' expr_no_commas (rule 55) + expr_no_commas -> expr_no_commas . '-' expr_no_commas (rule 56) + expr_no_commas -> expr_no_commas . '*' expr_no_commas (rule 57) + expr_no_commas -> expr_no_commas . '/' expr_no_commas (rule 58) + expr_no_commas -> expr_no_commas . '%' expr_no_commas (rule 59) + expr_no_commas -> expr_no_commas . LSHIFT expr_no_commas (rule 60) + expr_no_commas -> expr_no_commas . RSHIFT expr_no_commas (rule 61) + expr_no_commas -> expr_no_commas . ARITHCOMPARE expr_no_commas (rule 62) + expr_no_commas -> expr_no_commas . EQCOMPARE expr_no_commas (rule 63) + expr_no_commas -> expr_no_commas . '&' expr_no_commas (rule 64) + expr_no_commas -> expr_no_commas '&' expr_no_commas . (rule 64) + expr_no_commas -> expr_no_commas . '|' expr_no_commas (rule 65) + expr_no_commas -> expr_no_commas . '^' expr_no_commas (rule 66) + expr_no_commas -> expr_no_commas . ANDAND expr_no_commas (rule 67) + expr_no_commas -> expr_no_commas . OROR expr_no_commas (rule 68) + expr_no_commas -> expr_no_commas . '?' xexpr ':' expr_no_commas (rule 69) + expr_no_commas -> expr_no_commas . '=' expr_no_commas (rule 70) + expr_no_commas -> expr_no_commas . ASSIGN expr_no_commas (rule 71) + + EQCOMPARE shift, and go to state 146 + ARITHCOMPARE shift, and go to state 147 + LSHIFT shift, and go to state 148 + RSHIFT shift, and go to state 149 + '+' shift, and go to state 150 + '-' shift, and go to state 151 + '*' shift, and go to state 152 + '/' shift, and go to state 153 + '%' shift, and go to state 154 + + $default reduce using rule 64 (expr_no_commas) + + + +state 229 + + expr_no_commas -> expr_no_commas . '+' expr_no_commas (rule 55) + expr_no_commas -> expr_no_commas . '-' expr_no_commas (rule 56) + expr_no_commas -> expr_no_commas . '*' expr_no_commas (rule 57) + expr_no_commas -> expr_no_commas . '/' expr_no_commas (rule 58) + expr_no_commas -> expr_no_commas . '%' expr_no_commas (rule 59) + expr_no_commas -> expr_no_commas . LSHIFT expr_no_commas (rule 60) + expr_no_commas -> expr_no_commas . RSHIFT expr_no_commas (rule 61) + expr_no_commas -> expr_no_commas . ARITHCOMPARE expr_no_commas (rule 62) + expr_no_commas -> expr_no_commas . EQCOMPARE expr_no_commas (rule 63) + expr_no_commas -> expr_no_commas EQCOMPARE expr_no_commas . (rule 63) + expr_no_commas -> expr_no_commas . '&' expr_no_commas (rule 64) + expr_no_commas -> expr_no_commas . '|' expr_no_commas (rule 65) + expr_no_commas -> expr_no_commas . '^' expr_no_commas (rule 66) + expr_no_commas -> expr_no_commas . ANDAND expr_no_commas (rule 67) + expr_no_commas -> expr_no_commas . OROR expr_no_commas (rule 68) + expr_no_commas -> expr_no_commas . '?' xexpr ':' expr_no_commas (rule 69) + expr_no_commas -> expr_no_commas . '=' expr_no_commas (rule 70) + expr_no_commas -> expr_no_commas . ASSIGN expr_no_commas (rule 71) + + ARITHCOMPARE shift, and go to state 147 + LSHIFT shift, and go to state 148 + RSHIFT shift, and go to state 149 + '+' shift, and go to state 150 + '-' shift, and go to state 151 + '*' shift, and go to state 152 + '/' shift, and go to state 153 + '%' shift, and go to state 154 + + $default reduce using rule 63 (expr_no_commas) + + + +state 230 + + expr_no_commas -> expr_no_commas . '+' expr_no_commas (rule 55) + expr_no_commas -> expr_no_commas . '-' expr_no_commas (rule 56) + expr_no_commas -> expr_no_commas . '*' expr_no_commas (rule 57) + expr_no_commas -> expr_no_commas . '/' expr_no_commas (rule 58) + expr_no_commas -> expr_no_commas . '%' expr_no_commas (rule 59) + expr_no_commas -> expr_no_commas . LSHIFT expr_no_commas (rule 60) + expr_no_commas -> expr_no_commas . RSHIFT expr_no_commas (rule 61) + expr_no_commas -> expr_no_commas . ARITHCOMPARE expr_no_commas (rule 62) + expr_no_commas -> expr_no_commas ARITHCOMPARE expr_no_commas . (rule 62) + expr_no_commas -> expr_no_commas . EQCOMPARE expr_no_commas (rule 63) + expr_no_commas -> expr_no_commas . '&' expr_no_commas (rule 64) + expr_no_commas -> expr_no_commas . '|' expr_no_commas (rule 65) + expr_no_commas -> expr_no_commas . '^' expr_no_commas (rule 66) + expr_no_commas -> expr_no_commas . ANDAND expr_no_commas (rule 67) + expr_no_commas -> expr_no_commas . OROR expr_no_commas (rule 68) + expr_no_commas -> expr_no_commas . '?' xexpr ':' expr_no_commas (rule 69) + expr_no_commas -> expr_no_commas . '=' expr_no_commas (rule 70) + expr_no_commas -> expr_no_commas . ASSIGN expr_no_commas (rule 71) + + LSHIFT shift, and go to state 148 + RSHIFT shift, and go to state 149 + '+' shift, and go to state 150 + '-' shift, and go to state 151 + '*' shift, and go to state 152 + '/' shift, and go to state 153 + '%' shift, and go to state 154 + + $default reduce using rule 62 (expr_no_commas) + + + +state 231 + + expr_no_commas -> expr_no_commas . '+' expr_no_commas (rule 55) + expr_no_commas -> expr_no_commas . '-' expr_no_commas (rule 56) + expr_no_commas -> expr_no_commas . '*' expr_no_commas (rule 57) + expr_no_commas -> expr_no_commas . '/' expr_no_commas (rule 58) + expr_no_commas -> expr_no_commas . '%' expr_no_commas (rule 59) + expr_no_commas -> expr_no_commas . LSHIFT expr_no_commas (rule 60) + expr_no_commas -> expr_no_commas LSHIFT expr_no_commas . (rule 60) + expr_no_commas -> expr_no_commas . RSHIFT expr_no_commas (rule 61) + expr_no_commas -> expr_no_commas . ARITHCOMPARE expr_no_commas (rule 62) + expr_no_commas -> expr_no_commas . EQCOMPARE expr_no_commas (rule 63) + expr_no_commas -> expr_no_commas . '&' expr_no_commas (rule 64) + expr_no_commas -> expr_no_commas . '|' expr_no_commas (rule 65) + expr_no_commas -> expr_no_commas . '^' expr_no_commas (rule 66) + expr_no_commas -> expr_no_commas . ANDAND expr_no_commas (rule 67) + expr_no_commas -> expr_no_commas . OROR expr_no_commas (rule 68) + expr_no_commas -> expr_no_commas . '?' xexpr ':' expr_no_commas (rule 69) + expr_no_commas -> expr_no_commas . '=' expr_no_commas (rule 70) + expr_no_commas -> expr_no_commas . ASSIGN expr_no_commas (rule 71) + + '+' shift, and go to state 150 + '-' shift, and go to state 151 + '*' shift, and go to state 152 + '/' shift, and go to state 153 + '%' shift, and go to state 154 + + $default reduce using rule 60 (expr_no_commas) + + + +state 232 + + expr_no_commas -> expr_no_commas . '+' expr_no_commas (rule 55) + expr_no_commas -> expr_no_commas . '-' expr_no_commas (rule 56) + expr_no_commas -> expr_no_commas . '*' expr_no_commas (rule 57) + expr_no_commas -> expr_no_commas . '/' expr_no_commas (rule 58) + expr_no_commas -> expr_no_commas . '%' expr_no_commas (rule 59) + expr_no_commas -> expr_no_commas . LSHIFT expr_no_commas (rule 60) + expr_no_commas -> expr_no_commas . RSHIFT expr_no_commas (rule 61) + expr_no_commas -> expr_no_commas RSHIFT expr_no_commas . (rule 61) + expr_no_commas -> expr_no_commas . ARITHCOMPARE expr_no_commas (rule 62) + expr_no_commas -> expr_no_commas . EQCOMPARE expr_no_commas (rule 63) + expr_no_commas -> expr_no_commas . '&' expr_no_commas (rule 64) + expr_no_commas -> expr_no_commas . '|' expr_no_commas (rule 65) + expr_no_commas -> expr_no_commas . '^' expr_no_commas (rule 66) + expr_no_commas -> expr_no_commas . ANDAND expr_no_commas (rule 67) + expr_no_commas -> expr_no_commas . OROR expr_no_commas (rule 68) + expr_no_commas -> expr_no_commas . '?' xexpr ':' expr_no_commas (rule 69) + expr_no_commas -> expr_no_commas . '=' expr_no_commas (rule 70) + expr_no_commas -> expr_no_commas . ASSIGN expr_no_commas (rule 71) + + '+' shift, and go to state 150 + '-' shift, and go to state 151 + '*' shift, and go to state 152 + '/' shift, and go to state 153 + '%' shift, and go to state 154 + + $default reduce using rule 61 (expr_no_commas) + + + +state 233 + + expr_no_commas -> expr_no_commas . '+' expr_no_commas (rule 55) + expr_no_commas -> expr_no_commas '+' expr_no_commas . (rule 55) + expr_no_commas -> expr_no_commas . '-' expr_no_commas (rule 56) + expr_no_commas -> expr_no_commas . '*' expr_no_commas (rule 57) + expr_no_commas -> expr_no_commas . '/' expr_no_commas (rule 58) + expr_no_commas -> expr_no_commas . '%' expr_no_commas (rule 59) + expr_no_commas -> expr_no_commas . LSHIFT expr_no_commas (rule 60) + expr_no_commas -> expr_no_commas . RSHIFT expr_no_commas (rule 61) + expr_no_commas -> expr_no_commas . ARITHCOMPARE expr_no_commas (rule 62) + expr_no_commas -> expr_no_commas . EQCOMPARE expr_no_commas (rule 63) + expr_no_commas -> expr_no_commas . '&' expr_no_commas (rule 64) + expr_no_commas -> expr_no_commas . '|' expr_no_commas (rule 65) + expr_no_commas -> expr_no_commas . '^' expr_no_commas (rule 66) + expr_no_commas -> expr_no_commas . ANDAND expr_no_commas (rule 67) + expr_no_commas -> expr_no_commas . OROR expr_no_commas (rule 68) + expr_no_commas -> expr_no_commas . '?' xexpr ':' expr_no_commas (rule 69) + expr_no_commas -> expr_no_commas . '=' expr_no_commas (rule 70) + expr_no_commas -> expr_no_commas . ASSIGN expr_no_commas (rule 71) + + '*' shift, and go to state 152 + '/' shift, and go to state 153 + '%' shift, and go to state 154 + + $default reduce using rule 55 (expr_no_commas) + + + +state 234 + + expr_no_commas -> expr_no_commas . '+' expr_no_commas (rule 55) + expr_no_commas -> expr_no_commas . '-' expr_no_commas (rule 56) + expr_no_commas -> expr_no_commas '-' expr_no_commas . (rule 56) + expr_no_commas -> expr_no_commas . '*' expr_no_commas (rule 57) + expr_no_commas -> expr_no_commas . '/' expr_no_commas (rule 58) + expr_no_commas -> expr_no_commas . '%' expr_no_commas (rule 59) + expr_no_commas -> expr_no_commas . LSHIFT expr_no_commas (rule 60) + expr_no_commas -> expr_no_commas . RSHIFT expr_no_commas (rule 61) + expr_no_commas -> expr_no_commas . ARITHCOMPARE expr_no_commas (rule 62) + expr_no_commas -> expr_no_commas . EQCOMPARE expr_no_commas (rule 63) + expr_no_commas -> expr_no_commas . '&' expr_no_commas (rule 64) + expr_no_commas -> expr_no_commas . '|' expr_no_commas (rule 65) + expr_no_commas -> expr_no_commas . '^' expr_no_commas (rule 66) + expr_no_commas -> expr_no_commas . ANDAND expr_no_commas (rule 67) + expr_no_commas -> expr_no_commas . OROR expr_no_commas (rule 68) + expr_no_commas -> expr_no_commas . '?' xexpr ':' expr_no_commas (rule 69) + expr_no_commas -> expr_no_commas . '=' expr_no_commas (rule 70) + expr_no_commas -> expr_no_commas . ASSIGN expr_no_commas (rule 71) + + '*' shift, and go to state 152 + '/' shift, and go to state 153 + '%' shift, and go to state 154 + + $default reduce using rule 56 (expr_no_commas) + + + +state 235 + + expr_no_commas -> expr_no_commas . '+' expr_no_commas (rule 55) + expr_no_commas -> expr_no_commas . '-' expr_no_commas (rule 56) + expr_no_commas -> expr_no_commas . '*' expr_no_commas (rule 57) + expr_no_commas -> expr_no_commas '*' expr_no_commas . (rule 57) + expr_no_commas -> expr_no_commas . '/' expr_no_commas (rule 58) + expr_no_commas -> expr_no_commas . '%' expr_no_commas (rule 59) + expr_no_commas -> expr_no_commas . LSHIFT expr_no_commas (rule 60) + expr_no_commas -> expr_no_commas . RSHIFT expr_no_commas (rule 61) + expr_no_commas -> expr_no_commas . ARITHCOMPARE expr_no_commas (rule 62) + expr_no_commas -> expr_no_commas . EQCOMPARE expr_no_commas (rule 63) + expr_no_commas -> expr_no_commas . '&' expr_no_commas (rule 64) + expr_no_commas -> expr_no_commas . '|' expr_no_commas (rule 65) + expr_no_commas -> expr_no_commas . '^' expr_no_commas (rule 66) + expr_no_commas -> expr_no_commas . ANDAND expr_no_commas (rule 67) + expr_no_commas -> expr_no_commas . OROR expr_no_commas (rule 68) + expr_no_commas -> expr_no_commas . '?' xexpr ':' expr_no_commas (rule 69) + expr_no_commas -> expr_no_commas . '=' expr_no_commas (rule 70) + expr_no_commas -> expr_no_commas . ASSIGN expr_no_commas (rule 71) + + + $default reduce using rule 57 (expr_no_commas) + + + +state 236 + + expr_no_commas -> expr_no_commas . '+' expr_no_commas (rule 55) + expr_no_commas -> expr_no_commas . '-' expr_no_commas (rule 56) + expr_no_commas -> expr_no_commas . '*' expr_no_commas (rule 57) + expr_no_commas -> expr_no_commas . '/' expr_no_commas (rule 58) + expr_no_commas -> expr_no_commas '/' expr_no_commas . (rule 58) + expr_no_commas -> expr_no_commas . '%' expr_no_commas (rule 59) + expr_no_commas -> expr_no_commas . LSHIFT expr_no_commas (rule 60) + expr_no_commas -> expr_no_commas . RSHIFT expr_no_commas (rule 61) + expr_no_commas -> expr_no_commas . ARITHCOMPARE expr_no_commas (rule 62) + expr_no_commas -> expr_no_commas . EQCOMPARE expr_no_commas (rule 63) + expr_no_commas -> expr_no_commas . '&' expr_no_commas (rule 64) + expr_no_commas -> expr_no_commas . '|' expr_no_commas (rule 65) + expr_no_commas -> expr_no_commas . '^' expr_no_commas (rule 66) + expr_no_commas -> expr_no_commas . ANDAND expr_no_commas (rule 67) + expr_no_commas -> expr_no_commas . OROR expr_no_commas (rule 68) + expr_no_commas -> expr_no_commas . '?' xexpr ':' expr_no_commas (rule 69) + expr_no_commas -> expr_no_commas . '=' expr_no_commas (rule 70) + expr_no_commas -> expr_no_commas . ASSIGN expr_no_commas (rule 71) + + + $default reduce using rule 58 (expr_no_commas) + + + +state 237 + + expr_no_commas -> expr_no_commas . '+' expr_no_commas (rule 55) + expr_no_commas -> expr_no_commas . '-' expr_no_commas (rule 56) + expr_no_commas -> expr_no_commas . '*' expr_no_commas (rule 57) + expr_no_commas -> expr_no_commas . '/' expr_no_commas (rule 58) + expr_no_commas -> expr_no_commas . '%' expr_no_commas (rule 59) + expr_no_commas -> expr_no_commas '%' expr_no_commas . (rule 59) + expr_no_commas -> expr_no_commas . LSHIFT expr_no_commas (rule 60) + expr_no_commas -> expr_no_commas . RSHIFT expr_no_commas (rule 61) + expr_no_commas -> expr_no_commas . ARITHCOMPARE expr_no_commas (rule 62) + expr_no_commas -> expr_no_commas . EQCOMPARE expr_no_commas (rule 63) + expr_no_commas -> expr_no_commas . '&' expr_no_commas (rule 64) + expr_no_commas -> expr_no_commas . '|' expr_no_commas (rule 65) + expr_no_commas -> expr_no_commas . '^' expr_no_commas (rule 66) + expr_no_commas -> expr_no_commas . ANDAND expr_no_commas (rule 67) + expr_no_commas -> expr_no_commas . OROR expr_no_commas (rule 68) + expr_no_commas -> expr_no_commas . '?' xexpr ':' expr_no_commas (rule 69) + expr_no_commas -> expr_no_commas . '=' expr_no_commas (rule 70) + expr_no_commas -> expr_no_commas . ASSIGN expr_no_commas (rule 71) + + + $default reduce using rule 59 (expr_no_commas) + + + +state 238 + + primary -> primary POINTSAT identifier . (rule 82) + + $default reduce using rule 82 (primary) + + + +state 239 + + primary -> primary '.' identifier . (rule 81) + + $default reduce using rule 81 (primary) + + + +state 240 + + primary -> primary '(' exprlist . ')' (rule 79) + + ')' shift, and go to state 302 + + + +state 241 + + exprlist -> nonnull_exprlist . (rule 41) + nonnull_exprlist -> nonnull_exprlist . ',' expr_no_commas (rule 43) + + ',' shift, and go to state 137 + + $default reduce using rule 41 (exprlist) + + + +state 242 + + primary -> primary '[' expr . ']' (rule 80) + + ']' shift, and go to state 303 + + + +state 243 + + type_quals -> type_quals . TYPE_QUAL (rule 206) + absdcl1 -> '*' type_quals . absdcl1 (rule 208) + absdcl1 -> '*' type_quals . (rule 209) + + TYPE_QUAL shift, and go to state 171 + '*' shift, and go to state 161 + '(' shift, and go to state 162 + '[' shift, and go to state 163 + + $default reduce using rule 209 (absdcl1) + + absdcl1 go to state 304 + + + +state 244 + + absdcl1 -> '(' absdcl1 . ')' (rule 207) + absdcl1 -> absdcl1 . '(' parmlist (rule 210) + absdcl1 -> absdcl1 . '[' expr ']' (rule 211) + absdcl1 -> absdcl1 . '[' ']' (rule 212) + + '(' shift, and go to state 249 + '[' shift, and go to state 250 + ')' shift, and go to state 305 + + + +state 245 + + absdcl1 -> '(' parmlist . (rule 213) + + $default reduce using rule 213 (absdcl1) + + + +state 246 + + parmlist -> @29 . parmlist_1 (rule 276) + + error shift, and go to state 306 + TYPENAME shift, and go to state 5 + SCSPEC shift, and go to state 6 + TYPESPEC shift, and go to state 7 + TYPE_QUAL shift, and go to state 8 + ENUM shift, and go to state 9 + STRUCT shift, and go to state 10 + UNION shift, and go to state 11 + TYPEOF shift, and go to state 13 + + ')' reduce using rule 284 (parmlist_2) + + typed_declspecs go to state 256 + declmods go to state 257 + typespec go to state 21 + structsp go to state 22 + parmlist_1 go to state 307 + parmlist_2 go to state 308 + parms go to state 260 + parm go to state 261 + + + +state 247 + + absdcl1 -> '[' ']' . (rule 215) + + $default reduce using rule 215 (absdcl1) + + + +state 248 + + absdcl1 -> '[' expr . ']' (rule 214) + + ']' shift, and go to state 309 + + + +state 249 + + absdcl1 -> absdcl1 '(' . parmlist (rule 210) + + $default reduce using rule 275 (@29) + + parmlist go to state 310 + @29 go to state 246 + + + +state 250 + + absdcl1 -> absdcl1 '[' . expr ']' (rule 211) + absdcl1 -> absdcl1 '[' . ']' (rule 212) + + IDENTIFIER shift, and go to state 59 + CONSTANT shift, and go to state 61 + STRING shift, and go to state 57 + SIZEOF shift, and go to state 62 + ALIGNOF shift, and go to state 63 + '&' shift, and go to state 64 + '+' shift, and go to state 65 + '-' shift, and go to state 66 + '*' shift, and go to state 67 + PLUSPLUS shift, and go to state 68 + MINUSMINUS shift, and go to state 69 + '(' shift, and go to state 70 + '~' shift, and go to state 71 + '!' shift, and go to state 72 + ']' shift, and go to state 311 + + unop go to state 73 + expr go to state 312 + nonnull_exprlist go to state 75 + unary_expr go to state 76 + cast_expr go to state 77 + expr_no_commas go to state 78 + primary go to state 79 + string go to state 80 + + + +state 251 + + reserved_typespecquals -> reserved_typespecquals typespecqual_reserved . (rule 110) + + $default reduce using rule 110 (reserved_typespecquals) + + + +state 252 + + typed_typespecs -> nonempty_type_quals typespec reserved_typespecquals . (rule 108) + reserved_typespecquals -> reserved_typespecquals . typespecqual_reserved (rule 110) + + TYPESPEC shift, and go to state 107 + TYPE_QUAL shift, and go to state 108 + ENUM shift, and go to state 9 + STRUCT shift, and go to state 10 + UNION shift, and go to state 11 + + $default reduce using rule 108 (typed_typespecs) + + typespecqual_reserved go to state 251 + structsp go to state 110 + + + +state 253 + + string -> string . STRING (rule 86) + maybeasm -> ASM '(' string . ')' (rule 124) + + STRING shift, and go to state 124 + ')' shift, and go to state 313 + + + +state 254 + + parmlist_or_identifiers_1 -> error . ')' (rule 281) + + ')' shift, and go to state 314 + + + +state 255 + + identifiers -> IDENTIFIER . (rule 294) + + $default reduce using rule 294 (identifiers) + + + +state 256 + + parm -> typed_declspecs . parm_declarator (rule 289) + parm -> typed_declspecs . notype_declarator (rule 290) + parm -> typed_declspecs . absdcl (rule 291) + + IDENTIFIER shift, and go to state 36 + TYPENAME shift, and go to state 315 + '*' shift, and go to state 316 + '(' shift, and go to state 317 + '[' shift, and go to state 163 + + $default reduce using rule 201 (absdcl) + + parm_declarator go to state 318 + notype_declarator go to state 319 + absdcl go to state 320 + absdcl1 go to state 165 + + + +state 257 + + typed_declspecs -> declmods . typespec reserved_declspecs (rule 99) + declmods -> declmods . TYPE_QUAL (rule 105) + declmods -> declmods . SCSPEC (rule 106) + parm -> declmods . notype_declarator (rule 292) + parm -> declmods . absdcl (rule 293) + + IDENTIFIER shift, and go to state 36 + TYPENAME shift, and go to state 5 + SCSPEC shift, and go to state 44 + TYPESPEC shift, and go to state 7 + TYPE_QUAL shift, and go to state 45 + ENUM shift, and go to state 9 + STRUCT shift, and go to state 10 + UNION shift, and go to state 11 + TYPEOF shift, and go to state 13 + '*' shift, and go to state 321 + '(' shift, and go to state 317 + '[' shift, and go to state 163 + + $default reduce using rule 201 (absdcl) + + typespec go to state 48 + notype_declarator go to state 322 + structsp go to state 22 + absdcl go to state 323 + absdcl1 go to state 165 + + + +state 258 + + parmlist_or_identifiers -> @30 parmlist_or_identifiers_1 . (rule 278) + + $default reduce using rule 278 (parmlist_or_identifiers) + + + +state 259 + + parmlist_or_identifiers_1 -> parmlist_2 . ')' (rule 279) + + ')' shift, and go to state 324 + + + +state 260 + + parmlist_2 -> parms . (rule 285) + parmlist_2 -> parms . ',' ELLIPSIS (rule 286) + parms -> parms . ',' parm (rule 288) + + ',' shift, and go to state 325 + + $default reduce using rule 285 (parmlist_2) + + + +state 261 + + parms -> parm . (rule 287) + + $default reduce using rule 287 (parms) + + + +state 262 + + parmlist_or_identifiers_1 -> identifiers . ')' (rule 280) + identifiers -> identifiers . ',' IDENTIFIER (rule 295) + + ')' shift, and go to state 326 + ',' shift, and go to state 327 + + + +state 263 + + notype_declarator -> notype_declarator '[' expr ']' . (rule 161) + + $default reduce using rule 161 (notype_declarator) + + + +state 264 + + errstmt -> error ';' . (rule 221) + + $default reduce using rule 221 (errstmt) + + + +state 265 + + fndef -> setspecs notype_declarator @7 xdecls @8 . compstmt_or_error (rule 28) + + error shift, and go to state 328 + '{' shift, and go to state 216 + + compstmt_or_error go to state 329 + compstmt go to state 330 + + + +state 266 + + decls -> decls decl . (rule 91) + + $default reduce using rule 91 (decls) + + + +state 267 + + decls -> decl errstmt . (rule 92) + + $default reduce using rule 92 (decls) + + + +state 268 + + decl -> typed_declspecs ';' . (rule 96) + + $default reduce using rule 96 (decl) + + + +state 269 + + decl -> typed_declspecs setspecs . initdecls ';' (rule 94) + + IDENTIFIER shift, and go to state 36 + TYPENAME shift, and go to state 95 + '*' shift, and go to state 96 + '(' shift, and go to state 97 + + initdecls go to state 331 + initdcl go to state 99 + declarator go to state 175 + after_type_declarator go to state 101 + notype_declarator go to state 102 + + + +state 270 + + decl -> declmods ';' . (rule 97) + + $default reduce using rule 97 (decl) + + + +state 271 + + decl -> declmods setspecs . notype_initdecls ';' (rule 95) + + IDENTIFIER shift, and go to state 36 + '*' shift, and go to state 37 + '(' shift, and go to state 38 + + notype_initdecls go to state 332 + notype_initdcl go to state 40 + notype_declarator go to state 333 + + + +state 272 + + maybe_attribute -> ATTRIBUTE '(' . '(' attribute_list ')' ')' (rule 132) + + '(' shift, and go to state 334 + + + +state 273 + + notype_initdcl -> notype_declarator maybeasm maybe_attribute '=' . @11 init (rule 129) + + $default reduce using rule 128 (@11) + + @11 go to state 335 + + + +state 274 + + after_type_declarator -> after_type_declarator . '(' parmlist_or_identifiers (rule 148) + after_type_declarator -> after_type_declarator . '[' expr ']' (rule 149) + after_type_declarator -> after_type_declarator . '[' ']' (rule 150) + after_type_declarator -> '*' type_quals after_type_declarator . (rule 151) + + '(' shift, and go to state 197 + '[' shift, and go to state 198 + + $default reduce using rule 151 (after_type_declarator) + + + +state 275 + + after_type_declarator -> '(' after_type_declarator ')' . (rule 147) + + $default reduce using rule 147 (after_type_declarator) + + + +state 276 + + initdecls -> initdecls ',' initdcl . (rule 120) + + $default reduce using rule 120 (initdecls) + + + +state 277 + + fndef -> typed_declspecs setspecs declarator @3 xdecls . @4 compstmt_or_error (rule 20) + + $default reduce using rule 19 (@4) + + @4 go to state 336 + + + +state 278 + + initdcl -> declarator maybeasm maybe_attribute . '=' @10 init (rule 126) + initdcl -> declarator maybeasm maybe_attribute . (rule 127) + + '=' shift, and go to state 337 + + $default reduce using rule 127 (initdcl) + + + +state 279 + + after_type_declarator -> after_type_declarator '(' parmlist_or_identifiers . (rule 148) + + $default reduce using rule 148 (after_type_declarator) + + + +state 280 + + after_type_declarator -> after_type_declarator '[' ']' . (rule 150) + + $default reduce using rule 150 (after_type_declarator) + + + +state 281 + + after_type_declarator -> after_type_declarator '[' expr . ']' (rule 149) + + ']' shift, and go to state 338 + + + +state 282 + + fndef -> declmods setspecs notype_declarator @5 xdecls . @6 compstmt_or_error (rule 24) + + $default reduce using rule 23 (@6) + + @6 go to state 339 + + + +state 283 + + expr_no_commas -> expr_no_commas . '+' expr_no_commas (rule 55) + expr_no_commas -> expr_no_commas . '-' expr_no_commas (rule 56) + expr_no_commas -> expr_no_commas . '*' expr_no_commas (rule 57) + expr_no_commas -> expr_no_commas . '/' expr_no_commas (rule 58) + expr_no_commas -> expr_no_commas . '%' expr_no_commas (rule 59) + expr_no_commas -> expr_no_commas . LSHIFT expr_no_commas (rule 60) + expr_no_commas -> expr_no_commas . RSHIFT expr_no_commas (rule 61) + expr_no_commas -> expr_no_commas . ARITHCOMPARE expr_no_commas (rule 62) + expr_no_commas -> expr_no_commas . EQCOMPARE expr_no_commas (rule 63) + expr_no_commas -> expr_no_commas . '&' expr_no_commas (rule 64) + expr_no_commas -> expr_no_commas . '|' expr_no_commas (rule 65) + expr_no_commas -> expr_no_commas . '^' expr_no_commas (rule 66) + expr_no_commas -> expr_no_commas . ANDAND expr_no_commas (rule 67) + expr_no_commas -> expr_no_commas . OROR expr_no_commas (rule 68) + expr_no_commas -> expr_no_commas . '?' xexpr ':' expr_no_commas (rule 69) + expr_no_commas -> expr_no_commas . '=' expr_no_commas (rule 70) + expr_no_commas -> expr_no_commas . ASSIGN expr_no_commas (rule 71) + enumerator -> identifier '=' expr_no_commas . (rule 198) + + ASSIGN shift, and go to state 138 + '=' shift, and go to state 139 + '?' shift, and go to state 140 + OROR shift, and go to state 141 + ANDAND shift, and go to state 142 + '|' shift, and go to state 143 + '^' shift, and go to state 144 + '&' shift, and go to state 145 + EQCOMPARE shift, and go to state 146 + ARITHCOMPARE shift, and go to state 147 + LSHIFT shift, and go to state 148 + RSHIFT shift, and go to state 149 + '+' shift, and go to state 150 + '-' shift, and go to state 151 + '*' shift, and go to state 152 + '/' shift, and go to state 153 + '%' shift, and go to state 154 + + $default reduce using rule 198 (enumerator) + + + +state 284 + + enumlist -> enumlist ',' enumerator . (rule 196) + + $default reduce using rule 196 (enumlist) + + + +state 285 + + structsp -> ENUM '{' @15 enumlist maybecomma_warn '}' . (rule 175) + + $default reduce using rule 175 (structsp) + + + +state 286 + + structsp -> ENUM identifier '{' @14 enumlist maybecomma_warn . '}' (rule 173) + + '}' shift, and go to state 340 + + + +state 287 + + component_declarator -> ':' . expr_no_commas (rule 194) + + IDENTIFIER shift, and go to state 59 + CONSTANT shift, and go to state 61 + STRING shift, and go to state 57 + SIZEOF shift, and go to state 62 + ALIGNOF shift, and go to state 63 + '&' shift, and go to state 64 + '+' shift, and go to state 65 + '-' shift, and go to state 66 + '*' shift, and go to state 67 + PLUSPLUS shift, and go to state 68 + MINUSMINUS shift, and go to state 69 + '(' shift, and go to state 70 + '~' shift, and go to state 71 + '!' shift, and go to state 72 + + unop go to state 73 + unary_expr go to state 76 + cast_expr go to state 77 + expr_no_commas go to state 341 + primary go to state 79 + string go to state 80 + + + +state 288 + + component_declarator -> declarator . maybe_attribute (rule 192) + component_declarator -> declarator . ':' expr_no_commas maybe_attribute (rule 193) + + ATTRIBUTE shift, and go to state 188 + ':' shift, and go to state 342 + + $default reduce using rule 131 (maybe_attribute) + + maybe_attribute go to state 343 + + + +state 289 + + component_decl -> typed_typespecs setspecs components . (rule 186) + components -> components . ',' component_declarator (rule 191) + + ',' shift, and go to state 344 + + $default reduce using rule 186 (component_decl) + + + +state 290 + + components -> component_declarator . (rule 190) + + $default reduce using rule 190 (components) + + + +state 291 + + component_decl -> nonempty_type_quals setspecs components . (rule 187) + components -> components . ',' component_declarator (rule 191) + + ',' shift, and go to state 344 + + $default reduce using rule 187 (component_decl) + + + +state 292 + + structsp -> STRUCT identifier '{' @12 component_decl_list '}' . (rule 165) + + $default reduce using rule 165 (structsp) + + + +state 293 + + structsp -> UNION identifier '{' @13 component_decl_list '}' . (rule 169) + + $default reduce using rule 169 (structsp) + + + +state 294 + + unary_expr -> SIZEOF '(' typename ')' . (rule 48) + + $default reduce using rule 48 (unary_expr) + + + +state 295 + + unary_expr -> ALIGNOF '(' typename ')' . (rule 50) + + $default reduce using rule 50 (unary_expr) + + + +state 296 + + compstmt -> '{' '}' . (rule 225) + + $default reduce using rule 225 (compstmt) + + + +state 297 + + compstmt -> '{' pushlevel . decls xstmts '}' (rule 226) + compstmt -> '{' pushlevel . error '}' (rule 227) + compstmt -> '{' pushlevel . stmts '}' (rule 228) + + error shift, and go to state 345 + IDENTIFIER shift, and go to state 346 + TYPENAME shift, and go to state 347 + SCSPEC shift, and go to state 6 + TYPESPEC shift, and go to state 7 + TYPE_QUAL shift, and go to state 8 + CONSTANT shift, and go to state 61 + STRING shift, and go to state 57 + SIZEOF shift, and go to state 62 + ENUM shift, and go to state 9 + STRUCT shift, and go to state 10 + UNION shift, and go to state 11 + IF shift, and go to state 348 + WHILE shift, and go to state 349 + DO shift, and go to state 350 + FOR shift, and go to state 351 + SWITCH shift, and go to state 352 + CASE shift, and go to state 353 + DEFAULT shift, and go to state 354 + BREAK shift, and go to state 355 + CONTINUE shift, and go to state 356 + RETURN shift, and go to state 357 + GOTO shift, and go to state 358 + ASM shift, and go to state 359 + TYPEOF shift, and go to state 13 + ALIGNOF shift, and go to state 63 + '&' shift, and go to state 64 + '+' shift, and go to state 65 + '-' shift, and go to state 66 + '*' shift, and go to state 67 + PLUSPLUS shift, and go to state 68 + MINUSMINUS shift, and go to state 69 + '(' shift, and go to state 70 + ';' shift, and go to state 360 + '~' shift, and go to state 71 + '!' shift, and go to state 72 + '{' shift, and go to state 216 + + identifier go to state 361 + unop go to state 73 + expr go to state 362 + nonnull_exprlist go to state 75 + unary_expr go to state 76 + cast_expr go to state 77 + expr_no_commas go to state 78 + primary go to state 79 + string go to state 80 + decls go to state 363 + decl go to state 184 + typed_declspecs go to state 185 + declmods go to state 186 + typespec go to state 21 + structsp go to state 22 + stmts go to state 364 + errstmt go to state 187 + compstmt go to state 365 + simple_if go to state 366 + stmt go to state 367 + + + +state 298 + + primary -> '(' @9 compstmt ')' . (rule 78) + + $default reduce using rule 78 (primary) + + + +state 299 + + cast_expr -> '(' typename ')' '{' . initlist maybecomma '}' (rule 53) + + error shift, and go to state 368 + IDENTIFIER shift, and go to state 59 + CONSTANT shift, and go to state 61 + STRING shift, and go to state 57 + SIZEOF shift, and go to state 62 + ALIGNOF shift, and go to state 63 + '&' shift, and go to state 64 + '+' shift, and go to state 65 + '-' shift, and go to state 66 + '*' shift, and go to state 67 + PLUSPLUS shift, and go to state 68 + MINUSMINUS shift, and go to state 69 + '(' shift, and go to state 70 + '~' shift, and go to state 71 + '!' shift, and go to state 72 + '{' shift, and go to state 369 + + unop go to state 73 + unary_expr go to state 76 + cast_expr go to state 77 + expr_no_commas go to state 370 + primary go to state 79 + string go to state 80 + init go to state 371 + initlist go to state 372 + + + +state 300 + + cast_expr -> '(' typename ')' cast_expr . (rule 52) + + $default reduce using rule 52 (cast_expr) + + + +state 301 + + expr_no_commas -> expr_no_commas '?' xexpr ':' . expr_no_commas (rule 69) + + IDENTIFIER shift, and go to state 59 + CONSTANT shift, and go to state 61 + STRING shift, and go to state 57 + SIZEOF shift, and go to state 62 + ALIGNOF shift, and go to state 63 + '&' shift, and go to state 64 + '+' shift, and go to state 65 + '-' shift, and go to state 66 + '*' shift, and go to state 67 + PLUSPLUS shift, and go to state 68 + MINUSMINUS shift, and go to state 69 + '(' shift, and go to state 70 + '~' shift, and go to state 71 + '!' shift, and go to state 72 + + unop go to state 73 + unary_expr go to state 76 + cast_expr go to state 77 + expr_no_commas go to state 373 + primary go to state 79 + string go to state 80 + + + +state 302 + + primary -> primary '(' exprlist ')' . (rule 79) + + $default reduce using rule 79 (primary) + + + +state 303 + + primary -> primary '[' expr ']' . (rule 80) + + $default reduce using rule 80 (primary) + + + +state 304 + + absdcl1 -> '*' type_quals absdcl1 . (rule 208) + absdcl1 -> absdcl1 . '(' parmlist (rule 210) + absdcl1 -> absdcl1 . '[' expr ']' (rule 211) + absdcl1 -> absdcl1 . '[' ']' (rule 212) + + '(' shift, and go to state 249 + '[' shift, and go to state 250 + + $default reduce using rule 208 (absdcl1) + + + +state 305 + + absdcl1 -> '(' absdcl1 ')' . (rule 207) + + $default reduce using rule 207 (absdcl1) + + + +state 306 + + parmlist_1 -> error . ')' (rule 283) + + ')' shift, and go to state 374 + + + +state 307 + + parmlist -> @29 parmlist_1 . (rule 276) + + $default reduce using rule 276 (parmlist) + + + +state 308 + + parmlist_1 -> parmlist_2 . ')' (rule 282) + + ')' shift, and go to state 375 + + + +state 309 + + absdcl1 -> '[' expr ']' . (rule 214) + + $default reduce using rule 214 (absdcl1) + + + +state 310 + + absdcl1 -> absdcl1 '(' parmlist . (rule 210) + + $default reduce using rule 210 (absdcl1) + + + +state 311 + + absdcl1 -> absdcl1 '[' ']' . (rule 212) + + $default reduce using rule 212 (absdcl1) + + + +state 312 + + absdcl1 -> absdcl1 '[' expr . ']' (rule 211) + + ']' shift, and go to state 376 + + + +state 313 + + maybeasm -> ASM '(' string ')' . (rule 124) + + $default reduce using rule 124 (maybeasm) + + + +state 314 + + parmlist_or_identifiers_1 -> error ')' . (rule 281) + + $default reduce using rule 281 (parmlist_or_identifiers_1) + + + +state 315 + + parm_declarator -> TYPENAME . (rule 157) + + $default reduce using rule 157 (parm_declarator) + + + +state 316 + + parm_declarator -> '*' . type_quals parm_declarator (rule 156) + notype_declarator -> '*' . type_quals notype_declarator (rule 160) + absdcl1 -> '*' . type_quals absdcl1 (rule 208) + absdcl1 -> '*' . type_quals (rule 209) + + $default reduce using rule 205 (type_quals) + + type_quals go to state 377 + + + +state 317 + + notype_declarator -> '(' . notype_declarator ')' (rule 159) + absdcl1 -> '(' . absdcl1 ')' (rule 207) + absdcl1 -> '(' . parmlist (rule 213) + + IDENTIFIER shift, and go to state 36 + '*' shift, and go to state 321 + '(' shift, and go to state 317 + '[' shift, and go to state 163 + + $default reduce using rule 275 (@29) + + notype_declarator go to state 86 + absdcl1 go to state 244 + parmlist go to state 245 + @29 go to state 246 + + + +state 318 + + parm_declarator -> parm_declarator . '(' parmlist_or_identifiers (rule 153) + parm_declarator -> parm_declarator . '[' expr ']' (rule 154) + parm_declarator -> parm_declarator . '[' ']' (rule 155) + parm -> typed_declspecs parm_declarator . (rule 289) + + '(' shift, and go to state 378 + '[' shift, and go to state 379 + + $default reduce using rule 289 (parm) + + + +state 319 + + notype_declarator -> notype_declarator . '(' parmlist_or_identifiers (rule 158) + notype_declarator -> notype_declarator . '[' expr ']' (rule 161) + notype_declarator -> notype_declarator . '[' ']' (rule 162) + parm -> typed_declspecs notype_declarator . (rule 290) + + '(' shift, and go to state 91 + '[' shift, and go to state 92 + + $default reduce using rule 290 (parm) + + + +state 320 + + parm -> typed_declspecs absdcl . (rule 291) + + $default reduce using rule 291 (parm) + + + +state 321 + + notype_declarator -> '*' . type_quals notype_declarator (rule 160) + absdcl1 -> '*' . type_quals absdcl1 (rule 208) + absdcl1 -> '*' . type_quals (rule 209) + + $default reduce using rule 205 (type_quals) + + type_quals go to state 380 + + + +state 322 + + notype_declarator -> notype_declarator . '(' parmlist_or_identifiers (rule 158) + notype_declarator -> notype_declarator . '[' expr ']' (rule 161) + notype_declarator -> notype_declarator . '[' ']' (rule 162) + parm -> declmods notype_declarator . (rule 292) + + '(' shift, and go to state 91 + '[' shift, and go to state 92 + + $default reduce using rule 292 (parm) + + + +state 323 + + parm -> declmods absdcl . (rule 293) + + $default reduce using rule 293 (parm) + + + +state 324 + + parmlist_or_identifiers_1 -> parmlist_2 ')' . (rule 279) + + $default reduce using rule 279 (parmlist_or_identifiers_1) + + + +state 325 + + parmlist_2 -> parms ',' . ELLIPSIS (rule 286) + parms -> parms ',' . parm (rule 288) + + TYPENAME shift, and go to state 5 + SCSPEC shift, and go to state 6 + TYPESPEC shift, and go to state 7 + TYPE_QUAL shift, and go to state 8 + ELLIPSIS shift, and go to state 381 + ENUM shift, and go to state 9 + STRUCT shift, and go to state 10 + UNION shift, and go to state 11 + TYPEOF shift, and go to state 13 + + typed_declspecs go to state 256 + declmods go to state 257 + typespec go to state 21 + structsp go to state 22 + parm go to state 382 + + + +state 326 + + parmlist_or_identifiers_1 -> identifiers ')' . (rule 280) + + $default reduce using rule 280 (parmlist_or_identifiers_1) + + + +state 327 + + identifiers -> identifiers ',' . IDENTIFIER (rule 295) + + IDENTIFIER shift, and go to state 383 + + + +state 328 + + compstmt_or_error -> error . compstmt (rule 224) + + '{' shift, and go to state 216 + + compstmt go to state 384 + + + +state 329 + + fndef -> setspecs notype_declarator @7 xdecls @8 compstmt_or_error . (rule 28) + + $default reduce using rule 28 (fndef) + + + +state 330 + + compstmt_or_error -> compstmt . (rule 223) + + $default reduce using rule 223 (compstmt_or_error) + + + +state 331 + + decl -> typed_declspecs setspecs initdecls . ';' (rule 94) + initdecls -> initdecls . ',' initdcl (rule 120) + + ';' shift, and go to state 385 + ',' shift, and go to state 193 + + + +state 332 + + decl -> declmods setspecs notype_initdecls . ';' (rule 95) + notype_initdecls -> notype_initdecls . ',' initdcl (rule 122) + + ';' shift, and go to state 386 + ',' shift, and go to state 88 + + + +state 333 + + notype_initdcl -> notype_declarator . maybeasm maybe_attribute '=' @11 init (rule 129) + notype_initdcl -> notype_declarator . maybeasm maybe_attribute (rule 130) + notype_declarator -> notype_declarator . '(' parmlist_or_identifiers (rule 158) + notype_declarator -> notype_declarator . '[' expr ']' (rule 161) + notype_declarator -> notype_declarator . '[' ']' (rule 162) + + ASM shift, and go to state 90 + '(' shift, and go to state 91 + '[' shift, and go to state 92 + + $default reduce using rule 123 (maybeasm) + + maybeasm go to state 94 + + + +state 334 + + maybe_attribute -> ATTRIBUTE '(' '(' . attribute_list ')' ')' (rule 132) + + IDENTIFIER shift, and go to state 387 + + attribute_list go to state 388 + attrib go to state 389 + + + +state 335 + + notype_initdcl -> notype_declarator maybeasm maybe_attribute '=' @11 . init (rule 129) + + error shift, and go to state 368 + IDENTIFIER shift, and go to state 59 + CONSTANT shift, and go to state 61 + STRING shift, and go to state 57 + SIZEOF shift, and go to state 62 + ALIGNOF shift, and go to state 63 + '&' shift, and go to state 64 + '+' shift, and go to state 65 + '-' shift, and go to state 66 + '*' shift, and go to state 67 + PLUSPLUS shift, and go to state 68 + MINUSMINUS shift, and go to state 69 + '(' shift, and go to state 70 + '~' shift, and go to state 71 + '!' shift, and go to state 72 + '{' shift, and go to state 369 + + unop go to state 73 + unary_expr go to state 76 + cast_expr go to state 77 + expr_no_commas go to state 370 + primary go to state 79 + string go to state 80 + init go to state 390 + + + +state 336 + + fndef -> typed_declspecs setspecs declarator @3 xdecls @4 . compstmt_or_error (rule 20) + + error shift, and go to state 328 + '{' shift, and go to state 216 + + compstmt_or_error go to state 391 + compstmt go to state 330 + + + +state 337 + + initdcl -> declarator maybeasm maybe_attribute '=' . @10 init (rule 126) + + $default reduce using rule 125 (@10) + + @10 go to state 392 + + + +state 338 + + after_type_declarator -> after_type_declarator '[' expr ']' . (rule 149) + + $default reduce using rule 149 (after_type_declarator) + + + +state 339 + + fndef -> declmods setspecs notype_declarator @5 xdecls @6 . compstmt_or_error (rule 24) + + error shift, and go to state 328 + '{' shift, and go to state 216 + + compstmt_or_error go to state 393 + compstmt go to state 330 + + + +state 340 + + structsp -> ENUM identifier '{' @14 enumlist maybecomma_warn '}' . (rule 173) + + $default reduce using rule 173 (structsp) + + + +state 341 + + expr_no_commas -> expr_no_commas . '+' expr_no_commas (rule 55) + expr_no_commas -> expr_no_commas . '-' expr_no_commas (rule 56) + expr_no_commas -> expr_no_commas . '*' expr_no_commas (rule 57) + expr_no_commas -> expr_no_commas . '/' expr_no_commas (rule 58) + expr_no_commas -> expr_no_commas . '%' expr_no_commas (rule 59) + expr_no_commas -> expr_no_commas . LSHIFT expr_no_commas (rule 60) + expr_no_commas -> expr_no_commas . RSHIFT expr_no_commas (rule 61) + expr_no_commas -> expr_no_commas . ARITHCOMPARE expr_no_commas (rule 62) + expr_no_commas -> expr_no_commas . EQCOMPARE expr_no_commas (rule 63) + expr_no_commas -> expr_no_commas . '&' expr_no_commas (rule 64) + expr_no_commas -> expr_no_commas . '|' expr_no_commas (rule 65) + expr_no_commas -> expr_no_commas . '^' expr_no_commas (rule 66) + expr_no_commas -> expr_no_commas . ANDAND expr_no_commas (rule 67) + expr_no_commas -> expr_no_commas . OROR expr_no_commas (rule 68) + expr_no_commas -> expr_no_commas . '?' xexpr ':' expr_no_commas (rule 69) + expr_no_commas -> expr_no_commas . '=' expr_no_commas (rule 70) + expr_no_commas -> expr_no_commas . ASSIGN expr_no_commas (rule 71) + component_declarator -> ':' expr_no_commas . (rule 194) + + ASSIGN shift, and go to state 138 + '=' shift, and go to state 139 + '?' shift, and go to state 140 + OROR shift, and go to state 141 + ANDAND shift, and go to state 142 + '|' shift, and go to state 143 + '^' shift, and go to state 144 + '&' shift, and go to state 145 + EQCOMPARE shift, and go to state 146 + ARITHCOMPARE shift, and go to state 147 + LSHIFT shift, and go to state 148 + RSHIFT shift, and go to state 149 + '+' shift, and go to state 150 + '-' shift, and go to state 151 + '*' shift, and go to state 152 + '/' shift, and go to state 153 + '%' shift, and go to state 154 + + $default reduce using rule 194 (component_declarator) + + + +state 342 + + component_declarator -> declarator ':' . expr_no_commas maybe_attribute (rule 193) + + IDENTIFIER shift, and go to state 59 + CONSTANT shift, and go to state 61 + STRING shift, and go to state 57 + SIZEOF shift, and go to state 62 + ALIGNOF shift, and go to state 63 + '&' shift, and go to state 64 + '+' shift, and go to state 65 + '-' shift, and go to state 66 + '*' shift, and go to state 67 + PLUSPLUS shift, and go to state 68 + MINUSMINUS shift, and go to state 69 + '(' shift, and go to state 70 + '~' shift, and go to state 71 + '!' shift, and go to state 72 + + unop go to state 73 + unary_expr go to state 76 + cast_expr go to state 77 + expr_no_commas go to state 394 + primary go to state 79 + string go to state 80 + + + +state 343 + + component_declarator -> declarator maybe_attribute . (rule 192) + + $default reduce using rule 192 (component_declarator) + + + +state 344 + + components -> components ',' . component_declarator (rule 191) + + IDENTIFIER shift, and go to state 36 + TYPENAME shift, and go to state 95 + ':' shift, and go to state 287 + '*' shift, and go to state 96 + '(' shift, and go to state 97 + + declarator go to state 288 + after_type_declarator go to state 101 + notype_declarator go to state 102 + component_declarator go to state 395 + + + +state 345 + + errstmt -> error . ';' (rule 221) + compstmt -> '{' pushlevel error . '}' (rule 227) + + ';' shift, and go to state 264 + '}' shift, and go to state 396 + + + +state 346 + + identifier -> IDENTIFIER . (rule 30) + primary -> IDENTIFIER . (rule 72) + + ':' reduce using rule 30 (identifier) + $default reduce using rule 72 (primary) + + + +state 347 + + identifier -> TYPENAME . (rule 31) + typespec -> TYPENAME . (rule 113) + + ':' reduce using rule 31 (identifier) + $default reduce using rule 113 (typespec) + + + +state 348 + + simple_if -> IF . '(' expr ')' @16 stmt (rule 230) + + '(' shift, and go to state 397 + + + +state 349 + + stmt -> WHILE . @18 '(' expr ')' @19 stmt (rule 238) + + $default reduce using rule 236 (@18) + + @18 go to state 398 + + + +state 350 + + stmt -> DO . @20 stmt WHILE @21 '(' expr ')' ';' (rule 241) + + $default reduce using rule 239 (@20) + + @20 go to state 399 + + + +state 351 + + stmt -> FOR . '(' xexpr ';' @22 xexpr ';' @23 xexpr ')' @24 stmt (rule 245) + + '(' shift, and go to state 400 + + + +state 352 + + stmt -> SWITCH . '(' expr ')' @25 stmt (rule 247) + + '(' shift, and go to state 401 + + + +state 353 + + stmt -> CASE . expr ':' @26 stmt (rule 249) + + IDENTIFIER shift, and go to state 59 + CONSTANT shift, and go to state 61 + STRING shift, and go to state 57 + SIZEOF shift, and go to state 62 + ALIGNOF shift, and go to state 63 + '&' shift, and go to state 64 + '+' shift, and go to state 65 + '-' shift, and go to state 66 + '*' shift, and go to state 67 + PLUSPLUS shift, and go to state 68 + MINUSMINUS shift, and go to state 69 + '(' shift, and go to state 70 + '~' shift, and go to state 71 + '!' shift, and go to state 72 + + unop go to state 73 + expr go to state 402 + nonnull_exprlist go to state 75 + unary_expr go to state 76 + cast_expr go to state 77 + expr_no_commas go to state 78 + primary go to state 79 + string go to state 80 + + + +state 354 + + stmt -> DEFAULT . ':' @27 stmt (rule 251) + + ':' shift, and go to state 403 + + + +state 355 + + stmt -> BREAK . ';' (rule 252) + + ';' shift, and go to state 404 + + + +state 356 + + stmt -> CONTINUE . ';' (rule 253) + + ';' shift, and go to state 405 + + + +state 357 + + stmt -> RETURN . ';' (rule 254) + stmt -> RETURN . expr ';' (rule 255) + + IDENTIFIER shift, and go to state 59 + CONSTANT shift, and go to state 61 + STRING shift, and go to state 57 + SIZEOF shift, and go to state 62 + ALIGNOF shift, and go to state 63 + '&' shift, and go to state 64 + '+' shift, and go to state 65 + '-' shift, and go to state 66 + '*' shift, and go to state 67 + PLUSPLUS shift, and go to state 68 + MINUSMINUS shift, and go to state 69 + '(' shift, and go to state 70 + ';' shift, and go to state 406 + '~' shift, and go to state 71 + '!' shift, and go to state 72 + + unop go to state 73 + expr go to state 407 + nonnull_exprlist go to state 75 + unary_expr go to state 76 + cast_expr go to state 77 + expr_no_commas go to state 78 + primary go to state 79 + string go to state 80 + + + +state 358 + + stmt -> GOTO . identifier ';' (rule 260) + + IDENTIFIER shift, and go to state 26 + TYPENAME shift, and go to state 27 + + identifier go to state 408 + + + +state 359 + + stmt -> ASM . maybe_type_qual '(' string ')' ';' (rule 256) + stmt -> ASM . maybe_type_qual '(' string ':' asm_operands ')' ';' (rule 257) + stmt -> ASM . maybe_type_qual '(' string ':' asm_operands ':' asm_operands ')' ';' (rule 258) + stmt -> ASM . maybe_type_qual '(' string ':' asm_operands ':' asm_operands ':' asm_clobbers ')' ';' (rule 259) + + TYPE_QUAL shift, and go to state 409 + + $default reduce using rule 264 (maybe_type_qual) + + maybe_type_qual go to state 410 + + + +state 360 + + stmt -> ';' . (rule 263) + + $default reduce using rule 263 (stmt) + + + +state 361 + + stmt -> identifier . ':' @28 stmt (rule 262) + + ':' shift, and go to state 411 + + + +state 362 + + stmt -> expr . ';' (rule 232) + + ';' shift, and go to state 412 + + + +state 363 + + decls -> decls . decl (rule 91) + compstmt -> '{' pushlevel decls . xstmts '}' (rule 226) + + IDENTIFIER shift, and go to state 346 + TYPENAME shift, and go to state 347 + SCSPEC shift, and go to state 6 + TYPESPEC shift, and go to state 7 + TYPE_QUAL shift, and go to state 8 + CONSTANT shift, and go to state 61 + STRING shift, and go to state 57 + SIZEOF shift, and go to state 62 + ENUM shift, and go to state 9 + STRUCT shift, and go to state 10 + UNION shift, and go to state 11 + IF shift, and go to state 348 + WHILE shift, and go to state 349 + DO shift, and go to state 350 + FOR shift, and go to state 351 + SWITCH shift, and go to state 352 + CASE shift, and go to state 353 + DEFAULT shift, and go to state 354 + BREAK shift, and go to state 355 + CONTINUE shift, and go to state 356 + RETURN shift, and go to state 357 + GOTO shift, and go to state 358 + ASM shift, and go to state 359 + TYPEOF shift, and go to state 13 + ALIGNOF shift, and go to state 63 + '&' shift, and go to state 64 + '+' shift, and go to state 65 + '-' shift, and go to state 66 + '*' shift, and go to state 67 + PLUSPLUS shift, and go to state 68 + MINUSMINUS shift, and go to state 69 + '(' shift, and go to state 70 + ';' shift, and go to state 360 + '~' shift, and go to state 71 + '!' shift, and go to state 72 + '{' shift, and go to state 216 + + $default reduce using rule 219 (xstmts) + + identifier go to state 361 + unop go to state 73 + expr go to state 362 + nonnull_exprlist go to state 75 + unary_expr go to state 76 + cast_expr go to state 77 + expr_no_commas go to state 78 + primary go to state 79 + string go to state 80 + decl go to state 266 + typed_declspecs go to state 185 + declmods go to state 186 + typespec go to state 21 + structsp go to state 22 + stmts go to state 413 + xstmts go to state 414 + compstmt go to state 365 + simple_if go to state 366 + stmt go to state 367 + + + +state 364 + + stmts -> stmts . stmt (rule 217) + stmts -> stmts . errstmt (rule 218) + compstmt -> '{' pushlevel stmts . '}' (rule 228) + + error shift, and go to state 181 + IDENTIFIER shift, and go to state 346 + TYPENAME shift, and go to state 27 + CONSTANT shift, and go to state 61 + STRING shift, and go to state 57 + SIZEOF shift, and go to state 62 + IF shift, and go to state 348 + WHILE shift, and go to state 349 + DO shift, and go to state 350 + FOR shift, and go to state 351 + SWITCH shift, and go to state 352 + CASE shift, and go to state 353 + DEFAULT shift, and go to state 354 + BREAK shift, and go to state 355 + CONTINUE shift, and go to state 356 + RETURN shift, and go to state 357 + GOTO shift, and go to state 358 + ASM shift, and go to state 359 + ALIGNOF shift, and go to state 63 + '&' shift, and go to state 64 + '+' shift, and go to state 65 + '-' shift, and go to state 66 + '*' shift, and go to state 67 + PLUSPLUS shift, and go to state 68 + MINUSMINUS shift, and go to state 69 + '(' shift, and go to state 70 + ';' shift, and go to state 360 + '}' shift, and go to state 415 + '~' shift, and go to state 71 + '!' shift, and go to state 72 + '{' shift, and go to state 216 + + identifier go to state 361 + unop go to state 73 + expr go to state 362 + nonnull_exprlist go to state 75 + unary_expr go to state 76 + cast_expr go to state 77 + expr_no_commas go to state 78 + primary go to state 79 + string go to state 80 + errstmt go to state 416 + compstmt go to state 365 + simple_if go to state 366 + stmt go to state 417 + + + +state 365 + + stmt -> compstmt . (rule 231) + + $default reduce using rule 231 (stmt) + + + +state 366 + + stmt -> simple_if . ELSE @17 stmt (rule 234) + stmt -> simple_if . (rule 235) + + ELSE shift, and go to state 418 + + $default reduce using rule 235 (stmt) + + + +state 367 + + stmts -> stmt . (rule 216) + + $default reduce using rule 216 (stmts) + + + +state 368 + + init -> error . (rule 142) + + $default reduce using rule 142 (init) + + + +state 369 + + init -> '{' . '}' (rule 139) + init -> '{' . initlist '}' (rule 140) + init -> '{' . initlist ',' '}' (rule 141) + + error shift, and go to state 368 + IDENTIFIER shift, and go to state 59 + CONSTANT shift, and go to state 61 + STRING shift, and go to state 57 + SIZEOF shift, and go to state 62 + ALIGNOF shift, and go to state 63 + '&' shift, and go to state 64 + '+' shift, and go to state 65 + '-' shift, and go to state 66 + '*' shift, and go to state 67 + PLUSPLUS shift, and go to state 68 + MINUSMINUS shift, and go to state 69 + '(' shift, and go to state 70 + '}' shift, and go to state 419 + '~' shift, and go to state 71 + '!' shift, and go to state 72 + '{' shift, and go to state 369 + + unop go to state 73 + unary_expr go to state 76 + cast_expr go to state 77 + expr_no_commas go to state 370 + primary go to state 79 + string go to state 80 + init go to state 371 + initlist go to state 420 + + + +state 370 + + expr_no_commas -> expr_no_commas . '+' expr_no_commas (rule 55) + expr_no_commas -> expr_no_commas . '-' expr_no_commas (rule 56) + expr_no_commas -> expr_no_commas . '*' expr_no_commas (rule 57) + expr_no_commas -> expr_no_commas . '/' expr_no_commas (rule 58) + expr_no_commas -> expr_no_commas . '%' expr_no_commas (rule 59) + expr_no_commas -> expr_no_commas . LSHIFT expr_no_commas (rule 60) + expr_no_commas -> expr_no_commas . RSHIFT expr_no_commas (rule 61) + expr_no_commas -> expr_no_commas . ARITHCOMPARE expr_no_commas (rule 62) + expr_no_commas -> expr_no_commas . EQCOMPARE expr_no_commas (rule 63) + expr_no_commas -> expr_no_commas . '&' expr_no_commas (rule 64) + expr_no_commas -> expr_no_commas . '|' expr_no_commas (rule 65) + expr_no_commas -> expr_no_commas . '^' expr_no_commas (rule 66) + expr_no_commas -> expr_no_commas . ANDAND expr_no_commas (rule 67) + expr_no_commas -> expr_no_commas . OROR expr_no_commas (rule 68) + expr_no_commas -> expr_no_commas . '?' xexpr ':' expr_no_commas (rule 69) + expr_no_commas -> expr_no_commas . '=' expr_no_commas (rule 70) + expr_no_commas -> expr_no_commas . ASSIGN expr_no_commas (rule 71) + init -> expr_no_commas . (rule 138) + + ASSIGN shift, and go to state 138 + '=' shift, and go to state 139 + '?' shift, and go to state 140 + OROR shift, and go to state 141 + ANDAND shift, and go to state 142 + '|' shift, and go to state 143 + '^' shift, and go to state 144 + '&' shift, and go to state 145 + EQCOMPARE shift, and go to state 146 + ARITHCOMPARE shift, and go to state 147 + LSHIFT shift, and go to state 148 + RSHIFT shift, and go to state 149 + '+' shift, and go to state 150 + '-' shift, and go to state 151 + '*' shift, and go to state 152 + '/' shift, and go to state 153 + '%' shift, and go to state 154 + + $default reduce using rule 138 (init) + + + +state 371 + + initlist -> init . (rule 143) + + $default reduce using rule 143 (initlist) + + + +state 372 + + cast_expr -> '(' typename ')' '{' initlist . maybecomma '}' (rule 53) + initlist -> initlist . ',' init (rule 144) + + ',' shift, and go to state 421 + + $default reduce using rule 177 (maybecomma) + + maybecomma go to state 422 + + + +state 373 + + expr_no_commas -> expr_no_commas . '+' expr_no_commas (rule 55) + expr_no_commas -> expr_no_commas . '-' expr_no_commas (rule 56) + expr_no_commas -> expr_no_commas . '*' expr_no_commas (rule 57) + expr_no_commas -> expr_no_commas . '/' expr_no_commas (rule 58) + expr_no_commas -> expr_no_commas . '%' expr_no_commas (rule 59) + expr_no_commas -> expr_no_commas . LSHIFT expr_no_commas (rule 60) + expr_no_commas -> expr_no_commas . RSHIFT expr_no_commas (rule 61) + expr_no_commas -> expr_no_commas . ARITHCOMPARE expr_no_commas (rule 62) + expr_no_commas -> expr_no_commas . EQCOMPARE expr_no_commas (rule 63) + expr_no_commas -> expr_no_commas . '&' expr_no_commas (rule 64) + expr_no_commas -> expr_no_commas . '|' expr_no_commas (rule 65) + expr_no_commas -> expr_no_commas . '^' expr_no_commas (rule 66) + expr_no_commas -> expr_no_commas . ANDAND expr_no_commas (rule 67) + expr_no_commas -> expr_no_commas . OROR expr_no_commas (rule 68) + expr_no_commas -> expr_no_commas . '?' xexpr ':' expr_no_commas (rule 69) + expr_no_commas -> expr_no_commas '?' xexpr ':' expr_no_commas . (rule 69) + expr_no_commas -> expr_no_commas . '=' expr_no_commas (rule 70) + expr_no_commas -> expr_no_commas . ASSIGN expr_no_commas (rule 71) + + '?' shift, and go to state 140 + OROR shift, and go to state 141 + ANDAND shift, and go to state 142 + '|' shift, and go to state 143 + '^' shift, and go to state 144 + '&' shift, and go to state 145 + EQCOMPARE shift, and go to state 146 + ARITHCOMPARE shift, and go to state 147 + LSHIFT shift, and go to state 148 + RSHIFT shift, and go to state 149 + '+' shift, and go to state 150 + '-' shift, and go to state 151 + '*' shift, and go to state 152 + '/' shift, and go to state 153 + '%' shift, and go to state 154 + + $default reduce using rule 69 (expr_no_commas) + + + +state 374 + + parmlist_1 -> error ')' . (rule 283) + + $default reduce using rule 283 (parmlist_1) + + + +state 375 + + parmlist_1 -> parmlist_2 ')' . (rule 282) + + $default reduce using rule 282 (parmlist_1) + + + +state 376 + + absdcl1 -> absdcl1 '[' expr ']' . (rule 211) + + $default reduce using rule 211 (absdcl1) + + + +state 377 + + parm_declarator -> '*' type_quals . parm_declarator (rule 156) + notype_declarator -> '*' type_quals . notype_declarator (rule 160) + type_quals -> type_quals . TYPE_QUAL (rule 206) + absdcl1 -> '*' type_quals . absdcl1 (rule 208) + absdcl1 -> '*' type_quals . (rule 209) + + IDENTIFIER shift, and go to state 36 + TYPENAME shift, and go to state 315 + TYPE_QUAL shift, and go to state 171 + '*' shift, and go to state 316 + '(' shift, and go to state 317 + '[' shift, and go to state 163 + + $default reduce using rule 209 (absdcl1) + + parm_declarator go to state 423 + notype_declarator go to state 172 + absdcl1 go to state 304 + + + +state 378 + + parm_declarator -> parm_declarator '(' . parmlist_or_identifiers (rule 153) + + $default reduce using rule 277 (@30) + + parmlist_or_identifiers go to state 424 + @30 go to state 178 + + + +state 379 + + parm_declarator -> parm_declarator '[' . expr ']' (rule 154) + parm_declarator -> parm_declarator '[' . ']' (rule 155) + + IDENTIFIER shift, and go to state 59 + CONSTANT shift, and go to state 61 + STRING shift, and go to state 57 + SIZEOF shift, and go to state 62 + ALIGNOF shift, and go to state 63 + '&' shift, and go to state 64 + '+' shift, and go to state 65 + '-' shift, and go to state 66 + '*' shift, and go to state 67 + PLUSPLUS shift, and go to state 68 + MINUSMINUS shift, and go to state 69 + '(' shift, and go to state 70 + '~' shift, and go to state 71 + '!' shift, and go to state 72 + ']' shift, and go to state 425 + + unop go to state 73 + expr go to state 426 + nonnull_exprlist go to state 75 + unary_expr go to state 76 + cast_expr go to state 77 + expr_no_commas go to state 78 + primary go to state 79 + string go to state 80 + + + +state 380 + + notype_declarator -> '*' type_quals . notype_declarator (rule 160) + type_quals -> type_quals . TYPE_QUAL (rule 206) + absdcl1 -> '*' type_quals . absdcl1 (rule 208) + absdcl1 -> '*' type_quals . (rule 209) + + IDENTIFIER shift, and go to state 36 + TYPE_QUAL shift, and go to state 171 + '*' shift, and go to state 321 + '(' shift, and go to state 317 + '[' shift, and go to state 163 + + $default reduce using rule 209 (absdcl1) + + notype_declarator go to state 172 + absdcl1 go to state 304 + + + +state 381 + + parmlist_2 -> parms ',' ELLIPSIS . (rule 286) + + $default reduce using rule 286 (parmlist_2) + + + +state 382 + + parms -> parms ',' parm . (rule 288) + + $default reduce using rule 288 (parms) + + + +state 383 + + identifiers -> identifiers ',' IDENTIFIER . (rule 295) + + $default reduce using rule 295 (identifiers) + + + +state 384 + + compstmt_or_error -> error compstmt . (rule 224) + + $default reduce using rule 224 (compstmt_or_error) + + + +state 385 + + decl -> typed_declspecs setspecs initdecls ';' . (rule 94) + + $default reduce using rule 94 (decl) + + + +state 386 + + decl -> declmods setspecs notype_initdecls ';' . (rule 95) + + $default reduce using rule 95 (decl) + + + +state 387 + + attrib -> IDENTIFIER . (rule 135) + attrib -> IDENTIFIER . '(' CONSTANT ')' (rule 136) + attrib -> IDENTIFIER . '(' identifiers ')' (rule 137) + + '(' shift, and go to state 427 + + $default reduce using rule 135 (attrib) + + + +state 388 + + maybe_attribute -> ATTRIBUTE '(' '(' attribute_list . ')' ')' (rule 132) + attribute_list -> attribute_list . ',' attrib (rule 134) + + ')' shift, and go to state 428 + ',' shift, and go to state 429 + + + +state 389 + + attribute_list -> attrib . (rule 133) + + $default reduce using rule 133 (attribute_list) + + + +state 390 + + notype_initdcl -> notype_declarator maybeasm maybe_attribute '=' @11 init . (rule 129) + + $default reduce using rule 129 (notype_initdcl) + + + +state 391 + + fndef -> typed_declspecs setspecs declarator @3 xdecls @4 compstmt_or_error . (rule 20) + + $default reduce using rule 20 (fndef) + + + +state 392 + + initdcl -> declarator maybeasm maybe_attribute '=' @10 . init (rule 126) + + error shift, and go to state 368 + IDENTIFIER shift, and go to state 59 + CONSTANT shift, and go to state 61 + STRING shift, and go to state 57 + SIZEOF shift, and go to state 62 + ALIGNOF shift, and go to state 63 + '&' shift, and go to state 64 + '+' shift, and go to state 65 + '-' shift, and go to state 66 + '*' shift, and go to state 67 + PLUSPLUS shift, and go to state 68 + MINUSMINUS shift, and go to state 69 + '(' shift, and go to state 70 + '~' shift, and go to state 71 + '!' shift, and go to state 72 + '{' shift, and go to state 369 + + unop go to state 73 + unary_expr go to state 76 + cast_expr go to state 77 + expr_no_commas go to state 370 + primary go to state 79 + string go to state 80 + init go to state 430 + + + +state 393 + + fndef -> declmods setspecs notype_declarator @5 xdecls @6 compstmt_or_error . (rule 24) + + $default reduce using rule 24 (fndef) + + + +state 394 + + expr_no_commas -> expr_no_commas . '+' expr_no_commas (rule 55) + expr_no_commas -> expr_no_commas . '-' expr_no_commas (rule 56) + expr_no_commas -> expr_no_commas . '*' expr_no_commas (rule 57) + expr_no_commas -> expr_no_commas . '/' expr_no_commas (rule 58) + expr_no_commas -> expr_no_commas . '%' expr_no_commas (rule 59) + expr_no_commas -> expr_no_commas . LSHIFT expr_no_commas (rule 60) + expr_no_commas -> expr_no_commas . RSHIFT expr_no_commas (rule 61) + expr_no_commas -> expr_no_commas . ARITHCOMPARE expr_no_commas (rule 62) + expr_no_commas -> expr_no_commas . EQCOMPARE expr_no_commas (rule 63) + expr_no_commas -> expr_no_commas . '&' expr_no_commas (rule 64) + expr_no_commas -> expr_no_commas . '|' expr_no_commas (rule 65) + expr_no_commas -> expr_no_commas . '^' expr_no_commas (rule 66) + expr_no_commas -> expr_no_commas . ANDAND expr_no_commas (rule 67) + expr_no_commas -> expr_no_commas . OROR expr_no_commas (rule 68) + expr_no_commas -> expr_no_commas . '?' xexpr ':' expr_no_commas (rule 69) + expr_no_commas -> expr_no_commas . '=' expr_no_commas (rule 70) + expr_no_commas -> expr_no_commas . ASSIGN expr_no_commas (rule 71) + component_declarator -> declarator ':' expr_no_commas . maybe_attribute (rule 193) + + ATTRIBUTE shift, and go to state 188 + ASSIGN shift, and go to state 138 + '=' shift, and go to state 139 + '?' shift, and go to state 140 + OROR shift, and go to state 141 + ANDAND shift, and go to state 142 + '|' shift, and go to state 143 + '^' shift, and go to state 144 + '&' shift, and go to state 145 + EQCOMPARE shift, and go to state 146 + ARITHCOMPARE shift, and go to state 147 + LSHIFT shift, and go to state 148 + RSHIFT shift, and go to state 149 + '+' shift, and go to state 150 + '-' shift, and go to state 151 + '*' shift, and go to state 152 + '/' shift, and go to state 153 + '%' shift, and go to state 154 + + $default reduce using rule 131 (maybe_attribute) + + maybe_attribute go to state 431 + + + +state 395 + + components -> components ',' component_declarator . (rule 191) + + $default reduce using rule 191 (components) + + + +state 396 + + compstmt -> '{' pushlevel error '}' . (rule 227) + + $default reduce using rule 227 (compstmt) + + + +state 397 + + simple_if -> IF '(' . expr ')' @16 stmt (rule 230) + + IDENTIFIER shift, and go to state 59 + CONSTANT shift, and go to state 61 + STRING shift, and go to state 57 + SIZEOF shift, and go to state 62 + ALIGNOF shift, and go to state 63 + '&' shift, and go to state 64 + '+' shift, and go to state 65 + '-' shift, and go to state 66 + '*' shift, and go to state 67 + PLUSPLUS shift, and go to state 68 + MINUSMINUS shift, and go to state 69 + '(' shift, and go to state 70 + '~' shift, and go to state 71 + '!' shift, and go to state 72 + + unop go to state 73 + expr go to state 432 + nonnull_exprlist go to state 75 + unary_expr go to state 76 + cast_expr go to state 77 + expr_no_commas go to state 78 + primary go to state 79 + string go to state 80 + + + +state 398 + + stmt -> WHILE @18 . '(' expr ')' @19 stmt (rule 238) + + '(' shift, and go to state 433 + + + +state 399 + + stmt -> DO @20 . stmt WHILE @21 '(' expr ')' ';' (rule 241) + + IDENTIFIER shift, and go to state 346 + TYPENAME shift, and go to state 27 + CONSTANT shift, and go to state 61 + STRING shift, and go to state 57 + SIZEOF shift, and go to state 62 + IF shift, and go to state 348 + WHILE shift, and go to state 349 + DO shift, and go to state 350 + FOR shift, and go to state 351 + SWITCH shift, and go to state 352 + CASE shift, and go to state 353 + DEFAULT shift, and go to state 354 + BREAK shift, and go to state 355 + CONTINUE shift, and go to state 356 + RETURN shift, and go to state 357 + GOTO shift, and go to state 358 + ASM shift, and go to state 359 + ALIGNOF shift, and go to state 63 + '&' shift, and go to state 64 + '+' shift, and go to state 65 + '-' shift, and go to state 66 + '*' shift, and go to state 67 + PLUSPLUS shift, and go to state 68 + MINUSMINUS shift, and go to state 69 + '(' shift, and go to state 70 + ';' shift, and go to state 360 + '~' shift, and go to state 71 + '!' shift, and go to state 72 + '{' shift, and go to state 216 + + identifier go to state 361 + unop go to state 73 + expr go to state 362 + nonnull_exprlist go to state 75 + unary_expr go to state 76 + cast_expr go to state 77 + expr_no_commas go to state 78 + primary go to state 79 + string go to state 80 + compstmt go to state 365 + simple_if go to state 366 + stmt go to state 434 + + + +state 400 + + stmt -> FOR '(' . xexpr ';' @22 xexpr ';' @23 xexpr ')' @24 stmt (rule 245) + + IDENTIFIER shift, and go to state 59 + CONSTANT shift, and go to state 61 + STRING shift, and go to state 57 + SIZEOF shift, and go to state 62 + ALIGNOF shift, and go to state 63 + '&' shift, and go to state 64 + '+' shift, and go to state 65 + '-' shift, and go to state 66 + '*' shift, and go to state 67 + PLUSPLUS shift, and go to state 68 + MINUSMINUS shift, and go to state 69 + '(' shift, and go to state 70 + '~' shift, and go to state 71 + '!' shift, and go to state 72 + + $default reduce using rule 266 (xexpr) + + unop go to state 73 + expr go to state 222 + nonnull_exprlist go to state 75 + unary_expr go to state 76 + cast_expr go to state 77 + expr_no_commas go to state 78 + primary go to state 79 + string go to state 80 + xexpr go to state 435 + + + +state 401 + + stmt -> SWITCH '(' . expr ')' @25 stmt (rule 247) + + IDENTIFIER shift, and go to state 59 + CONSTANT shift, and go to state 61 + STRING shift, and go to state 57 + SIZEOF shift, and go to state 62 + ALIGNOF shift, and go to state 63 + '&' shift, and go to state 64 + '+' shift, and go to state 65 + '-' shift, and go to state 66 + '*' shift, and go to state 67 + PLUSPLUS shift, and go to state 68 + MINUSMINUS shift, and go to state 69 + '(' shift, and go to state 70 + '~' shift, and go to state 71 + '!' shift, and go to state 72 + + unop go to state 73 + expr go to state 436 + nonnull_exprlist go to state 75 + unary_expr go to state 76 + cast_expr go to state 77 + expr_no_commas go to state 78 + primary go to state 79 + string go to state 80 + + + +state 402 + + stmt -> CASE expr . ':' @26 stmt (rule 249) + + ':' shift, and go to state 437 + + + +state 403 + + stmt -> DEFAULT ':' . @27 stmt (rule 251) + + $default reduce using rule 250 (@27) + + @27 go to state 438 + + + +state 404 + + stmt -> BREAK ';' . (rule 252) + + $default reduce using rule 252 (stmt) + + + +state 405 + + stmt -> CONTINUE ';' . (rule 253) + + $default reduce using rule 253 (stmt) + + + +state 406 + + stmt -> RETURN ';' . (rule 254) + + $default reduce using rule 254 (stmt) + + + +state 407 + + stmt -> RETURN expr . ';' (rule 255) + + ';' shift, and go to state 439 + + + +state 408 + + stmt -> GOTO identifier . ';' (rule 260) + + ';' shift, and go to state 440 + + + +state 409 + + maybe_type_qual -> TYPE_QUAL . (rule 265) + + $default reduce using rule 265 (maybe_type_qual) + + + +state 410 + + stmt -> ASM maybe_type_qual . '(' string ')' ';' (rule 256) + stmt -> ASM maybe_type_qual . '(' string ':' asm_operands ')' ';' (rule 257) + stmt -> ASM maybe_type_qual . '(' string ':' asm_operands ':' asm_operands ')' ';' (rule 258) + stmt -> ASM maybe_type_qual . '(' string ':' asm_operands ':' asm_operands ':' asm_clobbers ')' ';' (rule 259) + + '(' shift, and go to state 441 + + + +state 411 + + stmt -> identifier ':' . @28 stmt (rule 262) + + $default reduce using rule 261 (@28) + + @28 go to state 442 + + + +state 412 + + stmt -> expr ';' . (rule 232) + + $default reduce using rule 232 (stmt) + + + +state 413 + + stmts -> stmts . stmt (rule 217) + stmts -> stmts . errstmt (rule 218) + xstmts -> stmts . (rule 220) + + error shift, and go to state 181 + IDENTIFIER shift, and go to state 346 + TYPENAME shift, and go to state 27 + CONSTANT shift, and go to state 61 + STRING shift, and go to state 57 + SIZEOF shift, and go to state 62 + IF shift, and go to state 348 + WHILE shift, and go to state 349 + DO shift, and go to state 350 + FOR shift, and go to state 351 + SWITCH shift, and go to state 352 + CASE shift, and go to state 353 + DEFAULT shift, and go to state 354 + BREAK shift, and go to state 355 + CONTINUE shift, and go to state 356 + RETURN shift, and go to state 357 + GOTO shift, and go to state 358 + ASM shift, and go to state 359 + ALIGNOF shift, and go to state 63 + '&' shift, and go to state 64 + '+' shift, and go to state 65 + '-' shift, and go to state 66 + '*' shift, and go to state 67 + PLUSPLUS shift, and go to state 68 + MINUSMINUS shift, and go to state 69 + '(' shift, and go to state 70 + ';' shift, and go to state 360 + '~' shift, and go to state 71 + '!' shift, and go to state 72 + '{' shift, and go to state 216 + + '}' [reduce using rule 220 (xstmts)] + + identifier go to state 361 + unop go to state 73 + expr go to state 362 + nonnull_exprlist go to state 75 + unary_expr go to state 76 + cast_expr go to state 77 + expr_no_commas go to state 78 + primary go to state 79 + string go to state 80 + errstmt go to state 416 + compstmt go to state 365 + simple_if go to state 366 + stmt go to state 417 + + + +state 414 + + compstmt -> '{' pushlevel decls xstmts . '}' (rule 226) + + '}' shift, and go to state 443 + + + +state 415 + + compstmt -> '{' pushlevel stmts '}' . (rule 228) + + $default reduce using rule 228 (compstmt) + + + +state 416 + + stmts -> stmts errstmt . (rule 218) + + $default reduce using rule 218 (stmts) + + + +state 417 + + stmts -> stmts stmt . (rule 217) + + $default reduce using rule 217 (stmts) + + + +state 418 + + stmt -> simple_if ELSE . @17 stmt (rule 234) + + $default reduce using rule 233 (@17) + + @17 go to state 444 + + + +state 419 + + init -> '{' '}' . (rule 139) + + $default reduce using rule 139 (init) + + + +state 420 + + init -> '{' initlist . '}' (rule 140) + init -> '{' initlist . ',' '}' (rule 141) + initlist -> initlist . ',' init (rule 144) + + '}' shift, and go to state 445 + ',' shift, and go to state 446 + + + +state 421 + + initlist -> initlist ',' . init (rule 144) + maybecomma -> ',' . (rule 178) + + error shift, and go to state 368 + IDENTIFIER shift, and go to state 59 + CONSTANT shift, and go to state 61 + STRING shift, and go to state 57 + SIZEOF shift, and go to state 62 + ALIGNOF shift, and go to state 63 + '&' shift, and go to state 64 + '+' shift, and go to state 65 + '-' shift, and go to state 66 + '*' shift, and go to state 67 + PLUSPLUS shift, and go to state 68 + MINUSMINUS shift, and go to state 69 + '(' shift, and go to state 70 + '~' shift, and go to state 71 + '!' shift, and go to state 72 + '{' shift, and go to state 369 + + '}' reduce using rule 178 (maybecomma) + + unop go to state 73 + unary_expr go to state 76 + cast_expr go to state 77 + expr_no_commas go to state 370 + primary go to state 79 + string go to state 80 + init go to state 447 + + + +state 422 + + cast_expr -> '(' typename ')' '{' initlist maybecomma . '}' (rule 53) + + '}' shift, and go to state 448 + + + +state 423 + + parm_declarator -> parm_declarator . '(' parmlist_or_identifiers (rule 153) + parm_declarator -> parm_declarator . '[' expr ']' (rule 154) + parm_declarator -> parm_declarator . '[' ']' (rule 155) + parm_declarator -> '*' type_quals parm_declarator . (rule 156) + + '(' shift, and go to state 378 + '[' shift, and go to state 379 + + $default reduce using rule 156 (parm_declarator) + + + +state 424 + + parm_declarator -> parm_declarator '(' parmlist_or_identifiers . (rule 153) + + $default reduce using rule 153 (parm_declarator) + + + +state 425 + + parm_declarator -> parm_declarator '[' ']' . (rule 155) + + $default reduce using rule 155 (parm_declarator) + + + +state 426 + + parm_declarator -> parm_declarator '[' expr . ']' (rule 154) + + ']' shift, and go to state 449 + + + +state 427 + + attrib -> IDENTIFIER '(' . CONSTANT ')' (rule 136) + attrib -> IDENTIFIER '(' . identifiers ')' (rule 137) + + IDENTIFIER shift, and go to state 255 + CONSTANT shift, and go to state 450 + + identifiers go to state 451 + + + +state 428 + + maybe_attribute -> ATTRIBUTE '(' '(' attribute_list ')' . ')' (rule 132) + + ')' shift, and go to state 452 + + + +state 429 + + attribute_list -> attribute_list ',' . attrib (rule 134) + + IDENTIFIER shift, and go to state 387 + + attrib go to state 453 + + + +state 430 + + initdcl -> declarator maybeasm maybe_attribute '=' @10 init . (rule 126) + + $default reduce using rule 126 (initdcl) + + + +state 431 + + component_declarator -> declarator ':' expr_no_commas maybe_attribute . (rule 193) + + $default reduce using rule 193 (component_declarator) + + + +state 432 + + simple_if -> IF '(' expr . ')' @16 stmt (rule 230) + + ')' shift, and go to state 454 + + + +state 433 + + stmt -> WHILE @18 '(' . expr ')' @19 stmt (rule 238) + + IDENTIFIER shift, and go to state 59 + CONSTANT shift, and go to state 61 + STRING shift, and go to state 57 + SIZEOF shift, and go to state 62 + ALIGNOF shift, and go to state 63 + '&' shift, and go to state 64 + '+' shift, and go to state 65 + '-' shift, and go to state 66 + '*' shift, and go to state 67 + PLUSPLUS shift, and go to state 68 + MINUSMINUS shift, and go to state 69 + '(' shift, and go to state 70 + '~' shift, and go to state 71 + '!' shift, and go to state 72 + + unop go to state 73 + expr go to state 455 + nonnull_exprlist go to state 75 + unary_expr go to state 76 + cast_expr go to state 77 + expr_no_commas go to state 78 + primary go to state 79 + string go to state 80 + + + +state 434 + + stmt -> DO @20 stmt . WHILE @21 '(' expr ')' ';' (rule 241) + + WHILE shift, and go to state 456 + + + +state 435 + + stmt -> FOR '(' xexpr . ';' @22 xexpr ';' @23 xexpr ')' @24 stmt (rule 245) + + ';' shift, and go to state 457 + + + +state 436 + + stmt -> SWITCH '(' expr . ')' @25 stmt (rule 247) + + ')' shift, and go to state 458 + + + +state 437 + + stmt -> CASE expr ':' . @26 stmt (rule 249) + + $default reduce using rule 248 (@26) + + @26 go to state 459 + + + +state 438 + + stmt -> DEFAULT ':' @27 . stmt (rule 251) + + IDENTIFIER shift, and go to state 346 + TYPENAME shift, and go to state 27 + CONSTANT shift, and go to state 61 + STRING shift, and go to state 57 + SIZEOF shift, and go to state 62 + IF shift, and go to state 348 + WHILE shift, and go to state 349 + DO shift, and go to state 350 + FOR shift, and go to state 351 + SWITCH shift, and go to state 352 + CASE shift, and go to state 353 + DEFAULT shift, and go to state 354 + BREAK shift, and go to state 355 + CONTINUE shift, and go to state 356 + RETURN shift, and go to state 357 + GOTO shift, and go to state 358 + ASM shift, and go to state 359 + ALIGNOF shift, and go to state 63 + '&' shift, and go to state 64 + '+' shift, and go to state 65 + '-' shift, and go to state 66 + '*' shift, and go to state 67 + PLUSPLUS shift, and go to state 68 + MINUSMINUS shift, and go to state 69 + '(' shift, and go to state 70 + ';' shift, and go to state 360 + '~' shift, and go to state 71 + '!' shift, and go to state 72 + '{' shift, and go to state 216 + + identifier go to state 361 + unop go to state 73 + expr go to state 362 + nonnull_exprlist go to state 75 + unary_expr go to state 76 + cast_expr go to state 77 + expr_no_commas go to state 78 + primary go to state 79 + string go to state 80 + compstmt go to state 365 + simple_if go to state 366 + stmt go to state 460 + + + +state 439 + + stmt -> RETURN expr ';' . (rule 255) + + $default reduce using rule 255 (stmt) + + + +state 440 + + stmt -> GOTO identifier ';' . (rule 260) + + $default reduce using rule 260 (stmt) + + + +state 441 + + stmt -> ASM maybe_type_qual '(' . string ')' ';' (rule 256) + stmt -> ASM maybe_type_qual '(' . string ':' asm_operands ')' ';' (rule 257) + stmt -> ASM maybe_type_qual '(' . string ':' asm_operands ':' asm_operands ')' ';' (rule 258) + stmt -> ASM maybe_type_qual '(' . string ':' asm_operands ':' asm_operands ':' asm_clobbers ')' ';' (rule 259) + + STRING shift, and go to state 57 + + string go to state 461 + + + +state 442 + + stmt -> identifier ':' @28 . stmt (rule 262) + + IDENTIFIER shift, and go to state 346 + TYPENAME shift, and go to state 27 + CONSTANT shift, and go to state 61 + STRING shift, and go to state 57 + SIZEOF shift, and go to state 62 + IF shift, and go to state 348 + WHILE shift, and go to state 349 + DO shift, and go to state 350 + FOR shift, and go to state 351 + SWITCH shift, and go to state 352 + CASE shift, and go to state 353 + DEFAULT shift, and go to state 354 + BREAK shift, and go to state 355 + CONTINUE shift, and go to state 356 + RETURN shift, and go to state 357 + GOTO shift, and go to state 358 + ASM shift, and go to state 359 + ALIGNOF shift, and go to state 63 + '&' shift, and go to state 64 + '+' shift, and go to state 65 + '-' shift, and go to state 66 + '*' shift, and go to state 67 + PLUSPLUS shift, and go to state 68 + MINUSMINUS shift, and go to state 69 + '(' shift, and go to state 70 + ';' shift, and go to state 360 + '~' shift, and go to state 71 + '!' shift, and go to state 72 + '{' shift, and go to state 216 + + identifier go to state 361 + unop go to state 73 + expr go to state 362 + nonnull_exprlist go to state 75 + unary_expr go to state 76 + cast_expr go to state 77 + expr_no_commas go to state 78 + primary go to state 79 + string go to state 80 + compstmt go to state 365 + simple_if go to state 366 + stmt go to state 462 + + + +state 443 + + compstmt -> '{' pushlevel decls xstmts '}' . (rule 226) + + $default reduce using rule 226 (compstmt) + + + +state 444 + + stmt -> simple_if ELSE @17 . stmt (rule 234) + + IDENTIFIER shift, and go to state 346 + TYPENAME shift, and go to state 27 + CONSTANT shift, and go to state 61 + STRING shift, and go to state 57 + SIZEOF shift, and go to state 62 + IF shift, and go to state 348 + WHILE shift, and go to state 349 + DO shift, and go to state 350 + FOR shift, and go to state 351 + SWITCH shift, and go to state 352 + CASE shift, and go to state 353 + DEFAULT shift, and go to state 354 + BREAK shift, and go to state 355 + CONTINUE shift, and go to state 356 + RETURN shift, and go to state 357 + GOTO shift, and go to state 358 + ASM shift, and go to state 359 + ALIGNOF shift, and go to state 63 + '&' shift, and go to state 64 + '+' shift, and go to state 65 + '-' shift, and go to state 66 + '*' shift, and go to state 67 + PLUSPLUS shift, and go to state 68 + MINUSMINUS shift, and go to state 69 + '(' shift, and go to state 70 + ';' shift, and go to state 360 + '~' shift, and go to state 71 + '!' shift, and go to state 72 + '{' shift, and go to state 216 + + identifier go to state 361 + unop go to state 73 + expr go to state 362 + nonnull_exprlist go to state 75 + unary_expr go to state 76 + cast_expr go to state 77 + expr_no_commas go to state 78 + primary go to state 79 + string go to state 80 + compstmt go to state 365 + simple_if go to state 366 + stmt go to state 463 + + + +state 445 + + init -> '{' initlist '}' . (rule 140) + + $default reduce using rule 140 (init) + + + +state 446 + + init -> '{' initlist ',' . '}' (rule 141) + initlist -> initlist ',' . init (rule 144) + + error shift, and go to state 368 + IDENTIFIER shift, and go to state 59 + CONSTANT shift, and go to state 61 + STRING shift, and go to state 57 + SIZEOF shift, and go to state 62 + ALIGNOF shift, and go to state 63 + '&' shift, and go to state 64 + '+' shift, and go to state 65 + '-' shift, and go to state 66 + '*' shift, and go to state 67 + PLUSPLUS shift, and go to state 68 + MINUSMINUS shift, and go to state 69 + '(' shift, and go to state 70 + '}' shift, and go to state 464 + '~' shift, and go to state 71 + '!' shift, and go to state 72 + '{' shift, and go to state 369 + + unop go to state 73 + unary_expr go to state 76 + cast_expr go to state 77 + expr_no_commas go to state 370 + primary go to state 79 + string go to state 80 + init go to state 447 + + + +state 447 + + initlist -> initlist ',' init . (rule 144) + + $default reduce using rule 144 (initlist) + + + +state 448 + + cast_expr -> '(' typename ')' '{' initlist maybecomma '}' . (rule 53) + + $default reduce using rule 53 (cast_expr) + + + +state 449 + + parm_declarator -> parm_declarator '[' expr ']' . (rule 154) + + $default reduce using rule 154 (parm_declarator) + + + +state 450 + + attrib -> IDENTIFIER '(' CONSTANT . ')' (rule 136) + + ')' shift, and go to state 465 + + + +state 451 + + attrib -> IDENTIFIER '(' identifiers . ')' (rule 137) + identifiers -> identifiers . ',' IDENTIFIER (rule 295) + + ')' shift, and go to state 466 + ',' shift, and go to state 327 + + + +state 452 + + maybe_attribute -> ATTRIBUTE '(' '(' attribute_list ')' ')' . (rule 132) + + $default reduce using rule 132 (maybe_attribute) + + + +state 453 + + attribute_list -> attribute_list ',' attrib . (rule 134) + + $default reduce using rule 134 (attribute_list) + + + +state 454 + + simple_if -> IF '(' expr ')' . @16 stmt (rule 230) + + $default reduce using rule 229 (@16) + + @16 go to state 467 + + + +state 455 + + stmt -> WHILE @18 '(' expr . ')' @19 stmt (rule 238) + + ')' shift, and go to state 468 + + + +state 456 + + stmt -> DO @20 stmt WHILE . @21 '(' expr ')' ';' (rule 241) + + $default reduce using rule 240 (@21) + + @21 go to state 469 + + + +state 457 + + stmt -> FOR '(' xexpr ';' . @22 xexpr ';' @23 xexpr ')' @24 stmt (rule 245) + + $default reduce using rule 242 (@22) + + @22 go to state 470 + + + +state 458 + + stmt -> SWITCH '(' expr ')' . @25 stmt (rule 247) + + $default reduce using rule 246 (@25) + + @25 go to state 471 + + + +state 459 + + stmt -> CASE expr ':' @26 . stmt (rule 249) + + IDENTIFIER shift, and go to state 346 + TYPENAME shift, and go to state 27 + CONSTANT shift, and go to state 61 + STRING shift, and go to state 57 + SIZEOF shift, and go to state 62 + IF shift, and go to state 348 + WHILE shift, and go to state 349 + DO shift, and go to state 350 + FOR shift, and go to state 351 + SWITCH shift, and go to state 352 + CASE shift, and go to state 353 + DEFAULT shift, and go to state 354 + BREAK shift, and go to state 355 + CONTINUE shift, and go to state 356 + RETURN shift, and go to state 357 + GOTO shift, and go to state 358 + ASM shift, and go to state 359 + ALIGNOF shift, and go to state 63 + '&' shift, and go to state 64 + '+' shift, and go to state 65 + '-' shift, and go to state 66 + '*' shift, and go to state 67 + PLUSPLUS shift, and go to state 68 + MINUSMINUS shift, and go to state 69 + '(' shift, and go to state 70 + ';' shift, and go to state 360 + '~' shift, and go to state 71 + '!' shift, and go to state 72 + '{' shift, and go to state 216 + + identifier go to state 361 + unop go to state 73 + expr go to state 362 + nonnull_exprlist go to state 75 + unary_expr go to state 76 + cast_expr go to state 77 + expr_no_commas go to state 78 + primary go to state 79 + string go to state 80 + compstmt go to state 365 + simple_if go to state 366 + stmt go to state 472 + + + +state 460 + + stmt -> DEFAULT ':' @27 stmt . (rule 251) + + $default reduce using rule 251 (stmt) + + + +state 461 + + string -> string . STRING (rule 86) + stmt -> ASM maybe_type_qual '(' string . ')' ';' (rule 256) + stmt -> ASM maybe_type_qual '(' string . ':' asm_operands ')' ';' (rule 257) + stmt -> ASM maybe_type_qual '(' string . ':' asm_operands ':' asm_operands ')' ';' (rule 258) + stmt -> ASM maybe_type_qual '(' string . ':' asm_operands ':' asm_operands ':' asm_clobbers ')' ';' (rule 259) + + STRING shift, and go to state 124 + ':' shift, and go to state 473 + ')' shift, and go to state 474 + + + +state 462 + + stmt -> identifier ':' @28 stmt . (rule 262) + + $default reduce using rule 262 (stmt) + + + +state 463 + + stmt -> simple_if ELSE @17 stmt . (rule 234) + + $default reduce using rule 234 (stmt) + + + +state 464 + + init -> '{' initlist ',' '}' . (rule 141) + + $default reduce using rule 141 (init) + + + +state 465 + + attrib -> IDENTIFIER '(' CONSTANT ')' . (rule 136) + + $default reduce using rule 136 (attrib) + + + +state 466 + + attrib -> IDENTIFIER '(' identifiers ')' . (rule 137) + + $default reduce using rule 137 (attrib) + + + +state 467 + + simple_if -> IF '(' expr ')' @16 . stmt (rule 230) + + IDENTIFIER shift, and go to state 346 + TYPENAME shift, and go to state 27 + CONSTANT shift, and go to state 61 + STRING shift, and go to state 57 + SIZEOF shift, and go to state 62 + IF shift, and go to state 348 + WHILE shift, and go to state 349 + DO shift, and go to state 350 + FOR shift, and go to state 351 + SWITCH shift, and go to state 352 + CASE shift, and go to state 353 + DEFAULT shift, and go to state 354 + BREAK shift, and go to state 355 + CONTINUE shift, and go to state 356 + RETURN shift, and go to state 357 + GOTO shift, and go to state 358 + ASM shift, and go to state 359 + ALIGNOF shift, and go to state 63 + '&' shift, and go to state 64 + '+' shift, and go to state 65 + '-' shift, and go to state 66 + '*' shift, and go to state 67 + PLUSPLUS shift, and go to state 68 + MINUSMINUS shift, and go to state 69 + '(' shift, and go to state 70 + ';' shift, and go to state 360 + '~' shift, and go to state 71 + '!' shift, and go to state 72 + '{' shift, and go to state 216 + + identifier go to state 361 + unop go to state 73 + expr go to state 362 + nonnull_exprlist go to state 75 + unary_expr go to state 76 + cast_expr go to state 77 + expr_no_commas go to state 78 + primary go to state 79 + string go to state 80 + compstmt go to state 365 + simple_if go to state 366 + stmt go to state 475 + + + +state 468 + + stmt -> WHILE @18 '(' expr ')' . @19 stmt (rule 238) + + $default reduce using rule 237 (@19) + + @19 go to state 476 + + + +state 469 + + stmt -> DO @20 stmt WHILE @21 . '(' expr ')' ';' (rule 241) + + '(' shift, and go to state 477 + + + +state 470 + + stmt -> FOR '(' xexpr ';' @22 . xexpr ';' @23 xexpr ')' @24 stmt (rule 245) + + IDENTIFIER shift, and go to state 59 + CONSTANT shift, and go to state 61 + STRING shift, and go to state 57 + SIZEOF shift, and go to state 62 + ALIGNOF shift, and go to state 63 + '&' shift, and go to state 64 + '+' shift, and go to state 65 + '-' shift, and go to state 66 + '*' shift, and go to state 67 + PLUSPLUS shift, and go to state 68 + MINUSMINUS shift, and go to state 69 + '(' shift, and go to state 70 + '~' shift, and go to state 71 + '!' shift, and go to state 72 + + $default reduce using rule 266 (xexpr) + + unop go to state 73 + expr go to state 222 + nonnull_exprlist go to state 75 + unary_expr go to state 76 + cast_expr go to state 77 + expr_no_commas go to state 78 + primary go to state 79 + string go to state 80 + xexpr go to state 478 + + + +state 471 + + stmt -> SWITCH '(' expr ')' @25 . stmt (rule 247) + + IDENTIFIER shift, and go to state 346 + TYPENAME shift, and go to state 27 + CONSTANT shift, and go to state 61 + STRING shift, and go to state 57 + SIZEOF shift, and go to state 62 + IF shift, and go to state 348 + WHILE shift, and go to state 349 + DO shift, and go to state 350 + FOR shift, and go to state 351 + SWITCH shift, and go to state 352 + CASE shift, and go to state 353 + DEFAULT shift, and go to state 354 + BREAK shift, and go to state 355 + CONTINUE shift, and go to state 356 + RETURN shift, and go to state 357 + GOTO shift, and go to state 358 + ASM shift, and go to state 359 + ALIGNOF shift, and go to state 63 + '&' shift, and go to state 64 + '+' shift, and go to state 65 + '-' shift, and go to state 66 + '*' shift, and go to state 67 + PLUSPLUS shift, and go to state 68 + MINUSMINUS shift, and go to state 69 + '(' shift, and go to state 70 + ';' shift, and go to state 360 + '~' shift, and go to state 71 + '!' shift, and go to state 72 + '{' shift, and go to state 216 + + identifier go to state 361 + unop go to state 73 + expr go to state 362 + nonnull_exprlist go to state 75 + unary_expr go to state 76 + cast_expr go to state 77 + expr_no_commas go to state 78 + primary go to state 79 + string go to state 80 + compstmt go to state 365 + simple_if go to state 366 + stmt go to state 479 + + + +state 472 + + stmt -> CASE expr ':' @26 stmt . (rule 249) + + $default reduce using rule 249 (stmt) + + + +state 473 + + stmt -> ASM maybe_type_qual '(' string ':' . asm_operands ')' ';' (rule 257) + stmt -> ASM maybe_type_qual '(' string ':' . asm_operands ':' asm_operands ')' ';' (rule 258) + stmt -> ASM maybe_type_qual '(' string ':' . asm_operands ':' asm_operands ':' asm_clobbers ')' ';' (rule 259) + + STRING shift, and go to state 480 + + $default reduce using rule 268 (asm_operands) + + asm_operands go to state 481 + nonnull_asm_operands go to state 482 + asm_operand go to state 483 + + + +state 474 + + stmt -> ASM maybe_type_qual '(' string ')' . ';' (rule 256) + + ';' shift, and go to state 484 + + + +state 475 + + simple_if -> IF '(' expr ')' @16 stmt . (rule 230) + + $default reduce using rule 230 (simple_if) + + + +state 476 + + stmt -> WHILE @18 '(' expr ')' @19 . stmt (rule 238) + + IDENTIFIER shift, and go to state 346 + TYPENAME shift, and go to state 27 + CONSTANT shift, and go to state 61 + STRING shift, and go to state 57 + SIZEOF shift, and go to state 62 + IF shift, and go to state 348 + WHILE shift, and go to state 349 + DO shift, and go to state 350 + FOR shift, and go to state 351 + SWITCH shift, and go to state 352 + CASE shift, and go to state 353 + DEFAULT shift, and go to state 354 + BREAK shift, and go to state 355 + CONTINUE shift, and go to state 356 + RETURN shift, and go to state 357 + GOTO shift, and go to state 358 + ASM shift, and go to state 359 + ALIGNOF shift, and go to state 63 + '&' shift, and go to state 64 + '+' shift, and go to state 65 + '-' shift, and go to state 66 + '*' shift, and go to state 67 + PLUSPLUS shift, and go to state 68 + MINUSMINUS shift, and go to state 69 + '(' shift, and go to state 70 + ';' shift, and go to state 360 + '~' shift, and go to state 71 + '!' shift, and go to state 72 + '{' shift, and go to state 216 + + identifier go to state 361 + unop go to state 73 + expr go to state 362 + nonnull_exprlist go to state 75 + unary_expr go to state 76 + cast_expr go to state 77 + expr_no_commas go to state 78 + primary go to state 79 + string go to state 80 + compstmt go to state 365 + simple_if go to state 366 + stmt go to state 485 + + + +state 477 + + stmt -> DO @20 stmt WHILE @21 '(' . expr ')' ';' (rule 241) + + IDENTIFIER shift, and go to state 59 + CONSTANT shift, and go to state 61 + STRING shift, and go to state 57 + SIZEOF shift, and go to state 62 + ALIGNOF shift, and go to state 63 + '&' shift, and go to state 64 + '+' shift, and go to state 65 + '-' shift, and go to state 66 + '*' shift, and go to state 67 + PLUSPLUS shift, and go to state 68 + MINUSMINUS shift, and go to state 69 + '(' shift, and go to state 70 + '~' shift, and go to state 71 + '!' shift, and go to state 72 + + unop go to state 73 + expr go to state 486 + nonnull_exprlist go to state 75 + unary_expr go to state 76 + cast_expr go to state 77 + expr_no_commas go to state 78 + primary go to state 79 + string go to state 80 + + + +state 478 + + stmt -> FOR '(' xexpr ';' @22 xexpr . ';' @23 xexpr ')' @24 stmt (rule 245) + + ';' shift, and go to state 487 + + + +state 479 + + stmt -> SWITCH '(' expr ')' @25 stmt . (rule 247) + + $default reduce using rule 247 (stmt) + + + +state 480 + + asm_operand -> STRING . '(' expr ')' (rule 272) + + '(' shift, and go to state 488 + + + +state 481 + + stmt -> ASM maybe_type_qual '(' string ':' asm_operands . ')' ';' (rule 257) + stmt -> ASM maybe_type_qual '(' string ':' asm_operands . ':' asm_operands ')' ';' (rule 258) + stmt -> ASM maybe_type_qual '(' string ':' asm_operands . ':' asm_operands ':' asm_clobbers ')' ';' (rule 259) + + ':' shift, and go to state 489 + ')' shift, and go to state 490 + + + +state 482 + + asm_operands -> nonnull_asm_operands . (rule 269) + nonnull_asm_operands -> nonnull_asm_operands . ',' asm_operand (rule 271) + + ',' shift, and go to state 491 + + $default reduce using rule 269 (asm_operands) + + + +state 483 + + nonnull_asm_operands -> asm_operand . (rule 270) + + $default reduce using rule 270 (nonnull_asm_operands) + + + +state 484 + + stmt -> ASM maybe_type_qual '(' string ')' ';' . (rule 256) + + $default reduce using rule 256 (stmt) + + + +state 485 + + stmt -> WHILE @18 '(' expr ')' @19 stmt . (rule 238) + + $default reduce using rule 238 (stmt) + + + +state 486 + + stmt -> DO @20 stmt WHILE @21 '(' expr . ')' ';' (rule 241) + + ')' shift, and go to state 492 + + + +state 487 + + stmt -> FOR '(' xexpr ';' @22 xexpr ';' . @23 xexpr ')' @24 stmt (rule 245) + + $default reduce using rule 243 (@23) + + @23 go to state 493 + + + +state 488 + + asm_operand -> STRING '(' . expr ')' (rule 272) + + IDENTIFIER shift, and go to state 59 + CONSTANT shift, and go to state 61 + STRING shift, and go to state 57 + SIZEOF shift, and go to state 62 + ALIGNOF shift, and go to state 63 + '&' shift, and go to state 64 + '+' shift, and go to state 65 + '-' shift, and go to state 66 + '*' shift, and go to state 67 + PLUSPLUS shift, and go to state 68 + MINUSMINUS shift, and go to state 69 + '(' shift, and go to state 70 + '~' shift, and go to state 71 + '!' shift, and go to state 72 + + unop go to state 73 + expr go to state 494 + nonnull_exprlist go to state 75 + unary_expr go to state 76 + cast_expr go to state 77 + expr_no_commas go to state 78 + primary go to state 79 + string go to state 80 + + + +state 489 + + stmt -> ASM maybe_type_qual '(' string ':' asm_operands ':' . asm_operands ')' ';' (rule 258) + stmt -> ASM maybe_type_qual '(' string ':' asm_operands ':' . asm_operands ':' asm_clobbers ')' ';' (rule 259) + + STRING shift, and go to state 480 + + $default reduce using rule 268 (asm_operands) + + asm_operands go to state 495 + nonnull_asm_operands go to state 482 + asm_operand go to state 483 + + + +state 490 + + stmt -> ASM maybe_type_qual '(' string ':' asm_operands ')' . ';' (rule 257) + + ';' shift, and go to state 496 + + + +state 491 + + nonnull_asm_operands -> nonnull_asm_operands ',' . asm_operand (rule 271) + + STRING shift, and go to state 480 + + asm_operand go to state 497 + + + +state 492 + + stmt -> DO @20 stmt WHILE @21 '(' expr ')' . ';' (rule 241) + + ';' shift, and go to state 498 + + + +state 493 + + stmt -> FOR '(' xexpr ';' @22 xexpr ';' @23 . xexpr ')' @24 stmt (rule 245) + + IDENTIFIER shift, and go to state 59 + CONSTANT shift, and go to state 61 + STRING shift, and go to state 57 + SIZEOF shift, and go to state 62 + ALIGNOF shift, and go to state 63 + '&' shift, and go to state 64 + '+' shift, and go to state 65 + '-' shift, and go to state 66 + '*' shift, and go to state 67 + PLUSPLUS shift, and go to state 68 + MINUSMINUS shift, and go to state 69 + '(' shift, and go to state 70 + '~' shift, and go to state 71 + '!' shift, and go to state 72 + + $default reduce using rule 266 (xexpr) + + unop go to state 73 + expr go to state 222 + nonnull_exprlist go to state 75 + unary_expr go to state 76 + cast_expr go to state 77 + expr_no_commas go to state 78 + primary go to state 79 + string go to state 80 + xexpr go to state 499 + + + +state 494 + + asm_operand -> STRING '(' expr . ')' (rule 272) + + ')' shift, and go to state 500 + + + +state 495 + + stmt -> ASM maybe_type_qual '(' string ':' asm_operands ':' asm_operands . ')' ';' (rule 258) + stmt -> ASM maybe_type_qual '(' string ':' asm_operands ':' asm_operands . ':' asm_clobbers ')' ';' (rule 259) + + ':' shift, and go to state 501 + ')' shift, and go to state 502 + + + +state 496 + + stmt -> ASM maybe_type_qual '(' string ':' asm_operands ')' ';' . (rule 257) + + $default reduce using rule 257 (stmt) + + + +state 497 + + nonnull_asm_operands -> nonnull_asm_operands ',' asm_operand . (rule 271) + + $default reduce using rule 271 (nonnull_asm_operands) + + + +state 498 + + stmt -> DO @20 stmt WHILE @21 '(' expr ')' ';' . (rule 241) + + $default reduce using rule 241 (stmt) + + + +state 499 + + stmt -> FOR '(' xexpr ';' @22 xexpr ';' @23 xexpr . ')' @24 stmt (rule 245) + + ')' shift, and go to state 503 + + + +state 500 + + asm_operand -> STRING '(' expr ')' . (rule 272) + + $default reduce using rule 272 (asm_operand) + + + +state 501 + + stmt -> ASM maybe_type_qual '(' string ':' asm_operands ':' asm_operands ':' . asm_clobbers ')' ';' (rule 259) + + STRING shift, and go to state 57 + + string go to state 504 + asm_clobbers go to state 505 + + + +state 502 + + stmt -> ASM maybe_type_qual '(' string ':' asm_operands ':' asm_operands ')' . ';' (rule 258) + + ';' shift, and go to state 506 + + + +state 503 + + stmt -> FOR '(' xexpr ';' @22 xexpr ';' @23 xexpr ')' . @24 stmt (rule 245) + + $default reduce using rule 244 (@24) + + @24 go to state 507 + + + +state 504 + + string -> string . STRING (rule 86) + asm_clobbers -> string . (rule 273) + + STRING shift, and go to state 124 + + $default reduce using rule 273 (asm_clobbers) + + + +state 505 + + stmt -> ASM maybe_type_qual '(' string ':' asm_operands ':' asm_operands ':' asm_clobbers . ')' ';' (rule 259) + asm_clobbers -> asm_clobbers . ',' string (rule 274) + + ')' shift, and go to state 508 + ',' shift, and go to state 509 + + + +state 506 + + stmt -> ASM maybe_type_qual '(' string ':' asm_operands ':' asm_operands ')' ';' . (rule 258) + + $default reduce using rule 258 (stmt) + + + +state 507 + + stmt -> FOR '(' xexpr ';' @22 xexpr ';' @23 xexpr ')' @24 . stmt (rule 245) + + IDENTIFIER shift, and go to state 346 + TYPENAME shift, and go to state 27 + CONSTANT shift, and go to state 61 + STRING shift, and go to state 57 + SIZEOF shift, and go to state 62 + IF shift, and go to state 348 + WHILE shift, and go to state 349 + DO shift, and go to state 350 + FOR shift, and go to state 351 + SWITCH shift, and go to state 352 + CASE shift, and go to state 353 + DEFAULT shift, and go to state 354 + BREAK shift, and go to state 355 + CONTINUE shift, and go to state 356 + RETURN shift, and go to state 357 + GOTO shift, and go to state 358 + ASM shift, and go to state 359 + ALIGNOF shift, and go to state 63 + '&' shift, and go to state 64 + '+' shift, and go to state 65 + '-' shift, and go to state 66 + '*' shift, and go to state 67 + PLUSPLUS shift, and go to state 68 + MINUSMINUS shift, and go to state 69 + '(' shift, and go to state 70 + ';' shift, and go to state 360 + '~' shift, and go to state 71 + '!' shift, and go to state 72 + '{' shift, and go to state 216 + + identifier go to state 361 + unop go to state 73 + expr go to state 362 + nonnull_exprlist go to state 75 + unary_expr go to state 76 + cast_expr go to state 77 + expr_no_commas go to state 78 + primary go to state 79 + string go to state 80 + compstmt go to state 365 + simple_if go to state 366 + stmt go to state 510 + + + +state 508 + + stmt -> ASM maybe_type_qual '(' string ':' asm_operands ':' asm_operands ':' asm_clobbers ')' . ';' (rule 259) + + ';' shift, and go to state 511 + + + +state 509 + + asm_clobbers -> asm_clobbers ',' . string (rule 274) + + STRING shift, and go to state 57 + + string go to state 512 + + + +state 510 + + stmt -> FOR '(' xexpr ';' @22 xexpr ';' @23 xexpr ')' @24 stmt . (rule 245) + + $default reduce using rule 245 (stmt) + + + +state 511 + + stmt -> ASM maybe_type_qual '(' string ':' asm_operands ':' asm_operands ':' asm_clobbers ')' ';' . (rule 259) + + $default reduce using rule 259 (stmt) + + + +state 512 + + string -> string . STRING (rule 86) + asm_clobbers -> asm_clobbers ',' string . (rule 274) + + STRING shift, and go to state 124 + + $default reduce using rule 274 (asm_clobbers) + + + +state 513 + + $ shift, and go to state 514 + + + +state 514 + + $ shift, and go to state 515 + + + +state 515 + + NO ACTIONS diff --git a/gcc-1.40/c-parse.tab.c b/gcc-1.40/c-parse.tab.c new file mode 100644 index 0000000..f29a995 --- /dev/null +++ b/gcc-1.40/c-parse.tab.c @@ -0,0 +1,4280 @@ + +/* A Bison parser, made from ccdir/c-parse.y */ + +#define IDENTIFIER 258 +#define TYPENAME 259 +#define SCSPEC 260 +#define TYPESPEC 261 +#define TYPE_QUAL 262 +#define CONSTANT 263 +#define STRING 264 +#define ELLIPSIS 265 +#define SIZEOF 266 +#define ENUM 267 +#define STRUCT 268 +#define UNION 269 +#define IF 270 +#define ELSE 271 +#define WHILE 272 +#define DO 273 +#define FOR 274 +#define SWITCH 275 +#define CASE 276 +#define DEFAULT 277 +#define BREAK 278 +#define CONTINUE 279 +#define RETURN 280 +#define GOTO 281 +#define ASM 282 +#define TYPEOF 283 +#define ALIGNOF 284 +#define ATTRIBUTE 285 +#define ASSIGN 286 +#define OROR 287 +#define ANDAND 288 +#define EQCOMPARE 289 +#define ARITHCOMPARE 290 +#define LSHIFT 291 +#define RSHIFT 292 +#define UNARY 293 +#define PLUSPLUS 294 +#define MINUSMINUS 295 +#define HYPERUNARY 296 +#define POINTSAT 297 + +#line 39 "ccdir/c-parse.y" + +#include "config.h" +#include "tree.h" +#include "input.h" +#include "c-parse.h" +#include "c-tree.h" + +#include +#include + +#ifndef errno +extern int errno; +#endif + +void yyerror (); + +/* Cause the `yydebug' variable to be defined. */ +#define YYDEBUG 1 + +#line 61 "ccdir/c-parse.y" +typedef union {long itype; tree ttype; enum tree_code code; } YYSTYPE; +#line 154 "ccdir/c-parse.y" + +/* 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 + used in a context which makes it a reference to a variable. */ +static tree lastiddecl; + +static tree make_pointer_declarator (); +static tree combine_strings (); +static void reinit_parse_for_function (); + +/* List of types and structure classes of the current declaration. */ +tree current_declspecs; + +/* Stack of saved values of current_declspecs. */ +tree declspec_stack; + +int undeclared_variable_notice; /* 1 if we explained undeclared var errors. */ + +static int yylex (); + +#ifndef YYLTYPE +typedef + struct yyltype + { + int timestamp; + int first_line; + int first_column; + int last_line; + int last_column; + char *text; + } + yyltype; + +#define YYLTYPE yyltype +#endif + +#include + +#ifndef __STDC__ +#define const +#endif + + + +#define YYFINAL 515 +#define YYFLAG -32768 +#define YYNTBASE 65 + +#define YYTRANSLATE(x) ((unsigned)(x) <= 297 ? yytranslate[x] : 172) + +static const char yytranslate[] = { 0, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 61, 2, 2, 2, 48, 39, 2, 55, + 57, 46, 44, 62, 45, 54, 47, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 34, 58, 2, + 32, 2, 33, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 56, 2, 64, 38, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 63, 37, 59, 60, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31, 35, 36, 40, 41, + 42, 43, 49, 50, 51, 52, 53 +}; + +static const short yyprhs[] = { 0, + 0, 1, 3, 4, 7, 8, 12, 14, 16, 22, + 26, 31, 36, 39, 42, 45, 48, 50, 51, 52, + 60, 65, 66, 67, 75, 80, 81, 82, 89, 93, + 95, 97, 99, 101, 103, 105, 107, 109, 111, 113, + 114, 116, 118, 122, 124, 127, 130, 133, 138, 141, + 146, 148, 153, 161, 163, 167, 171, 175, 179, 183, + 187, 191, 195, 199, 203, 207, 211, 215, 219, 225, + 229, 233, 235, 237, 239, 243, 247, 248, 253, 258, + 263, 267, 271, 274, 277, 279, 282, 283, 285, 287, + 289, 292, 295, 296, 301, 306, 309, 312, 315, 319, + 320, 323, 326, 328, 330, 333, 336, 339, 343, 344, + 347, 349, 351, 353, 358, 363, 365, 367, 369, 371, + 375, 377, 381, 382, 387, 388, 395, 399, 400, 407, + 411, 412, 419, 421, 425, 427, 432, 437, 439, 442, + 446, 451, 453, 455, 459, 461, 463, 467, 471, 476, + 480, 484, 486, 490, 495, 499, 503, 505, 509, 513, + 517, 522, 526, 528, 529, 536, 541, 544, 545, 552, + 557, 560, 561, 569, 570, 577, 580, 581, 583, 584, + 586, 588, 591, 592, 596, 599, 603, 607, 609, 610, + 612, 616, 619, 624, 627, 629, 633, 635, 639, 642, + 645, 646, 648, 650, 653, 654, 657, 661, 665, 668, + 672, 677, 681, 684, 688, 691, 693, 696, 699, 700, + 702, 705, 706, 708, 711, 714, 720, 725, 730, 731, + 738, 740, 743, 744, 749, 751, 752, 753, 761, 762, + 763, 773, 774, 775, 776, 789, 790, 797, 798, 804, + 805, 810, 813, 816, 819, 823, 830, 839, 850, 863, + 867, 868, 873, 875, 876, 878, 879, 881, 882, 884, + 886, 890, 895, 897, 901, 902, 905, 906, 909, 912, + 915, 918, 921, 924, 925, 927, 931, 933, 937, 940, + 943, 946, 949, 952, 954 +}; + +static const short yyrhs[] = { -1, + 66, 0, 0, 67, 69, 0, 0, 66, 68, 69, + 0, 71, 0, 70, 0, 27, 55, 88, 57, 58, + 0, 91, 101, 58, 0, 95, 91, 101, 58, 0, + 93, 91, 100, 58, 0, 95, 58, 0, 93, 58, + 0, 1, 58, 0, 1, 59, 0, 58, 0, 0, + 0, 93, 91, 112, 72, 89, 73, 139, 0, 93, + 91, 112, 1, 0, 0, 0, 95, 91, 115, 74, + 89, 75, 139, 0, 95, 91, 115, 1, 0, 0, + 0, 91, 115, 76, 89, 77, 139, 0, 91, 115, + 1, 0, 3, 0, 4, 0, 39, 0, 45, 0, + 44, 0, 50, 0, 51, 0, 60, 0, 61, 0, + 82, 0, 0, 82, 0, 85, 0, 82, 62, 85, + 0, 86, 0, 46, 84, 0, 79, 84, 0, 11, + 83, 0, 11, 55, 130, 57, 0, 29, 83, 0, + 29, 55, 130, 57, 0, 83, 0, 55, 130, 57, + 84, 0, 55, 130, 57, 63, 111, 121, 59, 0, + 84, 0, 85, 44, 85, 0, 85, 45, 85, 0, + 85, 46, 85, 0, 85, 47, 85, 0, 85, 48, + 85, 0, 85, 42, 85, 0, 85, 43, 85, 0, + 85, 41, 85, 0, 85, 40, 85, 0, 85, 39, + 85, 0, 85, 37, 85, 0, 85, 38, 85, 0, + 85, 36, 85, 0, 85, 35, 85, 0, 85, 33, + 157, 34, 85, 0, 85, 32, 85, 0, 85, 31, + 85, 0, 3, 0, 8, 0, 88, 0, 55, 80, + 57, 0, 55, 1, 57, 0, 0, 55, 87, 140, + 57, 0, 86, 55, 81, 57, 0, 86, 56, 80, + 64, 0, 86, 54, 78, 0, 86, 53, 78, 0, + 86, 50, 0, 86, 51, 0, 9, 0, 88, 9, + 0, 0, 90, 0, 92, 0, 137, 0, 90, 92, + 0, 92, 137, 0, 0, 93, 91, 100, 58, 0, + 95, 91, 101, 58, 0, 93, 58, 0, 95, 58, + 0, 98, 94, 0, 95, 98, 94, 0, 0, 94, + 99, 0, 94, 5, 0, 7, 0, 5, 0, 95, + 7, 0, 95, 5, 0, 98, 97, 0, 132, 98, + 97, 0, 0, 97, 99, 0, 6, 0, 116, 0, + 4, 0, 28, 55, 80, 57, 0, 28, 55, 130, + 57, 0, 6, 0, 7, 0, 116, 0, 103, 0, + 100, 62, 103, 0, 105, 0, 101, 62, 103, 0, + 0, 27, 55, 88, 57, 0, 0, 112, 102, 107, + 32, 104, 110, 0, 112, 102, 107, 0, 0, 115, + 102, 107, 32, 106, 110, 0, 115, 102, 107, 0, + 0, 30, 55, 55, 108, 57, 57, 0, 109, 0, + 108, 62, 109, 0, 3, 0, 3, 55, 8, 57, + 0, 3, 55, 171, 57, 0, 85, 0, 63, 59, + 0, 63, 111, 59, 0, 63, 111, 62, 59, 0, + 1, 0, 110, 0, 111, 62, 110, 0, 113, 0, + 115, 0, 55, 113, 57, 0, 113, 55, 164, 0, + 113, 56, 80, 64, 0, 113, 56, 64, 0, 46, + 133, 113, 0, 4, 0, 114, 55, 164, 0, 114, + 56, 80, 64, 0, 114, 56, 64, 0, 46, 133, + 114, 0, 4, 0, 115, 55, 164, 0, 55, 115, + 57, 0, 46, 133, 115, 0, 115, 56, 80, 64, + 0, 115, 56, 64, 0, 3, 0, 0, 13, 78, + 63, 117, 123, 59, 0, 13, 63, 123, 59, 0, + 13, 78, 0, 0, 14, 78, 63, 118, 123, 59, + 0, 14, 63, 123, 59, 0, 14, 78, 0, 0, + 12, 78, 63, 119, 128, 122, 59, 0, 0, 12, + 63, 120, 128, 122, 59, 0, 12, 78, 0, 0, + 62, 0, 0, 62, 0, 124, 0, 124, 125, 0, + 0, 124, 125, 58, 0, 124, 58, 0, 96, 91, + 126, 0, 132, 91, 126, 0, 1, 0, 0, 127, + 0, 126, 62, 127, 0, 112, 107, 0, 112, 34, + 85, 107, 0, 34, 85, 0, 129, 0, 128, 62, + 129, 0, 78, 0, 78, 32, 85, 0, 96, 131, + 0, 132, 131, 0, 0, 134, 0, 7, 0, 132, + 7, 0, 0, 133, 7, 0, 55, 134, 57, 0, + 46, 133, 134, 0, 46, 133, 0, 134, 55, 162, + 0, 134, 56, 80, 64, 0, 134, 56, 64, 0, + 55, 162, 0, 56, 80, 64, 0, 56, 64, 0, + 143, 0, 135, 143, 0, 135, 137, 0, 0, 135, + 0, 1, 58, 0, 0, 140, 0, 1, 140, 0, + 63, 59, 0, 63, 138, 90, 136, 59, 0, 63, + 138, 1, 59, 0, 63, 138, 135, 59, 0, 0, + 15, 55, 80, 57, 142, 143, 0, 140, 0, 80, + 58, 0, 0, 141, 16, 144, 143, 0, 141, 0, + 0, 0, 17, 145, 55, 80, 57, 146, 143, 0, + 0, 0, 18, 147, 143, 17, 148, 55, 80, 57, + 58, 0, 0, 0, 0, 19, 55, 157, 58, 149, + 157, 58, 150, 157, 57, 151, 143, 0, 0, 20, + 55, 80, 57, 152, 143, 0, 0, 21, 80, 34, + 153, 143, 0, 0, 22, 34, 154, 143, 0, 23, + 58, 0, 24, 58, 0, 25, 58, 0, 25, 80, + 58, 0, 27, 156, 55, 88, 57, 58, 0, 27, + 156, 55, 88, 34, 158, 57, 58, 0, 27, 156, + 55, 88, 34, 158, 34, 158, 57, 58, 0, 27, + 156, 55, 88, 34, 158, 34, 158, 34, 161, 57, + 58, 0, 26, 78, 58, 0, 0, 78, 34, 155, + 143, 0, 58, 0, 0, 7, 0, 0, 80, 0, + 0, 159, 0, 160, 0, 159, 62, 160, 0, 9, + 55, 80, 57, 0, 88, 0, 161, 62, 88, 0, + 0, 163, 167, 0, 0, 165, 166, 0, 168, 57, + 0, 171, 57, 0, 1, 57, 0, 168, 57, 0, + 1, 57, 0, 0, 169, 0, 169, 62, 10, 0, + 170, 0, 169, 62, 170, 0, 93, 114, 0, 93, + 115, 0, 93, 131, 0, 95, 115, 0, 95, 131, + 0, 3, 0, 171, 62, 3, 0 +}; + +#if YYDEBUG != 0 +static const short yyrline[] = { 0, + 177, 178, 185, 187, 187, 188, 190, 192, 193, 200, + 206, 208, 210, 212, 214, 215, 216, 221, 227, 229, + 230, 232, 237, 239, 240, 242, 247, 249, 250, 254, + 256, 259, 261, 263, 265, 267, 269, 271, 275, 279, + 282, 285, 288, 292, 294, 296, 298, 311, 313, 346, + 350, 352, 355, 369, 371, 373, 375, 377, 379, 381, + 383, 385, 387, 389, 391, 393, 395, 397, 399, 401, + 403, 407, 456, 457, 459, 461, 463, 471, 483, 485, + 487, 489, 491, 493, 498, 500, 504, 506, 509, 511, + 512, 513, 520, 527, 532, 536, 538, 546, 549, 553, + 555, 557, 565, 568, 570, 572, 581, 584, 588, 590, + 598, 599, 600, 601, 605, 613, 614, 615, 618, 620, + 623, 625, 628, 631, 639, 644, 645, 650, 655, 656, + 662, 665, 670, 671, 675, 679, 687, 693, 695, 699, + 701, 703, 709, 712, 719, 721, 726, 729, 734, 736, + 738, 740, 748, 754, 756, 758, 760, 766, 772, 774, + 776, 778, 780, 783, 788, 792, 795, 797, 799, 801, + 804, 806, 809, 812, 815, 818, 822, 824, 827, 829, + 833, 836, 841, 843, 845, 859, 865, 870, 874, 879, + 880, 884, 887, 889, 898, 900, 905, 908, 912, 915, + 919, 922, 925, 928, 932, 935, 939, 943, 945, 947, + 949, 951, 953, 955, 957, 965, 967, 968, 971, 973, + 976, 979, 988, 991, 994, 996, 1000, 1004, 1010, 1015, + 1017, 1019, 1029, 1032, 1033, 1035, 1039, 1043, 1044, 1048, + 1050, 1055, 1061, 1065, 1071, 1077, 1084, 1086, 1118, 1118, + 1129, 1129, 1133, 1137, 1140, 1143, 1148, 1155, 1162, 1169, + 1175, 1181, 1181, 1186, 1191, 1197, 1200, 1205, 1207, 1210, + 1212, 1216, 1221, 1224, 1230, 1234, 1241, 1245, 1250, 1252, + 1254, 1258, 1260, 1266, 1268, 1270, 1274, 1277, 1283, 1286, + 1288, 1290, 1292, 1297, 1300 +}; + +static const char * const yytname[] = { "$", +"error","$illegal.","IDENTIFIER","TYPENAME","SCSPEC","TYPESPEC","TYPE_QUAL","CONSTANT","STRING","ELLIPSIS", +"SIZEOF","ENUM","STRUCT","UNION","IF","ELSE","WHILE","DO","FOR","SWITCH", +"CASE","DEFAULT","BREAK","CONTINUE","RETURN","GOTO","ASM","TYPEOF","ALIGNOF","ATTRIBUTE", +"ASSIGN","'='","'?'","':'","OROR","ANDAND","'|'","'^'","'&'","EQCOMPARE", +"ARITHCOMPARE","LSHIFT","RSHIFT","'+'","'-'","'*'","'/'","'%'","UNARY","PLUSPLUS", +"MINUSMINUS","HYPERUNARY","POINTSAT","'.'","'('","'['","')'","';'","'}'","'~'", +"'!'","','","'{'","']'","program","extdefs","@1","@2","extdef","datadef", +"fndef","@3","@4","@5","@6","@7","@8","identifier","unop","expr", +"exprlist","nonnull_exprlist","unary_expr","cast_expr","expr_no_commas","primary","@9","string","xdecls","decls", +"setspecs","decl","typed_declspecs","reserved_declspecs","declmods","typed_typespecs","reserved_typespecquals","typespec","typespecqual_reserved","initdecls", +"notype_initdecls","maybeasm","initdcl","@10","notype_initdcl","@11","maybe_attribute","attribute_list","attrib","init", +"initlist","declarator","after_type_declarator","parm_declarator","notype_declarator","structsp","@12","@13","@14","@15", +"maybecomma","maybecomma_warn","component_decl_list","component_decl_list2","component_decl","components","component_declarator","enumlist","enumerator","typename", +"absdcl","nonempty_type_quals","type_quals","absdcl1","stmts","xstmts","errstmt","pushlevel","compstmt_or_error","compstmt", +"simple_if","@16","stmt","@17","@18","@19","@20","@21","@22","@23", +"@24","@25","@26","@27","@28","maybe_type_qual","xexpr","asm_operands","nonnull_asm_operands","asm_operand", +"asm_clobbers","parmlist","@29","parmlist_or_identifiers","@30","parmlist_or_identifiers_1","parmlist_1","parmlist_2","parms","parm", +"identifiers","" +}; +#endif + +static const short yyr1[] = { 0, + 65, 65, 67, 66, 68, 66, 69, 69, 69, 70, + 70, 70, 70, 70, 70, 70, 70, 72, 73, 71, + 71, 74, 75, 71, 71, 76, 77, 71, 71, 78, + 78, 79, 79, 79, 79, 79, 79, 79, 80, 81, + 81, 82, 82, 83, 83, 83, 83, 83, 83, 83, + 84, 84, 84, 85, 85, 85, 85, 85, 85, 85, + 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, + 85, 86, 86, 86, 86, 86, 87, 86, 86, 86, + 86, 86, 86, 86, 88, 88, 89, 89, 90, 90, + 90, 90, 91, 92, 92, 92, 92, 93, 93, 94, + 94, 94, 95, 95, 95, 95, 96, 96, 97, 97, + 98, 98, 98, 98, 98, 99, 99, 99, 100, 100, + 101, 101, 102, 102, 104, 103, 103, 106, 105, 105, + 107, 107, 108, 108, 109, 109, 109, 110, 110, 110, + 110, 110, 111, 111, 112, 112, 113, 113, 113, 113, + 113, 113, 114, 114, 114, 114, 114, 115, 115, 115, + 115, 115, 115, 117, 116, 116, 116, 118, 116, 116, + 116, 119, 116, 120, 116, 116, 121, 121, 122, 122, + 123, 123, 124, 124, 124, 125, 125, 125, 126, 126, + 126, 127, 127, 127, 128, 128, 129, 129, 130, 130, + 131, 131, 132, 132, 133, 133, 134, 134, 134, 134, + 134, 134, 134, 134, 134, 135, 135, 135, 136, 136, + 137, 138, 139, 139, 140, 140, 140, 140, 142, 141, + 143, 143, 144, 143, 143, 145, 146, 143, 147, 148, + 143, 149, 150, 151, 143, 152, 143, 153, 143, 154, + 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, + 155, 143, 143, 156, 156, 157, 157, 158, 158, 159, + 159, 160, 161, 161, 163, 162, 165, 164, 166, 166, + 166, 167, 167, 168, 168, 168, 169, 169, 170, 170, + 170, 170, 170, 171, 171 +}; + +static const short yyr2[] = { 0, + 0, 1, 0, 2, 0, 3, 1, 1, 5, 3, + 4, 4, 2, 2, 2, 2, 1, 0, 0, 7, + 4, 0, 0, 7, 4, 0, 0, 6, 3, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, + 1, 1, 3, 1, 2, 2, 2, 4, 2, 4, + 1, 4, 7, 1, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 5, 3, + 3, 1, 1, 1, 3, 3, 0, 4, 4, 4, + 3, 3, 2, 2, 1, 2, 0, 1, 1, 1, + 2, 2, 0, 4, 4, 2, 2, 2, 3, 0, + 2, 2, 1, 1, 2, 2, 2, 3, 0, 2, + 1, 1, 1, 4, 4, 1, 1, 1, 1, 3, + 1, 3, 0, 4, 0, 6, 3, 0, 6, 3, + 0, 6, 1, 3, 1, 4, 4, 1, 2, 3, + 4, 1, 1, 3, 1, 1, 3, 3, 4, 3, + 3, 1, 3, 4, 3, 3, 1, 3, 3, 3, + 4, 3, 1, 0, 6, 4, 2, 0, 6, 4, + 2, 0, 7, 0, 6, 2, 0, 1, 0, 1, + 1, 2, 0, 3, 2, 3, 3, 1, 0, 1, + 3, 2, 4, 2, 1, 3, 1, 3, 2, 2, + 0, 1, 1, 2, 0, 2, 3, 3, 2, 3, + 4, 3, 2, 3, 2, 1, 2, 2, 0, 1, + 2, 0, 1, 2, 2, 5, 4, 4, 0, 6, + 1, 2, 0, 4, 1, 0, 0, 7, 0, 0, + 9, 0, 0, 0, 12, 0, 6, 0, 5, 0, + 4, 2, 2, 2, 3, 6, 8, 10, 12, 3, + 0, 4, 1, 0, 1, 0, 1, 0, 1, 1, + 3, 4, 1, 3, 0, 2, 0, 2, 2, 2, + 2, 2, 2, 0, 1, 3, 1, 3, 2, 2, + 2, 2, 2, 1, 3 +}; + +static const short yydefact[] = { 3, + 5, 0, 0, 0, 113, 104, 111, 103, 0, 0, + 0, 0, 0, 17, 4, 8, 7, 0, 93, 93, + 100, 112, 6, 15, 16, 30, 31, 174, 176, 183, + 167, 183, 171, 0, 0, 163, 205, 0, 0, 121, + 0, 14, 0, 106, 105, 13, 0, 100, 98, 0, + 172, 0, 0, 164, 0, 168, 85, 0, 72, 203, + 73, 0, 0, 32, 34, 33, 0, 35, 36, 0, + 37, 38, 0, 0, 39, 51, 54, 42, 44, 74, + 201, 109, 0, 201, 0, 0, 10, 0, 29, 0, + 277, 0, 0, 131, 152, 205, 0, 0, 119, 0, + 145, 146, 0, 0, 99, 102, 116, 117, 101, 118, + 197, 179, 195, 0, 166, 188, 185, 93, 182, 93, + 183, 170, 183, 86, 0, 0, 47, 0, 49, 45, + 0, 0, 0, 0, 46, 114, 0, 0, 0, 266, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 83, 84, 0, 0, 40, 0, + 205, 275, 0, 199, 202, 107, 115, 204, 109, 200, + 206, 160, 159, 122, 123, 0, 158, 0, 162, 0, + 0, 27, 88, 0, 93, 93, 90, 0, 130, 0, + 0, 12, 0, 21, 0, 131, 277, 0, 11, 25, + 0, 0, 180, 0, 179, 189, 184, 189, 0, 0, + 9, 0, 0, 76, 75, 222, 0, 0, 43, 71, + 70, 267, 0, 68, 67, 65, 66, 64, 63, 62, + 60, 61, 55, 56, 57, 58, 59, 82, 81, 0, + 41, 0, 209, 0, 213, 0, 215, 0, 275, 0, + 110, 108, 0, 0, 294, 201, 201, 278, 0, 285, + 287, 0, 161, 221, 0, 91, 92, 96, 0, 97, + 0, 0, 128, 151, 147, 120, 19, 127, 148, 150, + 0, 23, 198, 196, 175, 0, 0, 131, 186, 190, + 187, 165, 169, 48, 50, 225, 0, 78, 0, 52, + 0, 79, 80, 208, 207, 0, 276, 0, 214, 210, + 212, 0, 124, 281, 157, 205, 275, 289, 290, 291, + 205, 292, 293, 279, 0, 280, 0, 0, 28, 223, + 0, 0, 123, 0, 0, 0, 125, 149, 0, 173, + 194, 0, 192, 0, 0, 72, 113, 0, 236, 239, + 0, 0, 0, 0, 0, 0, 0, 0, 264, 263, + 0, 0, 219, 0, 231, 235, 216, 142, 0, 138, + 143, 177, 69, 283, 282, 211, 209, 277, 0, 209, + 286, 288, 295, 224, 94, 95, 135, 0, 133, 129, + 20, 0, 24, 131, 191, 227, 0, 0, 0, 266, + 0, 0, 250, 252, 253, 254, 0, 0, 265, 0, + 261, 232, 0, 0, 228, 218, 217, 233, 139, 0, + 0, 0, 156, 153, 155, 0, 0, 0, 0, 126, + 193, 0, 0, 0, 0, 0, 248, 0, 255, 260, + 0, 0, 226, 0, 140, 0, 144, 53, 154, 0, + 0, 132, 134, 229, 0, 240, 242, 246, 0, 251, + 0, 262, 234, 141, 136, 137, 0, 237, 0, 266, + 0, 249, 268, 0, 230, 0, 0, 0, 247, 0, + 0, 269, 270, 256, 238, 0, 243, 0, 268, 0, + 0, 0, 266, 0, 0, 257, 271, 241, 0, 272, + 0, 0, 244, 273, 0, 258, 0, 0, 0, 245, + 259, 274, 0, 0, 0 +}; + +static const short yydefgoto[] = { 513, + 1, 2, 3, 15, 16, 17, 195, 336, 201, 339, + 93, 265, 361, 73, 362, 240, 75, 76, 77, 78, + 79, 133, 80, 182, 183, 18, 184, 185, 49, 186, + 81, 166, 21, 109, 98, 39, 94, 99, 392, 40, + 335, 189, 388, 389, 371, 372, 175, 101, 318, 102, + 22, 121, 123, 114, 50, 422, 204, 52, 53, 119, + 289, 290, 112, 113, 83, 164, 84, 85, 165, 364, + 414, 187, 297, 329, 365, 366, 467, 367, 444, 398, + 476, 399, 469, 470, 493, 507, 471, 459, 438, 442, + 410, 223, 481, 482, 483, 505, 245, 246, 177, 178, + 258, 307, 259, 260, 261, 262 +}; + +static const short yypact[] = { 61, + 71, 1439, 1439, 210,-32768,-32768,-32768,-32768, 35, 37, + 39, 79, 109,-32768,-32768,-32768,-32768, 86, 36, 131, +-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768, 53,-32768, + 63,-32768, 84, 163, 1292,-32768,-32768, 86, 19,-32768, + 731,-32768, 267,-32768,-32768,-32768, 86,-32768, 467, 338, +-32768, 116, 389,-32768, 122,-32768,-32768, 76,-32768,-32768, +-32768, 1359, 1372,-32768,-32768,-32768, 1426,-32768,-32768, 369, +-32768,-32768, 1426, 135, 158,-32768,-32768, 1495, 844, 227, + 124,-32768, 187, 1450, 273, 190,-32768, 267,-32768, 220, +-32768, 947, 51, 223,-32768,-32768, 267, 26,-32768, 932, + 306, 310, 29, 768, 467,-32768,-32768,-32768,-32768,-32768, + 245, 217,-32768, 338,-32768,-32768,-32768,-32768, 229, 515, +-32768,-32768,-32768,-32768, 240, 369,-32768, 369,-32768,-32768, + 247, 264, 239, 266,-32768,-32768, 1426, 1426, 1426, 1426, + 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1426, + 1426, 1426, 1426, 1426,-32768,-32768, 338, 338, 1426, 1426, +-32768, 124, 970,-32768, 349, 154,-32768,-32768,-32768,-32768, +-32768, 310,-32768,-32768, 308, 163,-32768, 302,-32768, 261, + 287,-32768, 457, 487, 292, 260,-32768, 314, 325, 46, + 298,-32768, 267,-32768, 51, 223,-32768, 1015,-32768,-32768, + 51, 1426, 338, 312, 217, 182,-32768, 182, 315, 328, +-32768, 334, 337,-32768,-32768, 347, 361, 1231, 1495, 1495, + 1495,-32768, 382, 1524, 832, 1535, 707, 538, 598, 923, + 237, 237, 246, 246,-32768,-32768,-32768,-32768,-32768, 366, + 158, 363, 102, 329,-32768, 699,-32768, 364,-32768, 1038, +-32768, 154, 112, 368,-32768, 100, 806,-32768, 374, 376, +-32768, 10,-32768,-32768, 33,-32768,-32768,-32768, 267,-32768, + 86, 385,-32768, 306,-32768,-32768,-32768, 413,-32768,-32768, + 386,-32768, 1495,-32768,-32768, 387, 1426, 189, 390,-32768, + 390,-32768,-32768,-32768,-32768,-32768, 548,-32768, 880,-32768, + 1426,-32768,-32768, 349,-32768, 394,-32768, 396,-32768,-32768, +-32768, 392,-32768,-32768,-32768,-32768, 107, 354, 310,-32768, +-32768, 310,-32768,-32768, 429,-32768, 451, 239,-32768,-32768, + 193, 198, 27, 455, 880, 33,-32768,-32768, 33,-32768, + 1495, 1426,-32768, 182, 353, 425, 431, 411,-32768,-32768, + 421, 422, 1426, 434, 424, 426, 1305, 338, 476,-32768, + 452, 439, 1145, 609,-32768, 471,-32768,-32768, 288, 1495, +-32768, 427, 1511,-32768,-32768,-32768, 333,-32768, 1083, 255, +-32768,-32768,-32768,-32768,-32768,-32768, 462, 92,-32768,-32768, +-32768, 880,-32768, 1477,-32768,-32768, 1426, 463, 1206, 1426, + 1426, 486,-32768,-32768,-32768,-32768, 465, 466,-32768, 470, +-32768,-32768, 670, 475,-32768,-32768,-32768,-32768,-32768, -11, + 796, 477, 354,-32768,-32768, 480, 219, 473, 455,-32768, +-32768, 478, 1426, 522, 482, 484,-32768, 1206,-32768,-32768, + 163, 1206,-32768, 1206,-32768, 857,-32768,-32768,-32768, 501, + 176,-32768,-32768,-32768, 507,-32768,-32768,-32768, 1206,-32768, + 65,-32768,-32768,-32768,-32768,-32768, 1206,-32768, 533, 1426, + 1206,-32768, 580, 532,-32768, 1206, 1426, 537,-32768, 536, + 12, 534,-32768,-32768,-32768, 540,-32768, 1426, 580, 542, + 580, 543, 1426, 545, 13,-32768,-32768,-32768, 547,-32768, + 163, 549,-32768, 227, 186,-32768, 1206, 556, 163,-32768, +-32768, 227, 605, 615,-32768 +}; + +static const short yypgoto[] = {-32768, +-32768,-32768,-32768, 613,-32768,-32768,-32768,-32768,-32768,-32768, +-32768,-32768, -6,-32768, -33,-32768, 460, 359, -41, 57, +-32768,-32768, -34, -135, 324, 5, -148, 4, 574, 6, + 570, 456, -8, -147, 378, -30, -64, -65,-32768,-32768, +-32768, -182,-32768, 208, -306, 280, -32, -66, 274, -17, + -27,-32768,-32768,-32768,-32768,-32768, 445, -4,-32768,-32768, + 444, 313, 544, 453, 3, -69, 608, -86, -146, 299, +-32768, -171,-32768, -110, -115,-32768,-32768, -181,-32768,-32768, +-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768, +-32768, -380, 174,-32768, 175,-32768, 416,-32768, -164,-32768, +-32768,-32768, 430,-32768, 350, 250 +}; + + +#define YYLAST 1583 + + +static const short yytable[] = { 58, + 41, 74, 29, 31, 33, 19, 19, 20, 20, 190, + 100, 48, 267, 278, 170, 244, 103, 217, 251, 435, + 86, 110, 174, 43, 47, 130, 82, 55, 390, 104, + 191, 135, 279, 328, 266, 196, 132, 26, 27, 26, + 27, 26, 27, 111, 82, 489, 501, 445, 36, 95, + 446, 181, 171, 90, 5, 6, 7, 8, 180, 277, + -1, 82, 9, 10, 11, 282, 326, 172, 490, 502, + -2, 327, 134, 124, 243, 169, 87, 110, 13, 86, + 88, 91, 92, 192, 124, 430, 199, 193, 36, 478, + 88, 96, 132, 42, 132, 216, 304, 28, 473, 30, + 97, 32, 36, 315, 251, 343, 222, 111, 171, 36, + 196, 169, 499, -87, 447, 51, 209, 82, 210, 82, + 124, 474, 206, 274, 208, 54, 242, 276, 212, 248, + 213, 37, 125, 34, 5, 44, 7, 45, 110, 447, + 38, 253, 9, 10, 11, 316, 56, 161, 428, 330, + 238, 239, 321, 429, 317, 163, 162, 163, 13, 107, + 108, 317, 163, 35, 281, 9, 10, 11, 313, 161, + 244, 57, 172, 288, 115, 288, 300, 48, 162, 163, + 122, 256, 417, 257, 36, 95, 320, 323, 46, 269, + 271, 136, 416, 219, 220, 221, 111, 224, 225, 226, + 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, + 237, 431, 384, 424, 266, 287, 312, 434, 188, 137, + 330, 255, 342, 330, 110, 391, 450, 96, 393, 377, + 304, 417, 466, 304, 380, 124, 97, 327, 319, 322, + 332, 416, 508, 167, 91, 92, 173, 509, 48, 256, + 385, 257, 188, 333, 193, 386, 460, 36, 283, 88, + 462, 171, 463, 5, 44, 7, 45, 24, 25, 36, + 95, 9, 10, 11, 176, 36, 202, 472, 203, 171, + 150, 151, 152, 153, 154, 475, 207, 13, 368, 479, + 59, 152, 153, 154, 485, 61, 57, 211, 62, 86, + 321, 216, 254, 214, 255, 5, 6, 7, 8, 317, + 163, 288, 96, 9, 10, 11, 63, 270, 37, 402, + 215, 97, 218, 407, 263, 510, 64, 38, 256, 13, + 257, 65, 66, 67, 90, 36, 315, 68, 69, 171, + 26, 27, 70, 341, 264, 426, 419, 71, 72, 268, + 369, 408, 197, 198, 275, 370, 273, 373, -284, 172, + 197, 198, 172, 432, 91, 92, 222, 436, 272, 131, + 285, 59, 5, 292, 7, 60, 61, 57, 316, 62, + 9, 10, 11, 249, 250, 305, 293, 317, 163, 116, + 294, 370, 5, 295, 7, 60, 13, 63, 394, 455, + 9, 10, 11, 249, 250, 296, 461, 64, 378, 379, + 264, 396, 65, 66, 67, 301, 13, 298, 68, 69, + 127, 129, 302, 70, 314, 370, 303, 309, 71, 72, + 324, -77, 5, 6, 7, 8, 222, 325, 381, 334, + 9, 10, 11, 486, 337, 340, 117, -181, 370, 338, + 374, 344, 375, 383, 494, 376, 13, 387, -30, 222, + 5, 6, 7, 8, -31, 397, 504, 403, 9, 10, + 11, 106, 107, 108, 512, 400, 401, 370, 9, 10, + 11, 404, 409, 405, 13, 411, 418, 181, 421, -89, + -89, -89, -89, -89, -89, -89, 412, -89, -89, -89, + -89, -89, 370, -89, -89, -89, -89, -89, -89, -89, + -89, -89, -89, -89, -89, -89, 427, 433, 5, 437, + 7, 168, 439, 440, 441, -89, 9, 10, 11, 452, + -89, -89, -89, 443, 454, 448, -89, -89, 456, 457, + 458, -89, 13, 449, -89, -89, -89, -89, 345, -89, + 346, 347, 6, 7, 8, 61, 57, 465, 62, 9, + 10, 11, 348, 468, 349, 350, 351, 352, 353, 354, + 355, 356, 357, 358, 359, 13, 63, 146, 147, 148, + 149, 150, 151, 152, 153, 154, 64, 477, 480, 484, + 488, 65, 66, 67, 487, 491, 492, 68, 69, 496, + 498, 500, 70, 503, 514, 360, 506, 71, 72, 181, + 216, 346, 27, 511, 515, 23, 61, 57, 241, 62, + 363, 105, 118, 348, 252, 349, 350, 351, 352, 353, + 354, 355, 356, 357, 358, 359, 453, 63, 147, 148, + 149, 150, 151, 152, 153, 154, 331, 64, 420, 286, + 423, 291, 65, 66, 67, 284, 395, 205, 68, 69, + 120, 413, 495, 70, 310, 497, 360, 415, 71, 72, + 181, 216, 346, 27, 382, 308, 451, 61, 57, 0, + 62, 0, 0, 0, 348, 0, 349, 350, 351, 352, + 353, 354, 355, 356, 357, 358, 359, 0, 63, 306, + 0, 0, 5, 6, 7, 8, 0, 0, 64, 0, + 9, 10, 11, 65, 66, 67, 0, 0, 0, 68, + 69, 0, 0, 0, 70, 0, 13, 360, -220, 71, + 72, 89, 216, 0, -26, -26, -26, -26, 0, 0, + 0, 0, -26, -26, -26, 145, 146, 147, 148, 149, + 150, 151, 152, 153, 154, -284, 0, 90, -26, 0, + -123, 0, -123, 0, 0, 0, 0, 0, 200, 0, + 0, -22, -22, -22, -22, 0, 0, 0, 0, -22, + -22, -22, 0, 0, 0, 91, 92, 0, -123, 0, + 0, 0, -123, -26, 90, -22, 368, -123, 59, -123, + 0, 0, 0, 61, 57, 0, 62, 0, 36, 5, + 44, 7, 45, 0, 0, 0, 0, 9, 10, 11, + 0, 0, 91, 92, 63, -123, 0, 0, 0, -123, + -22, 0, 0, 13, 64, 0, 0, 0, 0, 65, + 66, 67, 0, 0, 0, 68, 69, 0, 0, 0, + 70, 321, 0, 0, -178, 71, 72, 368, 369, 59, + 317, 163, 0, 0, 61, 57, 0, 62, 143, 144, + 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, + 368, 0, 59, 0, 0, 63, 0, 61, 57, 0, + 62, 0, 0, 155, 156, 64, 157, 158, 159, 160, + 65, 66, 67, 0, 0, 0, 68, 69, 63, 0, + 0, 70, 0, 0, 0, 464, 71, 72, 64, 369, + 0, 0, 0, 65, 66, 67, 0, 0, 0, 68, + 69, 0, 194, 0, 70, -18, -18, -18, -18, 71, + 72, 0, 369, -18, -18, -18, 0, 0, 0, 59, + 0, 0, 0, 0, 61, 57, 0, 62, 90, -18, + 0, -123, 0, -123, 148, 149, 150, 151, 152, 153, + 154, 0, 59, 0, 0, 63, 0, 61, 57, 0, + 62, 0, 0, 0, 0, 64, 0, 0, 0, -123, + 65, 66, 67, -123, -18, 0, 68, 69, 63, 0, + 0, 70, 0, 0, 0, 0, 71, 72, 64, 0, + 179, 0, 0, 65, 66, 67, 0, 59, 0, 68, + 69, 0, 61, 57, 70, 62, 0, 0, 0, 71, + 72, 0, 0, 247, 0, 0, 0, 0, 0, 0, + 59, 0, 0, 63, 0, 61, 57, 0, 62, 0, + 0, 0, 0, 64, 0, 0, 0, 0, 65, 66, + 67, 0, 0, 0, 68, 69, 63, 0, 0, 70, + 0, 0, 0, 0, 71, 72, 64, 0, 280, 0, + 0, 65, 66, 67, 0, 59, 0, 68, 69, 0, + 61, 57, 70, 62, 0, 0, 0, 71, 72, 0, + 0, 311, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 63, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 64, 0, 0, 0, 0, 65, 66, 67, 0, + 0, 0, 68, 69, 0, 0, 0, 70, 0, 0, + 0, 0, 71, 72, 0, 0, 425, 346, 347, 6, + 7, 8, 61, 57, 0, 62, 9, 10, 11, 348, + 0, 349, 350, 351, 352, 353, 354, 355, 356, 357, + 358, 359, 13, 63, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 64, 0, 0, 0, 0, 65, 66, + 67, 0, 0, 0, 68, 69, 0, 0, 0, 70, + 0, 0, 360, 0, 71, 72, 0, 216, 346, 27, + 0, 0, 0, 61, 57, 0, 62, 0, 0, 0, + 348, 0, 349, 350, 351, 352, 353, 354, 355, 356, + 357, 358, 359, 59, 63, 0, 0, 0, 61, 57, + 0, 62, 0, 0, 64, 0, 0, 0, 0, 65, + 66, 67, 0, 0, 0, 68, 69, 0, 0, 63, + 70, 0, 0, 360, 0, 71, 72, 0, 216, 64, + 0, 0, 0, 0, 65, 66, 67, 0, 0, 0, + 68, 69, 0, 0, 0, 70, 0, 0, 0, 0, + 71, 72, 0, 299, 59, 5, 0, 7, 60, 61, + 57, 0, 62, 9, 10, 11, 0, 59, 0, 0, + 0, 0, 61, 57, 0, 62, 0, 0, 0, 13, + 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 64, 0, 0, 63, 0, 65, 66, 67, 0, 0, + 0, 68, 69, 64, 0, 0, 70, 0, 65, 66, + 67, 71, 72, 0, 68, 69, 0, 0, 0, 70, + 0, 59, 406, 0, 71, 72, 61, 57, 0, 62, + 0, 0, 0, 0, 59, 0, 0, 0, 0, 61, + 57, 0, 62, 0, 0, 0, 0, 63, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, + 63, 0, 65, 66, 67, 0, 0, 0, 68, 69, + 64, 0, 0, 126, 0, 65, 66, 67, 71, 72, + 0, 68, 69, 0, 0, 0, 128, 0, 59, 0, + 0, 71, 72, 61, 57, 0, 62, 0, 0, 4, + 0, -93, 5, 6, 7, 8, 0, 0, 0, 0, + 9, 10, 11, 5, 63, 7, 168, 0, 0, 0, + 0, 9, 10, 11, 64, 12, 13, 0, 0, 65, + 66, 67, 0, 0, 0, 68, 69, 13, 0, 0, + 70, 0, 0, 0, -93, 71, 72, 0, 0, 0, + 0, 0, 0, -93, 0, 161, 14, 0, 0, 0, + 0, 0, 0, 0, 162, 163, 188, 138, 139, 140, + 0, 141, 142, 143, 144, 145, 146, 147, 148, 149, + 150, 151, 152, 153, 154, 138, 139, 140, 0, 141, + 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, + 152, 153, 154, 140, 0, 141, 142, 143, 144, 145, + 146, 147, 148, 149, 150, 151, 152, 153, 154, 142, + 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, + 153, 154, 144, 145, 146, 147, 148, 149, 150, 151, + 152, 153, 154 +}; + +static const short yycheck[] = { 34, + 18, 35, 9, 10, 11, 2, 3, 2, 3, 96, + 43, 20, 184, 196, 84, 162, 47, 133, 166, 400, + 38, 49, 88, 19, 20, 67, 35, 32, 335, 47, + 97, 73, 197, 1, 183, 100, 70, 3, 4, 3, + 4, 3, 4, 50, 53, 34, 34, 59, 3, 4, + 62, 1, 7, 27, 4, 5, 6, 7, 92, 195, + 0, 70, 12, 13, 14, 201, 57, 85, 57, 57, + 0, 62, 70, 9, 161, 84, 58, 105, 28, 97, + 62, 55, 56, 58, 9, 392, 58, 62, 3, 470, + 62, 46, 126, 58, 128, 63, 243, 63, 34, 63, + 55, 63, 3, 4, 252, 288, 140, 114, 7, 3, + 175, 120, 493, 63, 421, 63, 121, 126, 123, 128, + 9, 57, 118, 190, 120, 63, 160, 193, 126, 163, + 128, 46, 57, 55, 4, 5, 6, 7, 166, 446, + 55, 176, 12, 13, 14, 46, 63, 46, 57, 265, + 157, 158, 46, 62, 55, 56, 55, 56, 28, 6, + 7, 55, 56, 55, 198, 12, 13, 14, 57, 46, + 317, 9, 190, 206, 59, 208, 218, 186, 55, 56, + 59, 178, 364, 178, 3, 4, 256, 257, 58, 185, + 186, 57, 364, 137, 138, 139, 203, 141, 142, 143, + 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, + 154, 394, 328, 378, 363, 34, 250, 399, 30, 62, + 336, 3, 34, 339, 252, 336, 8, 46, 339, 316, + 377, 413, 57, 380, 321, 9, 55, 62, 256, 257, + 271, 413, 57, 57, 55, 56, 57, 62, 257, 246, + 58, 246, 30, 271, 62, 58, 438, 3, 202, 62, + 442, 7, 444, 4, 5, 6, 7, 58, 59, 3, + 4, 12, 13, 14, 55, 3, 32, 459, 62, 7, + 44, 45, 46, 47, 48, 467, 58, 28, 1, 471, + 3, 46, 47, 48, 476, 8, 9, 58, 11, 317, + 46, 63, 1, 57, 3, 4, 5, 6, 7, 55, + 56, 344, 46, 12, 13, 14, 29, 58, 46, 353, + 57, 55, 57, 357, 64, 507, 39, 55, 325, 28, + 325, 44, 45, 46, 27, 3, 4, 50, 51, 7, + 3, 4, 55, 287, 58, 379, 59, 60, 61, 58, + 63, 358, 55, 56, 57, 299, 32, 301, 57, 377, + 55, 56, 380, 397, 55, 56, 400, 401, 55, 1, + 59, 3, 4, 59, 6, 7, 8, 9, 46, 11, + 12, 13, 14, 55, 56, 57, 59, 55, 56, 1, + 57, 335, 4, 57, 6, 7, 28, 29, 342, 433, + 12, 13, 14, 55, 56, 59, 441, 39, 55, 56, + 58, 59, 44, 45, 46, 34, 28, 57, 50, 51, + 62, 63, 57, 55, 57, 369, 64, 64, 60, 61, + 57, 63, 4, 5, 6, 7, 470, 62, 10, 55, + 12, 13, 14, 477, 32, 59, 58, 59, 392, 64, + 57, 62, 57, 3, 488, 64, 28, 3, 34, 493, + 4, 5, 6, 7, 34, 55, 501, 34, 12, 13, + 14, 5, 6, 7, 509, 55, 55, 421, 12, 13, + 14, 58, 7, 58, 28, 34, 16, 1, 62, 3, + 4, 5, 6, 7, 8, 9, 58, 11, 12, 13, + 14, 15, 446, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 55, 55, 4, 34, + 6, 7, 58, 58, 55, 39, 12, 13, 14, 57, + 44, 45, 46, 59, 57, 59, 50, 51, 17, 58, + 57, 55, 28, 64, 58, 59, 60, 61, 1, 63, + 3, 4, 5, 6, 7, 8, 9, 57, 11, 12, + 13, 14, 15, 57, 17, 18, 19, 20, 21, 22, + 23, 24, 25, 26, 27, 28, 29, 40, 41, 42, + 43, 44, 45, 46, 47, 48, 39, 55, 9, 58, + 55, 44, 45, 46, 58, 62, 57, 50, 51, 58, + 58, 57, 55, 57, 0, 58, 58, 60, 61, 1, + 63, 3, 4, 58, 0, 3, 8, 9, 159, 11, + 297, 48, 53, 15, 169, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 429, 29, 41, 42, + 43, 44, 45, 46, 47, 48, 269, 39, 369, 205, + 377, 208, 44, 45, 46, 203, 344, 114, 50, 51, + 53, 363, 489, 55, 249, 491, 58, 59, 60, 61, + 1, 63, 3, 4, 325, 246, 427, 8, 9, -1, + 11, -1, -1, -1, 15, -1, 17, 18, 19, 20, + 21, 22, 23, 24, 25, 26, 27, -1, 29, 1, + -1, -1, 4, 5, 6, 7, -1, -1, 39, -1, + 12, 13, 14, 44, 45, 46, -1, -1, -1, 50, + 51, -1, -1, -1, 55, -1, 28, 58, 59, 60, + 61, 1, 63, -1, 4, 5, 6, 7, -1, -1, + -1, -1, 12, 13, 14, 39, 40, 41, 42, 43, + 44, 45, 46, 47, 48, 57, -1, 27, 28, -1, + 30, -1, 32, -1, -1, -1, -1, -1, 1, -1, + -1, 4, 5, 6, 7, -1, -1, -1, -1, 12, + 13, 14, -1, -1, -1, 55, 56, -1, 58, -1, + -1, -1, 62, 63, 27, 28, 1, 30, 3, 32, + -1, -1, -1, 8, 9, -1, 11, -1, 3, 4, + 5, 6, 7, -1, -1, -1, -1, 12, 13, 14, + -1, -1, 55, 56, 29, 58, -1, -1, -1, 62, + 63, -1, -1, 28, 39, -1, -1, -1, -1, 44, + 45, 46, -1, -1, -1, 50, 51, -1, -1, -1, + 55, 46, -1, -1, 59, 60, 61, 1, 63, 3, + 55, 56, -1, -1, 8, 9, -1, 11, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 1, -1, 3, -1, -1, 29, -1, 8, 9, -1, + 11, -1, -1, 50, 51, 39, 53, 54, 55, 56, + 44, 45, 46, -1, -1, -1, 50, 51, 29, -1, + -1, 55, -1, -1, -1, 59, 60, 61, 39, 63, + -1, -1, -1, 44, 45, 46, -1, -1, -1, 50, + 51, -1, 1, -1, 55, 4, 5, 6, 7, 60, + 61, -1, 63, 12, 13, 14, -1, -1, -1, 3, + -1, -1, -1, -1, 8, 9, -1, 11, 27, 28, + -1, 30, -1, 32, 42, 43, 44, 45, 46, 47, + 48, -1, 3, -1, -1, 29, -1, 8, 9, -1, + 11, -1, -1, -1, -1, 39, -1, -1, -1, 58, + 44, 45, 46, 62, 63, -1, 50, 51, 29, -1, + -1, 55, -1, -1, -1, -1, 60, 61, 39, -1, + 64, -1, -1, 44, 45, 46, -1, 3, -1, 50, + 51, -1, 8, 9, 55, 11, -1, -1, -1, 60, + 61, -1, -1, 64, -1, -1, -1, -1, -1, -1, + 3, -1, -1, 29, -1, 8, 9, -1, 11, -1, + -1, -1, -1, 39, -1, -1, -1, -1, 44, 45, + 46, -1, -1, -1, 50, 51, 29, -1, -1, 55, + -1, -1, -1, -1, 60, 61, 39, -1, 64, -1, + -1, 44, 45, 46, -1, 3, -1, 50, 51, -1, + 8, 9, 55, 11, -1, -1, -1, 60, 61, -1, + -1, 64, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 29, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 39, -1, -1, -1, -1, 44, 45, 46, -1, + -1, -1, 50, 51, -1, -1, -1, 55, -1, -1, + -1, -1, 60, 61, -1, -1, 64, 3, 4, 5, + 6, 7, 8, 9, -1, 11, 12, 13, 14, 15, + -1, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 29, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 39, -1, -1, -1, -1, 44, 45, + 46, -1, -1, -1, 50, 51, -1, -1, -1, 55, + -1, -1, 58, -1, 60, 61, -1, 63, 3, 4, + -1, -1, -1, 8, 9, -1, 11, -1, -1, -1, + 15, -1, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 3, 29, -1, -1, -1, 8, 9, + -1, 11, -1, -1, 39, -1, -1, -1, -1, 44, + 45, 46, -1, -1, -1, 50, 51, -1, -1, 29, + 55, -1, -1, 58, -1, 60, 61, -1, 63, 39, + -1, -1, -1, -1, 44, 45, 46, -1, -1, -1, + 50, 51, -1, -1, -1, 55, -1, -1, -1, -1, + 60, 61, -1, 63, 3, 4, -1, 6, 7, 8, + 9, -1, 11, 12, 13, 14, -1, 3, -1, -1, + -1, -1, 8, 9, -1, 11, -1, -1, -1, 28, + 29, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 39, -1, -1, 29, -1, 44, 45, 46, -1, -1, + -1, 50, 51, 39, -1, -1, 55, -1, 44, 45, + 46, 60, 61, -1, 50, 51, -1, -1, -1, 55, + -1, 3, 58, -1, 60, 61, 8, 9, -1, 11, + -1, -1, -1, -1, 3, -1, -1, -1, -1, 8, + 9, -1, 11, -1, -1, -1, -1, 29, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 39, -1, -1, + 29, -1, 44, 45, 46, -1, -1, -1, 50, 51, + 39, -1, -1, 55, -1, 44, 45, 46, 60, 61, + -1, 50, 51, -1, -1, -1, 55, -1, 3, -1, + -1, 60, 61, 8, 9, -1, 11, -1, -1, 1, + -1, 3, 4, 5, 6, 7, -1, -1, -1, -1, + 12, 13, 14, 4, 29, 6, 7, -1, -1, -1, + -1, 12, 13, 14, 39, 27, 28, -1, -1, 44, + 45, 46, -1, -1, -1, 50, 51, 28, -1, -1, + 55, -1, -1, -1, 46, 60, 61, -1, -1, -1, + -1, -1, -1, 55, -1, 46, 58, -1, -1, -1, + -1, -1, -1, -1, 55, 56, 30, 31, 32, 33, + -1, 35, 36, 37, 38, 39, 40, 41, 42, 43, + 44, 45, 46, 47, 48, 31, 32, 33, -1, 35, + 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 33, -1, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, 48, 36, + 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, + 47, 48, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48 +}; +/* -*-C-*- Note some compilers choke on comments on `#line' lines. */ +#line 3 "bison.simple" + +/* Skeleton output parser for bison, + Copyright (C) 1984, 1989, 1990 Bob Corbett and Richard Stallman + + 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. + + 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. */ + + +#ifndef alloca +#ifdef __GNUC__ +#define alloca __builtin_alloca +#else /* Not GNU C. */ +#if (!defined (__STDC__) && defined (sparc)) || defined (__sparc__) +#include +#endif /* Sparc. */ +#endif /* Not GNU C. */ +#endif /* alloca not defined. */ + +/* This is the parser code that is written into each bison parser + when the %semantic_parser declaration is not specified in the grammar. + It was written by Richard Stallman by simplifying the hairy parser + used when %semantic_parser is specified. */ + +/* Note: there must be only one dollar sign in this file. + It is replaced by the list of actions, each action + as one case of the switch. */ + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY -2 +#define YYEOF 0 +#define YYACCEPT return(0) +#define YYABORT return(1) +#define YYERROR goto yyerrlab1 +/* Like YYERROR except do call yyerror. + This remains here temporarily to ease the + transition to the new meaning of YYERROR, for GCC. + Once GCC version 2 has supplanted version 1, this can go. */ +#define YYFAIL goto yyerrlab +#define YYRECOVERING() (!!yyerrstatus) +#define YYBACKUP(token, value) \ +do \ + if (yychar == YYEMPTY && yylen == 1) \ + { yychar = (token), yylval = (value); \ + yychar1 = YYTRANSLATE (yychar); \ + YYPOPSTACK; \ + goto yybackup; \ + } \ + else \ + { yyerror ("syntax error: cannot back up"); YYERROR; } \ +while (0) + +#define YYTERROR 1 +#define YYERRCODE 256 + +#ifndef YYPURE +#define YYLEX yylex() +#endif + +#ifdef YYPURE +#ifdef YYLSP_NEEDED +#define YYLEX yylex(&yylval, &yylloc) +#else +#define YYLEX yylex(&yylval) +#endif +#endif + +/* If nonreentrant, generate the variables here */ + +#ifndef YYPURE + +int yychar; /* the lookahead symbol */ +YYSTYPE yylval; /* the semantic value of the */ + /* lookahead symbol */ + +#ifdef YYLSP_NEEDED +YYLTYPE yylloc; /* location data for the lookahead */ + /* symbol */ +#endif + +int yynerrs; /* number of parse errors so far */ +#endif /* not YYPURE */ + +#if YYDEBUG != 0 +int yydebug; /* nonzero means print parse trace */ +/* Since this is uninitialized, it does not stop multiple parsers + from coexisting. */ +#endif + +/* YYINITDEPTH indicates the initial size of the parser's stacks */ + +#ifndef YYINITDEPTH +#define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH is the maximum size the stacks can grow to + (effective only if the built-in stack extension method is used). */ + +#if YYMAXDEPTH == 0 +#undef YYMAXDEPTH +#endif + +#ifndef YYMAXDEPTH +#define YYMAXDEPTH 10000 +#endif + +#ifndef __cplusplus + +/* This is the most reliable way to avoid incompatibilities + in available built-in functions on various systems. */ +static void +__yy_bcopy (from, to, count) + char *from; + char *to; + int count; +{ + register char *f = from; + register char *t = to; + register int i = count; + + while (i-- > 0) + *t++ = *f++; +} + +#else /* __cplusplus */ + +/* This is the most reliable way to avoid incompatibilities + in available built-in functions on various systems. */ +static void +__yy_bcopy (char *from, char *to, int count) +{ + register char *f = from; + register char *t = to; + register int i = count; + + while (i-- > 0) + *t++ = *f++; +} + +#endif + +#line 156 "bison.simple" +int +yyparse() +{ + register int yystate; + register int yyn; + register short *yyssp; + register YYSTYPE *yyvsp; + int yyerrstatus; /* number of tokens to shift before error messages enabled */ + int yychar1; /* lookahead token as an internal (translated) token number */ + + short yyssa[YYINITDEPTH]; /* the state stack */ + YYSTYPE yyvsa[YYINITDEPTH]; /* the semantic value stack */ + + short *yyss = yyssa; /* refer to the stacks thru separate pointers */ + YYSTYPE *yyvs = yyvsa; /* to allow yyoverflow to reallocate them elsewhere */ + +#ifdef YYLSP_NEEDED + YYLTYPE *yyls = yylsa; + YYLTYPE *yylsp; + YYLTYPE yylsa[YYINITDEPTH]; /* the location stack */ + +#define YYPOPSTACK (yyvsp--, yysp--, yylsp--) +#else +#define YYPOPSTACK (yyvsp--, yysp--) +#endif + + int yystacksize = YYINITDEPTH; + +#ifdef YYPURE + int yychar; + YYSTYPE yylval; + int yynerrs; +#ifdef YYLSP_NEEDED + YYLTYPE yylloc; +#endif +#endif + + YYSTYPE yyval; /* the variable used to return */ + /* semantic values from the action */ + /* routines */ + + int yylen; + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Starting parse\n"); +#endif + + yystate = 0; + yyerrstatus = 0; + yynerrs = 0; + yychar = YYEMPTY; /* Cause a token to be read. */ + + /* Initialize stack pointers. + Waste one element of value and location stack + so that they stay on the same level as the state stack. */ + + yyssp = yyss - 1; + yyvsp = yyvs; +#ifdef YYLSP_NEEDED + yylsp = yyls; +#endif + +/* Push a new state, which is found in yystate . */ +/* In all cases, when you get here, the value and location stacks + have just been pushed. so pushing a state here evens the stacks. */ +yynewstate: + + *++yyssp = yystate; + + if (yyssp >= yyss + yystacksize - 1) + { + /* Give user a chance to reallocate the stack */ + /* Use copies of these so that the &'s don't force the real ones into memory. */ + YYSTYPE *yyvs1 = yyvs; + short *yyss1 = yyss; +#ifdef YYLSP_NEEDED + YYLTYPE *yyls1 = yyls; +#endif + + /* Get the current used size of the three stacks, in elements. */ + int size = yyssp - yyss + 1; + +#ifdef yyoverflow + /* Each stack pointer address is followed by the size of + the data in use in that stack, in bytes. */ + yyoverflow("parser stack overflow", + &yyss1, size * sizeof (*yyssp), + &yyvs1, size * sizeof (*yyvsp), +#ifdef YYLSP_NEEDED + &yyls1, size * sizeof (*yylsp), +#endif + &yystacksize); + + yyss = yyss1; yyvs = yyvs1; +#ifdef YYLSP_NEEDED + yyls = yyls1; +#endif +#else /* no yyoverflow */ + /* Extend the stack our own way. */ + if (yystacksize >= YYMAXDEPTH) + { + yyerror("parser stack overflow"); + return 2; + } + yystacksize *= 2; + if (yystacksize > YYMAXDEPTH) + yystacksize = YYMAXDEPTH; + yyss = (short *) alloca (yystacksize * sizeof (*yyssp)); + __yy_bcopy ((char *)yyss1, (char *)yyss, size * sizeof (*yyssp)); + yyvs = (YYSTYPE *) alloca (yystacksize * sizeof (*yyvsp)); + __yy_bcopy ((char *)yyvs1, (char *)yyvs, size * sizeof (*yyvsp)); +#ifdef YYLSP_NEEDED + yyls = (YYLTYPE *) alloca (yystacksize * sizeof (*yylsp)); + __yy_bcopy ((char *)yyls1, (char *)yyls, size * sizeof (*yylsp)); +#endif +#endif /* no yyoverflow */ + + yyssp = yyss + size - 1; + yyvsp = yyvs + size - 1; +#ifdef YYLSP_NEEDED + yylsp = yyls + size - 1; +#endif + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Stack size increased to %d\n", yystacksize); +#endif + + if (yyssp >= yyss + yystacksize - 1) + YYABORT; + } + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Entering state %d\n", yystate); +#endif + + yybackup: + +/* Do appropriate processing given the current state. */ +/* Read a lookahead token if we need one and don't already have one. */ +/* yyresume: */ + + /* First try to decide what to do without reference to lookahead token. */ + + yyn = yypact[yystate]; + if (yyn == YYFLAG) + goto yydefault; + + /* Not known => get a lookahead token if don't already have one. */ + + /* yychar is either YYEMPTY or YYEOF + or a valid token in external form. */ + + if (yychar == YYEMPTY) + { +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Reading a token: "); +#endif + yychar = YYLEX; + } + + /* Convert token to internal form (in yychar1) for indexing tables with */ + + if (yychar <= 0) /* This means end of input. */ + { + yychar1 = 0; + yychar = YYEOF; /* Don't call YYLEX any more */ + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Now at end of input.\n"); +#endif + } + else + { + yychar1 = YYTRANSLATE(yychar); + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Next token is %d (%s)\n", yychar, yytname[yychar1]); +#endif + } + + yyn += yychar1; + if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != yychar1) + goto yydefault; + + yyn = yytable[yyn]; + + /* yyn is what to do for this token type in this state. + Negative => reduce, -yyn is rule number. + Positive => shift, yyn is new state. + New state is final state => don't bother to shift, + just return success. + 0, or most negative number => error. */ + + if (yyn < 0) + { + if (yyn == YYFLAG) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + else if (yyn == 0) + goto yyerrlab; + + if (yyn == YYFINAL) + YYACCEPT; + + /* Shift the lookahead token. */ + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Shifting token %d (%s), ", yychar, yytname[yychar1]); +#endif + + /* Discard the token being shifted unless it is eof. */ + if (yychar != YYEOF) + yychar = YYEMPTY; + + *++yyvsp = yylval; +#ifdef YYLSP_NEEDED + *++yylsp = yylloc; +#endif + + /* count tokens shifted since error; after three, turn off error status. */ + if (yyerrstatus) yyerrstatus--; + + yystate = yyn; + goto yynewstate; + +/* Do the default action for the current state. */ +yydefault: + + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + +/* Do a reduction. yyn is the number of a rule to reduce with. */ +yyreduce: + yylen = yyr2[yyn]; + yyval = yyvsp[1-yylen]; /* implement default value of the action */ + +#if YYDEBUG != 0 + if (yydebug) + { + int i; + + fprintf (stderr, "Reducing via rule %d (line %d), ", + yyn, yyrline[yyn]); + + /* Print the symboles being reduced, and their result. */ + for (i = yyprhs[yyn]; yyrhs[i] > 0; i++) + fprintf (stderr, "%s ", yytname[yyrhs[i]]); + fprintf (stderr, " -> %s\n", yytname[yyr1[yyn]]); + } +#endif + + + switch (yyn) { + +case 3: +#line 186 "ccdir/c-parse.y" +{yyval.ttype = NULL_TREE; ; + break;} +case 5: +#line 187 "ccdir/c-parse.y" +{yyval.ttype = NULL_TREE; ; + break;} +case 9: +#line 194 "ccdir/c-parse.y" +{ if (pedantic) + warning ("ANSI C forbids use of `asm' keyword"); + if (TREE_CHAIN (yyvsp[-2].ttype)) yyvsp[-2].ttype = combine_strings (yyvsp[-2].ttype); + assemble_asm (yyvsp[-2].ttype); ; + break;} +case 10: +#line 202 "ccdir/c-parse.y" +{ if (pedantic) + error ("ANSI C forbids data definition lacking type or storage class"); + else if (!flag_traditional) + warning ("data definition lacks type or storage class"); ; + break;} +case 11: +#line 207 "ccdir/c-parse.y" +{; + break;} +case 12: +#line 209 "ccdir/c-parse.y" +{; + break;} +case 13: +#line 211 "ccdir/c-parse.y" +{ error ("empty declaration"); ; + break;} +case 14: +#line 213 "ccdir/c-parse.y" +{ shadow_tag (yyvsp[-1].ttype); ; + break;} +case 17: +#line 217 "ccdir/c-parse.y" +{ if (pedantic) + warning ("ANSI C does not allow extra `;' outside of a function"); ; + break;} +case 18: +#line 223 "ccdir/c-parse.y" +{ if (! start_function (yyvsp[-2].ttype, yyvsp[0].ttype)) + YYFAIL; + reinit_parse_for_function (); ; + break;} +case 19: +#line 227 "ccdir/c-parse.y" +{ store_parm_decls (); ; + break;} +case 20: +#line 229 "ccdir/c-parse.y" +{ finish_function (lineno); ; + break;} +case 21: +#line 231 "ccdir/c-parse.y" +{ ; + break;} +case 22: +#line 233 "ccdir/c-parse.y" +{ if (! start_function (yyvsp[-2].ttype, yyvsp[0].ttype)) + YYFAIL; + reinit_parse_for_function (); ; + break;} +case 23: +#line 237 "ccdir/c-parse.y" +{ store_parm_decls (); ; + break;} +case 24: +#line 239 "ccdir/c-parse.y" +{ finish_function (lineno); ; + break;} +case 25: +#line 241 "ccdir/c-parse.y" +{ ; + break;} +case 26: +#line 243 "ccdir/c-parse.y" +{ if (! start_function (0, yyvsp[0].ttype)) + YYFAIL; + reinit_parse_for_function (); ; + break;} +case 27: +#line 247 "ccdir/c-parse.y" +{ store_parm_decls (); ; + break;} +case 28: +#line 249 "ccdir/c-parse.y" +{ finish_function (lineno); ; + break;} +case 29: +#line 251 "ccdir/c-parse.y" +{ ; + break;} +case 32: +#line 260 "ccdir/c-parse.y" +{ yyval.code = ADDR_EXPR; ; + break;} +case 33: +#line 262 "ccdir/c-parse.y" +{ yyval.code = NEGATE_EXPR; ; + break;} +case 34: +#line 264 "ccdir/c-parse.y" +{ yyval.code = CONVERT_EXPR; ; + break;} +case 35: +#line 266 "ccdir/c-parse.y" +{ yyval.code = PREINCREMENT_EXPR; ; + break;} +case 36: +#line 268 "ccdir/c-parse.y" +{ yyval.code = PREDECREMENT_EXPR; ; + break;} +case 37: +#line 270 "ccdir/c-parse.y" +{ yyval.code = BIT_NOT_EXPR; ; + break;} +case 38: +#line 272 "ccdir/c-parse.y" +{ yyval.code = TRUTH_NOT_EXPR; ; + break;} +case 39: +#line 276 "ccdir/c-parse.y" +{ yyval.ttype = build_compound_expr (yyvsp[0].ttype); ; + break;} +case 40: +#line 281 "ccdir/c-parse.y" +{ yyval.ttype = NULL_TREE; ; + break;} +case 42: +#line 287 "ccdir/c-parse.y" +{ yyval.ttype = build_tree_list (NULL_TREE, yyvsp[0].ttype); ; + break;} +case 43: +#line 289 "ccdir/c-parse.y" +{ chainon (yyvsp[-2].ttype, build_tree_list (NULL_TREE, yyvsp[0].ttype)); ; + break;} +case 45: +#line 295 "ccdir/c-parse.y" +{ yyval.ttype = build_indirect_ref (yyvsp[0].ttype, "unary *"); ; + break;} +case 46: +#line 297 "ccdir/c-parse.y" +{ yyval.ttype = build_unary_op (yyvsp[-1].code, yyvsp[0].ttype, 0); ; + break;} +case 47: +#line 299 "ccdir/c-parse.y" +{ if (TREE_CODE (yyvsp[0].ttype) == COMPONENT_REF + && TREE_PACKED (TREE_OPERAND (yyvsp[0].ttype, 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 (yyvsp[0].ttype) == COMPOUND_EXPR + && (TREE_CODE (TREE_TYPE (yyvsp[0].ttype)) == ARRAY_TYPE + || TREE_CODE (TREE_TYPE (yyvsp[0].ttype)) == FUNCTION_TYPE)) + yyvsp[0].ttype = default_conversion (yyvsp[0].ttype); + yyval.ttype = c_sizeof (TREE_TYPE (yyvsp[0].ttype)); ; + break;} +case 48: +#line 312 "ccdir/c-parse.y" +{ yyval.ttype = c_sizeof (groktypename (yyvsp[-1].ttype)); ; + break;} +case 49: +#line 314 "ccdir/c-parse.y" +{ if (TREE_CODE (yyvsp[0].ttype) == COMPONENT_REF + && TREE_PACKED (TREE_OPERAND (yyvsp[0].ttype, 1))) + error ("`__alignof' applied to a bit-field"); + if (TREE_CODE (yyvsp[0].ttype) == INDIRECT_REF) + { + tree t = TREE_OPERAND (yyvsp[0].ttype, 0); + tree best = t; + int bestalign = TYPE_ALIGN (TREE_TYPE (TREE_TYPE (t))); + while (TREE_CODE (t) == NOP_EXPR + && TREE_CODE (TREE_TYPE (TREE_OPERAND (t, 0))) == POINTER_TYPE) + { + int thisalign; + t = TREE_OPERAND (t, 0); + thisalign = TYPE_ALIGN (TREE_TYPE (TREE_TYPE (t))); + if (thisalign > bestalign) + best = t, bestalign = thisalign; + } + yyval.ttype = c_alignof (TREE_TYPE (TREE_TYPE (best))); + } + else + { + /* ANSI says arrays and fns are converted inside comma. + But we can't 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 (yyvsp[0].ttype) == COMPOUND_EXPR + && (TREE_CODE (TREE_TYPE (yyvsp[0].ttype)) == ARRAY_TYPE + || TREE_CODE (TREE_TYPE (yyvsp[0].ttype)) == FUNCTION_TYPE)) + yyvsp[0].ttype = default_conversion (yyvsp[0].ttype); + yyval.ttype = c_alignof (TREE_TYPE (yyvsp[0].ttype)); + } + ; + break;} +case 50: +#line 347 "ccdir/c-parse.y" +{ yyval.ttype = c_alignof (groktypename (yyvsp[-1].ttype)); ; + break;} +case 52: +#line 353 "ccdir/c-parse.y" +{ tree type = groktypename (yyvsp[-2].ttype); + yyval.ttype = build_c_cast (type, yyvsp[0].ttype); ; + break;} +case 53: +#line 356 "ccdir/c-parse.y" +{ tree type = groktypename (yyvsp[-5].ttype); + if (pedantic) + warning ("ANSI C forbids constructor expressions"); + yyval.ttype = digest_init (type, build_nt (CONSTRUCTOR, NULL_TREE, nreverse (yyvsp[-2].ttype)), 0); + if (TREE_CODE (type) == ARRAY_TYPE && TYPE_SIZE (type) == 0) + { + int failure = complete_array_type (type, yyval.ttype, 1); + if (failure) + abort (); + } + ; + break;} +case 55: +#line 372 "ccdir/c-parse.y" +{ yyval.ttype = build_binary_op (yyvsp[-1].code, yyvsp[-2].ttype, yyvsp[0].ttype); ; + break;} +case 56: +#line 374 "ccdir/c-parse.y" +{ yyval.ttype = build_binary_op (yyvsp[-1].code, yyvsp[-2].ttype, yyvsp[0].ttype); ; + break;} +case 57: +#line 376 "ccdir/c-parse.y" +{ yyval.ttype = build_binary_op (yyvsp[-1].code, yyvsp[-2].ttype, yyvsp[0].ttype); ; + break;} +case 58: +#line 378 "ccdir/c-parse.y" +{ yyval.ttype = build_binary_op (yyvsp[-1].code, yyvsp[-2].ttype, yyvsp[0].ttype); ; + break;} +case 59: +#line 380 "ccdir/c-parse.y" +{ yyval.ttype = build_binary_op (yyvsp[-1].code, yyvsp[-2].ttype, yyvsp[0].ttype); ; + break;} +case 60: +#line 382 "ccdir/c-parse.y" +{ yyval.ttype = build_binary_op (yyvsp[-1].code, yyvsp[-2].ttype, yyvsp[0].ttype); ; + break;} +case 61: +#line 384 "ccdir/c-parse.y" +{ yyval.ttype = build_binary_op (yyvsp[-1].code, yyvsp[-2].ttype, yyvsp[0].ttype); ; + break;} +case 62: +#line 386 "ccdir/c-parse.y" +{ yyval.ttype = build_binary_op (yyvsp[-1].code, yyvsp[-2].ttype, yyvsp[0].ttype); ; + break;} +case 63: +#line 388 "ccdir/c-parse.y" +{ yyval.ttype = build_binary_op (yyvsp[-1].code, yyvsp[-2].ttype, yyvsp[0].ttype); ; + break;} +case 64: +#line 390 "ccdir/c-parse.y" +{ yyval.ttype = build_binary_op (yyvsp[-1].code, yyvsp[-2].ttype, yyvsp[0].ttype); ; + break;} +case 65: +#line 392 "ccdir/c-parse.y" +{ yyval.ttype = build_binary_op (yyvsp[-1].code, yyvsp[-2].ttype, yyvsp[0].ttype); ; + break;} +case 66: +#line 394 "ccdir/c-parse.y" +{ yyval.ttype = build_binary_op (yyvsp[-1].code, yyvsp[-2].ttype, yyvsp[0].ttype); ; + break;} +case 67: +#line 396 "ccdir/c-parse.y" +{ yyval.ttype = build_binary_op (TRUTH_ANDIF_EXPR, yyvsp[-2].ttype, yyvsp[0].ttype); ; + break;} +case 68: +#line 398 "ccdir/c-parse.y" +{ yyval.ttype = build_binary_op (TRUTH_ORIF_EXPR, yyvsp[-2].ttype, yyvsp[0].ttype); ; + break;} +case 69: +#line 400 "ccdir/c-parse.y" +{ yyval.ttype = build_conditional_expr (yyvsp[-4].ttype, yyvsp[-2].ttype, yyvsp[0].ttype); ; + break;} +case 70: +#line 402 "ccdir/c-parse.y" +{ yyval.ttype = build_modify_expr (yyvsp[-2].ttype, NOP_EXPR, yyvsp[0].ttype); ; + break;} +case 71: +#line 404 "ccdir/c-parse.y" +{ yyval.ttype = build_modify_expr (yyvsp[-2].ttype, yyvsp[-1].code, yyvsp[0].ttype); ; + break;} +case 72: +#line 409 "ccdir/c-parse.y" +{ yyval.ttype = lastiddecl; + if (!yyval.ttype || yyval.ttype == error_mark_node) + { + if (yychar == YYEMPTY) + yychar = YYLEX; + if (yychar == '(') + { + yyval.ttype = implicitly_declare (yyvsp[0].ttype); + assemble_external (yyval.ttype); + TREE_USED (yyval.ttype) = 1; + } + else if (current_function_decl == 0) + { + error ("`%s' undeclared, outside of functions", + IDENTIFIER_POINTER (yyvsp[0].ttype)); + yyval.ttype = error_mark_node; + } + else + { + if (IDENTIFIER_GLOBAL_VALUE (yyvsp[0].ttype) != error_mark_node + || IDENTIFIER_ERROR_LOCUS (yyvsp[0].ttype) != current_function_decl) + { + error ("`%s' undeclared (first use this function)", + IDENTIFIER_POINTER (yyvsp[0].ttype)); + + if (! undeclared_variable_notice) + { + error ("(Each undeclared identifier is reported only once"); + error ("for each function it appears in.)"); + undeclared_variable_notice = 1; + } + } + yyval.ttype = error_mark_node; + /* Prevent repeated error messages. */ + IDENTIFIER_GLOBAL_VALUE (yyvsp[0].ttype) = error_mark_node; + IDENTIFIER_ERROR_LOCUS (yyvsp[0].ttype) = current_function_decl; + } + } + else if (! TREE_USED (yyval.ttype)) + { + if (TREE_EXTERNAL (yyval.ttype)) + assemble_external (yyval.ttype); + TREE_USED (yyval.ttype) = 1; + } + if (TREE_CODE (yyval.ttype) == CONST_DECL) + yyval.ttype = DECL_INITIAL (yyval.ttype); + ; + break;} +case 74: +#line 458 "ccdir/c-parse.y" +{ yyval.ttype = combine_strings (yyvsp[0].ttype); ; + break;} +case 75: +#line 460 "ccdir/c-parse.y" +{ yyval.ttype = yyvsp[-1].ttype; ; + break;} +case 76: +#line 462 "ccdir/c-parse.y" +{ yyval.ttype = error_mark_node; ; + break;} +case 77: +#line 464 "ccdir/c-parse.y" +{ if (current_function_decl == 0) + { + error ("braced-group within expression allowed only inside a function"); + YYFAIL; + } + keep_next_level (); + yyval.ttype = expand_start_stmt_expr (); ; + break;} +case 78: +#line 472 "ccdir/c-parse.y" +{ tree rtl_exp; + if (pedantic) + warning ("ANSI C forbids braced-groups within expressions"); + rtl_exp = expand_end_stmt_expr (yyvsp[-2].ttype); + yyval.ttype = yyvsp[-1].ttype; + TREE_USED (yyval.ttype) = 0; + /* Since the statements have side effects, + consider this volatile. */ + TREE_VOLATILE (yyval.ttype) = 1; + TREE_TYPE (yyval.ttype) = TREE_TYPE (rtl_exp); + STMT_BODY (yyval.ttype) = rtl_exp; ; + break;} +case 79: +#line 484 "ccdir/c-parse.y" +{ yyval.ttype = build_function_call (yyvsp[-3].ttype, yyvsp[-1].ttype); ; + break;} +case 80: +#line 486 "ccdir/c-parse.y" +{ yyval.ttype = build_array_ref (yyvsp[-3].ttype, yyvsp[-1].ttype); ; + break;} +case 81: +#line 488 "ccdir/c-parse.y" +{ yyval.ttype = build_component_ref (yyvsp[-2].ttype, yyvsp[0].ttype); ; + break;} +case 82: +#line 490 "ccdir/c-parse.y" +{ yyval.ttype = build_component_ref (build_indirect_ref (yyvsp[-2].ttype, "->"), yyvsp[0].ttype); ; + break;} +case 83: +#line 492 "ccdir/c-parse.y" +{ yyval.ttype = build_unary_op (POSTINCREMENT_EXPR, yyvsp[-1].ttype, 0); ; + break;} +case 84: +#line 494 "ccdir/c-parse.y" +{ yyval.ttype = build_unary_op (POSTDECREMENT_EXPR, yyvsp[-1].ttype, 0); ; + break;} +case 86: +#line 501 "ccdir/c-parse.y" +{ yyval.ttype = chainon (yyvsp[-1].ttype, yyvsp[0].ttype); ; + break;} +case 93: +#line 521 "ccdir/c-parse.y" +{ yyval.itype = suspend_momentary (); + declspec_stack = tree_cons (0, current_declspecs, + declspec_stack); + current_declspecs = yyvsp[0].ttype; ; + break;} +case 94: +#line 529 "ccdir/c-parse.y" +{ current_declspecs = TREE_VALUE (declspec_stack); + declspec_stack = TREE_CHAIN (declspec_stack); + resume_momentary (yyvsp[-2].itype); ; + break;} +case 95: +#line 533 "ccdir/c-parse.y" +{ current_declspecs = TREE_VALUE (declspec_stack); + declspec_stack = TREE_CHAIN (declspec_stack); + resume_momentary (yyvsp[-2].itype); ; + break;} +case 96: +#line 537 "ccdir/c-parse.y" +{ shadow_tag (yyvsp[-1].ttype); ; + break;} +case 97: +#line 539 "ccdir/c-parse.y" +{ warning ("empty declaration"); ; + break;} +case 98: +#line 548 "ccdir/c-parse.y" +{ yyval.ttype = tree_cons (NULL_TREE, yyvsp[-1].ttype, yyvsp[0].ttype); ; + break;} +case 99: +#line 550 "ccdir/c-parse.y" +{ yyval.ttype = chainon (yyvsp[0].ttype, tree_cons (NULL_TREE, yyvsp[-1].ttype, yyvsp[-2].ttype)); ; + break;} +case 100: +#line 554 "ccdir/c-parse.y" +{ yyval.ttype = NULL_TREE; ; + break;} +case 101: +#line 556 "ccdir/c-parse.y" +{ yyval.ttype = tree_cons (NULL_TREE, yyvsp[0].ttype, yyvsp[-1].ttype); ; + break;} +case 102: +#line 558 "ccdir/c-parse.y" +{ yyval.ttype = tree_cons (NULL_TREE, yyvsp[0].ttype, yyvsp[-1].ttype); ; + break;} +case 103: +#line 567 "ccdir/c-parse.y" +{ yyval.ttype = tree_cons (NULL_TREE, yyvsp[0].ttype, NULL_TREE); ; + break;} +case 104: +#line 569 "ccdir/c-parse.y" +{ yyval.ttype = tree_cons (NULL_TREE, yyvsp[0].ttype, NULL_TREE); ; + break;} +case 105: +#line 571 "ccdir/c-parse.y" +{ yyval.ttype = tree_cons (NULL_TREE, yyvsp[0].ttype, yyvsp[-1].ttype); ; + break;} +case 106: +#line 573 "ccdir/c-parse.y" +{ yyval.ttype = tree_cons (NULL_TREE, yyvsp[0].ttype, yyvsp[-1].ttype); ; + break;} +case 107: +#line 583 "ccdir/c-parse.y" +{ yyval.ttype = tree_cons (NULL_TREE, yyvsp[-1].ttype, yyvsp[0].ttype); ; + break;} +case 108: +#line 585 "ccdir/c-parse.y" +{ yyval.ttype = chainon (yyvsp[0].ttype, tree_cons (NULL_TREE, yyvsp[-1].ttype, yyvsp[-2].ttype)); ; + break;} +case 109: +#line 589 "ccdir/c-parse.y" +{ yyval.ttype = NULL_TREE; ; + break;} +case 110: +#line 591 "ccdir/c-parse.y" +{ yyval.ttype = tree_cons (NULL_TREE, yyvsp[0].ttype, yyvsp[-1].ttype); ; + break;} +case 114: +#line 602 "ccdir/c-parse.y" +{ yyval.ttype = TREE_TYPE (yyvsp[-1].ttype); + if (pedantic) + warning ("ANSI C forbids `typeof'"); ; + break;} +case 115: +#line 606 "ccdir/c-parse.y" +{ yyval.ttype = groktypename (yyvsp[-1].ttype); + if (pedantic) + warning ("ANSI C forbids `typeof'"); ; + break;} +case 123: +#line 630 "ccdir/c-parse.y" +{ yyval.ttype = NULL_TREE; ; + break;} +case 124: +#line 632 "ccdir/c-parse.y" +{ if (TREE_CHAIN (yyvsp[-1].ttype)) yyvsp[-1].ttype = combine_strings (yyvsp[-1].ttype); + yyval.ttype = yyvsp[-1].ttype; + if (pedantic) + warning ("ANSI C forbids use of `asm' keyword"); + ; + break;} +case 125: +#line 641 "ccdir/c-parse.y" +{ yyval.ttype = start_decl (yyvsp[-3].ttype, current_declspecs, 1); ; + break;} +case 126: +#line 644 "ccdir/c-parse.y" +{ finish_decl (yyvsp[-1].ttype, yyvsp[0].ttype, yyvsp[-4].ttype); ; + break;} +case 127: +#line 646 "ccdir/c-parse.y" +{ tree d = start_decl (yyvsp[-2].ttype, current_declspecs, 0); + finish_decl (d, NULL_TREE, yyvsp[-1].ttype); ; + break;} +case 128: +#line 652 "ccdir/c-parse.y" +{ yyval.ttype = start_decl (yyvsp[-3].ttype, current_declspecs, 1); ; + break;} +case 129: +#line 655 "ccdir/c-parse.y" +{ finish_decl (yyvsp[-1].ttype, yyvsp[0].ttype, yyvsp[-4].ttype); ; + break;} +case 130: +#line 657 "ccdir/c-parse.y" +{ tree d = start_decl (yyvsp[-2].ttype, current_declspecs, 0); + finish_decl (d, NULL_TREE, yyvsp[-1].ttype); ; + break;} +case 131: +#line 664 "ccdir/c-parse.y" +{ yyval.ttype = NULL_TREE; ; + break;} +case 132: +#line 666 "ccdir/c-parse.y" +{ yyval.ttype = yyvsp[-2].ttype; ; + break;} +case 135: +#line 676 "ccdir/c-parse.y" +{ warning ("`%s' attribute directive ignored", + IDENTIFIER_POINTER (yyvsp[0].ttype)); + yyval.ttype = yyvsp[0].ttype; ; + break;} +case 136: +#line 680 "ccdir/c-parse.y" +{ /* if not "aligned(1)", then issue warning */ + if (strcmp (IDENTIFIER_POINTER (yyvsp[-3].ttype), "aligned") != 0 + || TREE_CODE (yyvsp[-1].ttype) != INTEGER_CST + || TREE_INT_CST_LOW (yyvsp[-1].ttype) != 1) + warning ("`%s' attribute directive ignored", + IDENTIFIER_POINTER (yyvsp[-3].ttype)); + yyval.ttype = yyvsp[-3].ttype; ; + break;} +case 137: +#line 688 "ccdir/c-parse.y" +{ warning ("`%s' attribute directive ignored", + IDENTIFIER_POINTER (yyvsp[-3].ttype)); + yyval.ttype = yyvsp[-3].ttype; ; + break;} +case 139: +#line 696 "ccdir/c-parse.y" +{ yyval.ttype = build_nt (CONSTRUCTOR, NULL_TREE, NULL_TREE); + if (pedantic) + warning ("ANSI C forbids empty initializer braces"); ; + break;} +case 140: +#line 700 "ccdir/c-parse.y" +{ yyval.ttype = build_nt (CONSTRUCTOR, NULL_TREE, nreverse (yyvsp[-1].ttype)); ; + break;} +case 141: +#line 702 "ccdir/c-parse.y" +{ yyval.ttype = build_nt (CONSTRUCTOR, NULL_TREE, nreverse (yyvsp[-2].ttype)); ; + break;} +case 142: +#line 704 "ccdir/c-parse.y" +{ yyval.ttype = NULL_TREE; ; + break;} +case 143: +#line 711 "ccdir/c-parse.y" +{ yyval.ttype = build_tree_list (NULL_TREE, yyvsp[0].ttype); ; + break;} +case 144: +#line 713 "ccdir/c-parse.y" +{ yyval.ttype = tree_cons (NULL_TREE, yyvsp[0].ttype, yyvsp[-2].ttype); ; + break;} +case 147: +#line 728 "ccdir/c-parse.y" +{ yyval.ttype = yyvsp[-1].ttype; ; + break;} +case 148: +#line 730 "ccdir/c-parse.y" +{ yyval.ttype = build_nt (CALL_EXPR, yyvsp[-2].ttype, yyvsp[0].ttype, NULL_TREE); ; + break;} +case 149: +#line 735 "ccdir/c-parse.y" +{ yyval.ttype = build_nt (ARRAY_REF, yyvsp[-3].ttype, yyvsp[-1].ttype); ; + break;} +case 150: +#line 737 "ccdir/c-parse.y" +{ yyval.ttype = build_nt (ARRAY_REF, yyvsp[-2].ttype, NULL_TREE); ; + break;} +case 151: +#line 739 "ccdir/c-parse.y" +{ yyval.ttype = make_pointer_declarator (yyvsp[-1].ttype, yyvsp[0].ttype); ; + break;} +case 153: +#line 750 "ccdir/c-parse.y" +{ yyval.ttype = build_nt (CALL_EXPR, yyvsp[-2].ttype, yyvsp[0].ttype, NULL_TREE); ; + break;} +case 154: +#line 755 "ccdir/c-parse.y" +{ yyval.ttype = build_nt (ARRAY_REF, yyvsp[-3].ttype, yyvsp[-1].ttype); ; + break;} +case 155: +#line 757 "ccdir/c-parse.y" +{ yyval.ttype = build_nt (ARRAY_REF, yyvsp[-2].ttype, NULL_TREE); ; + break;} +case 156: +#line 759 "ccdir/c-parse.y" +{ yyval.ttype = make_pointer_declarator (yyvsp[-1].ttype, yyvsp[0].ttype); ; + break;} +case 158: +#line 768 "ccdir/c-parse.y" +{ yyval.ttype = build_nt (CALL_EXPR, yyvsp[-2].ttype, yyvsp[0].ttype, NULL_TREE); ; + break;} +case 159: +#line 773 "ccdir/c-parse.y" +{ yyval.ttype = yyvsp[-1].ttype; ; + break;} +case 160: +#line 775 "ccdir/c-parse.y" +{ yyval.ttype = make_pointer_declarator (yyvsp[-1].ttype, yyvsp[0].ttype); ; + break;} +case 161: +#line 777 "ccdir/c-parse.y" +{ yyval.ttype = build_nt (ARRAY_REF, yyvsp[-3].ttype, yyvsp[-1].ttype); ; + break;} +case 162: +#line 779 "ccdir/c-parse.y" +{ yyval.ttype = build_nt (ARRAY_REF, yyvsp[-2].ttype, NULL_TREE); ; + break;} +case 164: +#line 785 "ccdir/c-parse.y" +{ yyval.ttype = start_struct (RECORD_TYPE, yyvsp[-1].ttype); + /* Start scope of tag before parsing components. */ + ; + break;} +case 165: +#line 789 "ccdir/c-parse.y" +{ yyval.ttype = finish_struct (yyvsp[-2].ttype, yyvsp[-1].ttype); + /* Really define the structure. */ + ; + break;} +case 166: +#line 793 "ccdir/c-parse.y" +{ yyval.ttype = finish_struct (start_struct (RECORD_TYPE, NULL_TREE), + yyvsp[-1].ttype); ; + break;} +case 167: +#line 796 "ccdir/c-parse.y" +{ yyval.ttype = xref_tag (RECORD_TYPE, yyvsp[0].ttype); ; + break;} +case 168: +#line 798 "ccdir/c-parse.y" +{ yyval.ttype = start_struct (UNION_TYPE, yyvsp[-1].ttype); ; + break;} +case 169: +#line 800 "ccdir/c-parse.y" +{ yyval.ttype = finish_struct (yyvsp[-2].ttype, yyvsp[-1].ttype); ; + break;} +case 170: +#line 802 "ccdir/c-parse.y" +{ yyval.ttype = finish_struct (start_struct (UNION_TYPE, NULL_TREE), + yyvsp[-1].ttype); ; + break;} +case 171: +#line 805 "ccdir/c-parse.y" +{ yyval.ttype = xref_tag (UNION_TYPE, yyvsp[0].ttype); ; + break;} +case 172: +#line 807 "ccdir/c-parse.y" +{ yyvsp[0].itype = suspend_momentary (); + yyval.ttype = start_enum (yyvsp[-1].ttype); ; + break;} +case 173: +#line 810 "ccdir/c-parse.y" +{ yyval.ttype = finish_enum (yyvsp[-3].ttype, nreverse (yyvsp[-2].ttype)); + resume_momentary (yyvsp[-4].itype); ; + break;} +case 174: +#line 813 "ccdir/c-parse.y" +{ yyvsp[0].itype = suspend_momentary (); + yyval.ttype = start_enum (NULL_TREE); ; + break;} +case 175: +#line 816 "ccdir/c-parse.y" +{ yyval.ttype = finish_enum (yyvsp[-3].ttype, nreverse (yyvsp[-2].ttype)); + resume_momentary (yyvsp[-4].itype); ; + break;} +case 176: +#line 819 "ccdir/c-parse.y" +{ yyval.ttype = xref_tag (ENUMERAL_TYPE, yyvsp[0].ttype); ; + break;} +case 180: +#line 830 "ccdir/c-parse.y" +{ if (pedantic) warning ("comma at end of enumerator list"); ; + break;} +case 181: +#line 835 "ccdir/c-parse.y" +{ yyval.ttype = yyvsp[0].ttype; ; + break;} +case 182: +#line 837 "ccdir/c-parse.y" +{ yyval.ttype = chainon (yyvsp[-1].ttype, yyvsp[0].ttype); + warning ("no semicolon at end of struct or union"); ; + break;} +case 183: +#line 842 "ccdir/c-parse.y" +{ yyval.ttype = NULL_TREE; ; + break;} +case 184: +#line 844 "ccdir/c-parse.y" +{ yyval.ttype = chainon (yyvsp[-2].ttype, yyvsp[-1].ttype); ; + break;} +case 185: +#line 846 "ccdir/c-parse.y" +{ if (pedantic) + warning ("extra semicolon in struct or union specified"); ; + break;} +case 186: +#line 861 "ccdir/c-parse.y" +{ yyval.ttype = yyvsp[0].ttype; + current_declspecs = TREE_VALUE (declspec_stack); + declspec_stack = TREE_CHAIN (declspec_stack); + resume_momentary (yyvsp[-1].itype); ; + break;} +case 187: +#line 866 "ccdir/c-parse.y" +{ yyval.ttype = yyvsp[0].ttype; + current_declspecs = TREE_VALUE (declspec_stack); + declspec_stack = TREE_CHAIN (declspec_stack); + resume_momentary (yyvsp[-1].itype); ; + break;} +case 188: +#line 871 "ccdir/c-parse.y" +{ yyval.ttype = NULL_TREE; ; + break;} +case 189: +#line 876 "ccdir/c-parse.y" +{ if (pedantic) + warning ("ANSI C forbids member declarations with no members"); + yyval.ttype = NULL_TREE; ; + break;} +case 191: +#line 881 "ccdir/c-parse.y" +{ yyval.ttype = chainon (yyvsp[-2].ttype, yyvsp[0].ttype); ; + break;} +case 192: +#line 886 "ccdir/c-parse.y" +{ yyval.ttype = grokfield (input_filename, lineno, yyvsp[-1].ttype, current_declspecs, NULL_TREE); ; + break;} +case 193: +#line 888 "ccdir/c-parse.y" +{ yyval.ttype = grokfield (input_filename, lineno, yyvsp[-3].ttype, current_declspecs, yyvsp[-1].ttype); ; + break;} +case 194: +#line 890 "ccdir/c-parse.y" +{ yyval.ttype = grokfield (input_filename, lineno, NULL_TREE, current_declspecs, yyvsp[0].ttype); ; + break;} +case 196: +#line 901 "ccdir/c-parse.y" +{ yyval.ttype = chainon (yyvsp[0].ttype, yyvsp[-2].ttype); ; + break;} +case 197: +#line 907 "ccdir/c-parse.y" +{ yyval.ttype = build_enumerator (yyvsp[0].ttype, NULL_TREE); ; + break;} +case 198: +#line 909 "ccdir/c-parse.y" +{ yyval.ttype = build_enumerator (yyvsp[-2].ttype, yyvsp[0].ttype); ; + break;} +case 199: +#line 914 "ccdir/c-parse.y" +{ yyval.ttype = build_tree_list (yyvsp[-1].ttype, yyvsp[0].ttype); ; + break;} +case 200: +#line 916 "ccdir/c-parse.y" +{ yyval.ttype = build_tree_list (yyvsp[-1].ttype, yyvsp[0].ttype); ; + break;} +case 201: +#line 921 "ccdir/c-parse.y" +{ yyval.ttype = NULL_TREE; ; + break;} +case 203: +#line 927 "ccdir/c-parse.y" +{ yyval.ttype = tree_cons (NULL_TREE, yyvsp[0].ttype, NULL_TREE); ; + break;} +case 204: +#line 929 "ccdir/c-parse.y" +{ yyval.ttype = tree_cons (NULL_TREE, yyvsp[0].ttype, yyvsp[-1].ttype); ; + break;} +case 205: +#line 934 "ccdir/c-parse.y" +{ yyval.ttype = NULL_TREE; ; + break;} +case 206: +#line 936 "ccdir/c-parse.y" +{ yyval.ttype = tree_cons (NULL_TREE, yyvsp[0].ttype, yyvsp[-1].ttype); ; + break;} +case 207: +#line 941 "ccdir/c-parse.y" +{ yyval.ttype = yyvsp[-1].ttype; ; + break;} +case 208: +#line 944 "ccdir/c-parse.y" +{ yyval.ttype = make_pointer_declarator (yyvsp[-1].ttype, yyvsp[0].ttype); ; + break;} +case 209: +#line 946 "ccdir/c-parse.y" +{ yyval.ttype = make_pointer_declarator (yyvsp[0].ttype, NULL_TREE); ; + break;} +case 210: +#line 948 "ccdir/c-parse.y" +{ yyval.ttype = build_nt (CALL_EXPR, yyvsp[-2].ttype, yyvsp[0].ttype, NULL_TREE); ; + break;} +case 211: +#line 950 "ccdir/c-parse.y" +{ yyval.ttype = build_nt (ARRAY_REF, yyvsp[-3].ttype, yyvsp[-1].ttype); ; + break;} +case 212: +#line 952 "ccdir/c-parse.y" +{ yyval.ttype = build_nt (ARRAY_REF, yyvsp[-2].ttype, NULL_TREE); ; + break;} +case 213: +#line 954 "ccdir/c-parse.y" +{ yyval.ttype = build_nt (CALL_EXPR, NULL_TREE, yyvsp[0].ttype, NULL_TREE); ; + break;} +case 214: +#line 956 "ccdir/c-parse.y" +{ yyval.ttype = build_nt (ARRAY_REF, NULL_TREE, yyvsp[-1].ttype); ; + break;} +case 215: +#line 958 "ccdir/c-parse.y" +{ yyval.ttype = build_nt (ARRAY_REF, NULL_TREE, NULL_TREE); ; + break;} +case 222: +#line 980 "ccdir/c-parse.y" +{ pushlevel (0); + clear_last_expr (); + push_momentary (); + expand_start_bindings (0); ; + break;} +case 223: +#line 990 "ccdir/c-parse.y" +{; + break;} +case 225: +#line 995 "ccdir/c-parse.y" +{ yyval.ttype = 0; ; + break;} +case 226: +#line 997 "ccdir/c-parse.y" +{ expand_end_bindings (getdecls (), 1, 0); + yyval.ttype = poplevel (1, 1, 0); + pop_momentary (); ; + break;} +case 227: +#line 1001 "ccdir/c-parse.y" +{ expand_end_bindings (getdecls (), kept_level_p (), 0); + yyval.ttype = poplevel (kept_level_p (), 0, 0); + pop_momentary (); ; + break;} +case 228: +#line 1005 "ccdir/c-parse.y" +{ expand_end_bindings (getdecls (), kept_level_p (), 0); + yyval.ttype = poplevel (kept_level_p (), 0, 0); + pop_momentary (); ; + break;} +case 229: +#line 1012 "ccdir/c-parse.y" +{ emit_line_note (input_filename, lineno); + expand_start_cond (truthvalue_conversion (yyvsp[-1].ttype), 0); ; + break;} +case 231: +#line 1018 "ccdir/c-parse.y" +{; + break;} +case 232: +#line 1020 "ccdir/c-parse.y" +{ emit_line_note (input_filename, lineno); + /* Do default conversion if safe and possibly important, + in case within ({...}). */ + if ((TREE_CODE (TREE_TYPE (yyvsp[-1].ttype)) == ARRAY_TYPE + && lvalue_p (yyvsp[-1].ttype)) + || TREE_CODE (TREE_TYPE (yyvsp[-1].ttype)) == FUNCTION_TYPE) + yyvsp[-1].ttype = default_conversion (yyvsp[-1].ttype); + expand_expr_stmt (yyvsp[-1].ttype); + clear_momentary (); ; + break;} +case 233: +#line 1030 "ccdir/c-parse.y" +{ expand_start_else (); ; + break;} +case 234: +#line 1032 "ccdir/c-parse.y" +{ expand_end_else (); ; + break;} +case 235: +#line 1034 "ccdir/c-parse.y" +{ expand_end_cond (); ; + break;} +case 236: +#line 1036 "ccdir/c-parse.y" +{ emit_nop (); + emit_line_note (input_filename, lineno); + expand_start_loop (1); ; + break;} +case 237: +#line 1040 "ccdir/c-parse.y" +{ emit_line_note (input_filename, lineno); + expand_exit_loop_if_false (truthvalue_conversion (yyvsp[-1].ttype)); ; + break;} +case 238: +#line 1043 "ccdir/c-parse.y" +{ expand_end_loop (); ; + break;} +case 239: +#line 1045 "ccdir/c-parse.y" +{ emit_nop (); + emit_line_note (input_filename, lineno); + expand_start_loop_continue_elsewhere (1); ; + break;} +case 240: +#line 1049 "ccdir/c-parse.y" +{ expand_loop_continue_here (); ; + break;} +case 241: +#line 1051 "ccdir/c-parse.y" +{ emit_line_note (input_filename, lineno); + expand_exit_loop_if_false (truthvalue_conversion (yyvsp[-2].ttype)); + expand_end_loop (); + clear_momentary (); ; + break;} +case 242: +#line 1057 "ccdir/c-parse.y" +{ emit_nop (); + emit_line_note (input_filename, lineno); + if (yyvsp[-1].ttype) expand_expr_stmt (yyvsp[-1].ttype); + expand_start_loop_continue_elsewhere (1); ; + break;} +case 243: +#line 1062 "ccdir/c-parse.y" +{ emit_line_note (input_filename, lineno); + if (yyvsp[-1].ttype) + expand_exit_loop_if_false (truthvalue_conversion (yyvsp[-1].ttype)); ; + break;} +case 244: +#line 1068 "ccdir/c-parse.y" +{ push_momentary (); + yyvsp[0].itype = lineno; ; + break;} +case 245: +#line 1071 "ccdir/c-parse.y" +{ emit_line_note (input_filename, yyvsp[-2].itype); + expand_loop_continue_here (); + if (yyvsp[-3].ttype) + expand_expr_stmt (yyvsp[-3].ttype); + pop_momentary (); + expand_end_loop (); ; + break;} +case 246: +#line 1078 "ccdir/c-parse.y" +{ emit_line_note (input_filename, lineno); + c_expand_start_case (yyvsp[-1].ttype); + /* Don't let the tree nodes for $3 be discarded by + clear_momentary during the parsing of the next stmt. */ + push_momentary (); ; + break;} +case 247: +#line 1084 "ccdir/c-parse.y" +{ expand_end_case (yyvsp[-3].ttype); + pop_momentary (); ; + break;} +case 248: +#line 1087 "ccdir/c-parse.y" +{ register tree value = fold (yyvsp[-1].ttype); + register tree label + = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE); + + /* 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); + + if (TREE_CODE (value) != INTEGER_CST + && value != error_mark_node) + { + error ("case label does not reduce to an integer constant"); + value = error_mark_node; + } + else + /* Promote char or short to int. */ + value = default_conversion (value); + if (value != error_mark_node) + { + int success = pushcase (value, label); + if (success == 1) + error ("case label not within a switch statement"); + else if (success == 2) + error ("duplicate case value"); + else if (success == 3) + warning ("case value out of range"); + } + ; + break;} +case 250: +#line 1119 "ccdir/c-parse.y" +{ + register tree label + = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE); + int success = pushcase (NULL_TREE, label); + if (success == 1) + error ("default label not within a switch statement"); + else if (success == 2) + error ("multiple default labels in one switch"); + ; + break;} +case 252: +#line 1130 "ccdir/c-parse.y" +{ emit_line_note (input_filename, lineno); + if ( ! expand_exit_something ()) + error ("break statement not within loop or switch"); ; + break;} +case 253: +#line 1134 "ccdir/c-parse.y" +{ emit_line_note (input_filename, lineno); + if (! expand_continue_loop ()) + error ("continue statement not within a loop"); ; + break;} +case 254: +#line 1138 "ccdir/c-parse.y" +{ emit_line_note (input_filename, lineno); + c_expand_return (NULL_TREE); ; + break;} +case 255: +#line 1141 "ccdir/c-parse.y" +{ emit_line_note (input_filename, lineno); + c_expand_return (yyvsp[-1].ttype); ; + break;} +case 256: +#line 1144 "ccdir/c-parse.y" +{ if (TREE_CHAIN (yyvsp[-2].ttype)) yyvsp[-2].ttype = combine_strings (yyvsp[-2].ttype); + emit_line_note (input_filename, lineno); + expand_asm (yyvsp[-2].ttype); ; + break;} +case 257: +#line 1149 "ccdir/c-parse.y" +{ if (TREE_CHAIN (yyvsp[-4].ttype)) yyvsp[-4].ttype = combine_strings (yyvsp[-4].ttype); + emit_line_note (input_filename, lineno); + c_expand_asm_operands (yyvsp[-4].ttype, yyvsp[-2].ttype, NULL_TREE, NULL_TREE, + yyvsp[-6].ttype == ridpointers[(int)RID_VOLATILE], + input_filename, lineno); ; + break;} +case 258: +#line 1156 "ccdir/c-parse.y" +{ if (TREE_CHAIN (yyvsp[-6].ttype)) yyvsp[-6].ttype = combine_strings (yyvsp[-6].ttype); + emit_line_note (input_filename, lineno); + c_expand_asm_operands (yyvsp[-6].ttype, yyvsp[-4].ttype, yyvsp[-2].ttype, NULL_TREE, + yyvsp[-8].ttype == ridpointers[(int)RID_VOLATILE], + input_filename, lineno); ; + break;} +case 259: +#line 1164 "ccdir/c-parse.y" +{ if (TREE_CHAIN (yyvsp[-8].ttype)) yyvsp[-8].ttype = combine_strings (yyvsp[-8].ttype); + emit_line_note (input_filename, lineno); + c_expand_asm_operands (yyvsp[-8].ttype, yyvsp[-6].ttype, yyvsp[-4].ttype, yyvsp[-2].ttype, + yyvsp[-10].ttype == ridpointers[(int)RID_VOLATILE], + input_filename, lineno); ; + break;} +case 260: +#line 1170 "ccdir/c-parse.y" +{ tree decl; + emit_line_note (input_filename, lineno); + decl = lookup_label (yyvsp[-1].ttype); + TREE_USED (decl) = 1; + expand_goto (decl); ; + break;} +case 261: +#line 1176 "ccdir/c-parse.y" +{ tree label = define_label (input_filename, lineno, yyvsp[-1].ttype); + emit_nop (); + if (label) + expand_label (label); ; + break;} +case 264: +#line 1188 "ccdir/c-parse.y" +{ if (pedantic) + warning ("ANSI C forbids use of `asm' keyword"); + emit_line_note (input_filename, lineno); ; + break;} +case 265: +#line 1192 "ccdir/c-parse.y" +{ if (pedantic) + warning ("ANSI C forbids use of `asm' keyword"); + emit_line_note (input_filename, lineno); ; + break;} +case 266: +#line 1199 "ccdir/c-parse.y" +{ yyval.ttype = NULL_TREE; ; + break;} +case 268: +#line 1206 "ccdir/c-parse.y" +{ yyval.ttype = NULL_TREE; ; + break;} +case 271: +#line 1213 "ccdir/c-parse.y" +{ yyval.ttype = chainon (yyvsp[-2].ttype, yyvsp[0].ttype); ; + break;} +case 272: +#line 1218 "ccdir/c-parse.y" +{ yyval.ttype = build_tree_list (yyvsp[-3].ttype, yyvsp[-1].ttype); ; + break;} +case 273: +#line 1223 "ccdir/c-parse.y" +{ yyval.ttype = tree_cons (NULL_TREE, combine_strings (yyvsp[0].ttype), NULL_TREE); ; + break;} +case 274: +#line 1225 "ccdir/c-parse.y" +{ yyval.ttype = tree_cons (NULL_TREE, combine_strings (yyvsp[0].ttype), yyvsp[-2].ttype); ; + break;} +case 275: +#line 1231 "ccdir/c-parse.y" +{ pushlevel (0); + declare_parm_level (); ; + break;} +case 276: +#line 1234 "ccdir/c-parse.y" +{ yyval.ttype = yyvsp[0].ttype; + parmlist_tags_warning (); + poplevel (0, 0, 0); ; + break;} +case 277: +#line 1242 "ccdir/c-parse.y" +{ pushlevel (0); + declare_parm_level (); ; + break;} +case 278: +#line 1245 "ccdir/c-parse.y" +{ yyval.ttype = yyvsp[0].ttype; + parmlist_tags_warning (); + poplevel (0, 0, 0); ; + break;} +case 280: +#line 1253 "ccdir/c-parse.y" +{ yyval.ttype = tree_cons (NULL_TREE, NULL_TREE, yyvsp[-1].ttype); ; + break;} +case 281: +#line 1255 "ccdir/c-parse.y" +{ yyval.ttype = tree_cons (NULL_TREE, NULL_TREE, NULL_TREE); ; + break;} +case 283: +#line 1261 "ccdir/c-parse.y" +{ yyval.ttype = tree_cons (NULL_TREE, NULL_TREE, NULL_TREE); ; + break;} +case 284: +#line 1267 "ccdir/c-parse.y" +{ yyval.ttype = get_parm_info (0); ; + break;} +case 285: +#line 1269 "ccdir/c-parse.y" +{ yyval.ttype = get_parm_info (1); ; + break;} +case 286: +#line 1271 "ccdir/c-parse.y" +{ yyval.ttype = get_parm_info (0); ; + break;} +case 287: +#line 1276 "ccdir/c-parse.y" +{ push_parm_decl (yyvsp[0].ttype); ; + break;} +case 288: +#line 1278 "ccdir/c-parse.y" +{ push_parm_decl (yyvsp[0].ttype); ; + break;} +case 289: +#line 1285 "ccdir/c-parse.y" +{ yyval.ttype = build_tree_list (yyvsp[-1].ttype, yyvsp[0].ttype) ; ; + break;} +case 290: +#line 1287 "ccdir/c-parse.y" +{ yyval.ttype = build_tree_list (yyvsp[-1].ttype, yyvsp[0].ttype) ; ; + break;} +case 291: +#line 1289 "ccdir/c-parse.y" +{ yyval.ttype = build_tree_list (yyvsp[-1].ttype, yyvsp[0].ttype); ; + break;} +case 292: +#line 1291 "ccdir/c-parse.y" +{ yyval.ttype = build_tree_list (yyvsp[-1].ttype, yyvsp[0].ttype) ; ; + break;} +case 293: +#line 1293 "ccdir/c-parse.y" +{ yyval.ttype = build_tree_list (yyvsp[-1].ttype, yyvsp[0].ttype); ; + break;} +case 294: +#line 1299 "ccdir/c-parse.y" +{ yyval.ttype = build_tree_list (NULL_TREE, yyvsp[0].ttype); ; + break;} +case 295: +#line 1301 "ccdir/c-parse.y" +{ yyval.ttype = chainon (yyvsp[-2].ttype, build_tree_list (NULL_TREE, yyvsp[0].ttype)); ; + break;} +} + /* the action file gets copied in in place of this dollarsign */ +#line 419 "bison.simple" + + yyvsp -= yylen; + yyssp -= yylen; +#ifdef YYLSP_NEEDED + yylsp -= yylen; +#endif + +#if YYDEBUG != 0 + if (yydebug) + { + short *ssp1 = yyss - 1; + fprintf (stderr, "state stack now"); + while (ssp1 != yyssp) + fprintf (stderr, " %d", *++ssp1); + fprintf (stderr, "\n"); + } +#endif + + *++yyvsp = yyval; + +#ifdef YYLSP_NEEDED + yylsp++; + if (yylen == 0) + { + yylsp->first_line = yylloc.first_line; + yylsp->first_column = yylloc.first_column; + yylsp->last_line = (yylsp-1)->last_line; + yylsp->last_column = (yylsp-1)->last_column; + yylsp->text = 0; + } + else + { + yylsp->last_line = (yylsp+yylen-1)->last_line; + yylsp->last_column = (yylsp+yylen-1)->last_column; + } +#endif + + /* Now "shift" the result of the reduction. + Determine what state that goes to, + based on the state we popped back to + and the rule number reduced by. */ + + yyn = yyr1[yyn]; + + yystate = yypgoto[yyn - YYNTBASE] + *yyssp; + if (yystate >= 0 && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTBASE]; + + goto yynewstate; + +yyerrlab: /* here on detecting error */ + + if (! yyerrstatus) + /* If not already recovering from an error, report this error. */ + { + ++yynerrs; + +#ifdef YYERROR_VERBOSE + yyn = yypact[yystate]; + + if (yyn > YYFLAG && yyn < YYLAST) + { + int size = 0; + char *msg; + int x, count; + + count = 0; + for (x = 0; x < (sizeof(yytname) / sizeof(char *)); x++) + if (yycheck[x + yyn] == x) + size += strlen(yytname[x]) + 15, count++; + msg = (char *) xmalloc(size + 15); + strcpy(msg, "parse error"); + + if (count < 5) + { + count = 0; + for (x = 0; x < (sizeof(yytname) / sizeof(char *)); x++) + if (yycheck[x + yyn] == x) + { + strcat(msg, count == 0 ? ", expecting `" : " or `"); + strcat(msg, yytname[x]); + strcat(msg, "'"); + count++; + } + } + yyerror(msg); + free(msg); + } + else +#endif /* YYERROR_VERBOSE */ + yyerror("parse error"); + } + +yyerrlab1: /* here on error raised explicitly by an action */ + + if (yyerrstatus == 3) + { + /* if just tried and failed to reuse lookahead token after an error, discard it. */ + + /* return failure if at end of input */ + if (yychar == YYEOF) + YYABORT; + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Discarding token %d (%s).\n", yychar, yytname[yychar1]); +#endif + + yychar = YYEMPTY; + } + + /* Else will try to reuse lookahead token + after shifting the error token. */ + + yyerrstatus = 3; /* Each real token shifted decrements this */ + + goto yyerrhandle; + +yyerrdefault: /* current state does not do anything special for the error token. */ + +#if 0 + /* This is wrong; only states that explicitly want error tokens + should shift them. */ + yyn = yydefact[yystate]; /* If its default is to accept any token, ok. Otherwise pop it.*/ + if (yyn) goto yydefault; +#endif + +yyerrpop: /* pop the current state because it cannot handle the error token */ + + if (yyssp == yyss) YYABORT; + yyvsp--; + yystate = *--yyssp; +#ifdef YYLSP_NEEDED + yylsp--; +#endif + +#if YYDEBUG != 0 + if (yydebug) + { + short *ssp1 = yyss - 1; + fprintf (stderr, "Error: state stack now"); + while (ssp1 != yyssp) + fprintf (stderr, " %d", *++ssp1); + fprintf (stderr, "\n"); + } +#endif + +yyerrhandle: + + yyn = yypact[yystate]; + if (yyn == YYFLAG) + goto yyerrdefault; + + yyn += YYTERROR; + if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != YYTERROR) + goto yyerrdefault; + + yyn = yytable[yyn]; + if (yyn < 0) + { + if (yyn == YYFLAG) + goto yyerrpop; + yyn = -yyn; + goto yyreduce; + } + else if (yyn == 0) + goto yyerrpop; + + if (yyn == YYFINAL) + YYACCEPT; + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Shifting error token, "); +#endif + + *++yyvsp = yylval; +#ifdef YYLSP_NEEDED + *++yylsp = yylloc; +#endif + + yystate = yyn; + goto yynewstate; +} +#line 1303 "ccdir/c-parse.y" + + +/* 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 + 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. */ + +static tree +make_pointer_declarator (type_quals, target) + tree type_quals, target; +{ + return build (INDIRECT_REF, type_quals, target); +} + +/* Given a chain of STRING_CST nodes, + concatenate them into one STRING_CST + and give it a suitable array-of-chars data type. */ + +static tree +combine_strings (strings) + tree strings; +{ + register tree value, t; + register int length = 1; + int wide_length = 0; + int wide_flag = 0; + int nchars; + + if (TREE_CHAIN (strings)) + { + /* More than one in the chain, so concatenate. */ + register char *p, *q; + + /* Don't include the \0 at the end of each substring, + except for the last one. + Count wide strings and ordinary strings separately. */ + for (t = strings; t; t = TREE_CHAIN (t)) + { + if (TREE_TYPE (t) == int_array_type_node) + { + wide_length += (TREE_STRING_LENGTH (t) - UNITS_PER_WORD); + wide_flag = 1; + } + else + length += (TREE_STRING_LENGTH (t) - 1); + } + + /* If anything is wide, the non-wides will be converted, + which makes them take more space. */ + if (wide_flag) + length = length * UNITS_PER_WORD + wide_length; + + p = (char *) savealloc (length); + + /* Copy the individual strings into the new combined string. + If the combined string is wide, convert the chars to ints + for any individual strings that are not wide. */ + + q = p; + for (t = strings; t; t = TREE_CHAIN (t)) + { + int len = (TREE_STRING_LENGTH (t) + - ((TREE_TYPE (t) == int_array_type_node) + ? UNITS_PER_WORD : 1)); + if ((TREE_TYPE (t) == int_array_type_node) == wide_flag) + { + bcopy (TREE_STRING_POINTER (t), q, len); + q += len; + } + else + { + int i; + for (i = 0; i < len; i++) + ((int *) q)[i] = TREE_STRING_POINTER (t)[i]; + q += len * UNITS_PER_WORD; + } + } + if (wide_flag) + { + int i; + for (i = 0; i < UNITS_PER_WORD; i++) + *q++ = 0; + } + else + *q = 0; + + value = make_node (STRING_CST); + TREE_STRING_POINTER (value) = p; + TREE_STRING_LENGTH (value) = length; + TREE_LITERAL (value) = 1; + } + else + { + value = strings; + length = TREE_STRING_LENGTH (value); + if (TREE_TYPE (value) == int_array_type_node) + wide_flag = 1; + } + + /* Compute the number of elements, for the array type. */ + nchars = wide_flag ? length / UNITS_PER_WORD : length; + + /* Create the array type for the string constant. + -Wwrite-strings says make the string constant an array of const char + so that copying it to a non-const pointer will get a warning. */ + if (warn_write_strings) + { + tree elements + = build_type_variant (wide_flag ? integer_type_node : char_type_node, + 1, 0); + TREE_TYPE (value) + = build_array_type (elements, + build_index_type (build_int_2 (nchars - 1, 0))); + } + else + TREE_TYPE (value) + = build_array_type (wide_flag ? integer_type_node : char_type_node, + build_index_type (build_int_2 (nchars - 1, 0))); + TREE_LITERAL (value) = 1; + TREE_STATIC (value) = 1; + return value; +} + +FILE *finput; /* input file. + Normally a pipe from the preprocessor. */ + +/* lexical analyzer */ + +static int maxtoken; /* Current nominal length of token buffer. */ +static char *token_buffer; /* Pointer to token buffer. + Actual allocated length is maxtoken + 2. */ +static int max_wide; /* Current nominal length of wide_buffer. */ +static int *wide_buffer; /* Pointer to wide-string buffer. + Actual allocated length is max_wide + 1. */ + +/* Nonzero if end-of-file has been seen on input. */ +static int end_of_file; + +/* Data type that represents the GNU C reserved words. */ +struct resword { char *name; short token; enum rid rid; }; + +#define MIN_WORD_LENGTH 2 /* minimum size for C keyword */ +#define MAX_WORD_LENGTH 13 /* maximum size for C keyword */ +#define MIN_HASH_VALUE 7 /* range of the hash keys values */ +#define MAX_HASH_VALUE 91 /* for the perfect hash generator */ +#define NORID RID_UNUSED + +/* This function performs the minimum-perfect hash mapping from input + string to reswords table index. It only looks at the first and + last characters in the string, thus assuring the O(1) lookup time + (this keeps our constant down to an insignificant amount!). Compiling + the following 2 functions as inline removes all overhead of the + function calls. */ + +#ifdef __GNUC__ +__inline +#endif +static int +hash (str, len) + register char *str; + register int len; +{ +/* This table is used to build the hash table index that recognizes + reserved words in 0(1) steps. It is larger than strictly necessary, + but I'm trading off the space for the time-saving luxury of avoiding + subtraction of an offset. All those ``91's'' (actually just a + short-hand for MAX_HASH_VALUE #defined above) are used to speed up + the search when the string found on the input stream doesn't have a + first or last character that is part of the set of alphabetic + characters that comprise the first or last characters in C + reserved words. */ + + static int hash_table[] = + { + 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, + 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, + 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, + 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, + 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, + 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, + 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, + 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, + 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, + 91, 91, 91, 91, 91, 1, 91, 2, 1, 32, + 7, 5, 18, 20, 1, 17, 91, 1, 18, 1, + 28, 1, 23, 91, 12, 20, 1, 41, 7, 15, + 91, 91, 10, 91, 91, 91, 91, 91, + }; + register int hval = len ; + + switch (hval) + { + default: + case 3: + hval += hash_table[str[2]]; + case 2: + case 1: + return hval + hash_table[str[0]] + hash_table[str[len - 1]]; + } +} + +/* This routine attempts to match the string found in the reswords table + with the one from the input stream. If all the relevant details + match then an actual strcmp comparison is performed and the address of + correct struct resword entry is returned. Otherwise, a NULL + pointer is returned. */ + +#ifdef __GNUC__ +__inline +#endif +struct resword * +is_reserved_word (str, len) + register char *str; + register int len; +{ + /* This is the hash table of keywords. + The order of keywords has been chosen for perfect hashing. + Therefore, this table cannot be updated by hand. + Use the program ``gperf,'' available with the latest libg++ + distribution, to generate an updated table. A file called + c-parse.gperf, distributed with GNU C, contains the keyword file. */ + + static struct resword reswords[] = + { + { "", }, { "", }, { "", }, { "", }, { "", }, { "", }, { "", }, + {"asm", ASM, NORID }, + {"auto", SCSPEC, RID_AUTO }, + {"__asm", ASM, NORID }, + {"do", DO, NORID }, + {"__asm__", ASM, NORID }, + {"break", BREAK, NORID }, + {"__typeof__", TYPEOF, NORID }, + { "", }, + {"__alignof__", ALIGNOF, NORID }, + { "", }, + {"__attribute__", ATTRIBUTE, NORID }, + { "", }, + {"__attribute", ATTRIBUTE, NORID }, + { "", }, + {"__volatile__", TYPE_QUAL, RID_VOLATILE }, + {"int", TYPESPEC, RID_INT }, + {"__volatile", TYPE_QUAL, RID_VOLATILE }, + { "", }, + {"float", TYPESPEC, RID_FLOAT }, + {"goto", GOTO, NORID }, + {"short", TYPESPEC, RID_SHORT }, + {"__typeof", TYPEOF, NORID }, + {"__inline__", SCSPEC, RID_INLINE }, + {"__alignof", ALIGNOF, NORID }, + {"__inline", SCSPEC, RID_INLINE }, + {"__signed__", TYPESPEC, RID_SIGNED }, + {"default", DEFAULT, NORID }, + {"else", ELSE, NORID }, + {"void", TYPESPEC, RID_VOID }, + {"__signed", TYPESPEC, RID_SIGNED }, + {"if", IF, NORID }, + {"volatile", TYPE_QUAL, RID_VOLATILE }, + {"struct", STRUCT, NORID }, + {"extern", SCSPEC, RID_EXTERN }, + {"__const", TYPE_QUAL, RID_CONST }, + {"while", WHILE, NORID }, + {"__const__", TYPE_QUAL, RID_CONST }, + {"switch", SWITCH, NORID }, + {"for", FOR, NORID }, + {"inline", SCSPEC, RID_INLINE }, + {"return", RETURN, NORID }, + {"typeof", TYPEOF, NORID }, + {"typedef", SCSPEC, RID_TYPEDEF }, + {"char", TYPESPEC, RID_CHAR }, + {"enum", ENUM, NORID }, + {"register", SCSPEC, RID_REGISTER }, + {"signed", TYPESPEC, RID_SIGNED }, + {"sizeof", SIZEOF, NORID }, + { "", }, { "", }, { "", }, { "", }, + {"double", TYPESPEC, RID_DOUBLE }, + {"static", SCSPEC, RID_STATIC }, + {"case", CASE, NORID }, + { "", }, { "", }, { "", }, { "", }, + {"const", TYPE_QUAL, RID_CONST }, + { "", }, { "", }, { "", }, + {"long", TYPESPEC, RID_LONG }, + { "", }, { "", }, + {"continue", CONTINUE, NORID }, + { "", }, { "", }, + {"unsigned", TYPESPEC, RID_UNSIGNED }, + { "", }, { "", }, { "", }, { "", }, { "", }, { "", }, { "", }, { "", }, { "", }, + { "", }, { "", }, { "", }, { "", }, { "", }, + {"union", UNION, NORID }, + }; + + if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH) + { + register int key = hash (str, len); + + if (key <= MAX_HASH_VALUE) + { + register char *s = reswords[key].name; + + if (*s == *str && !strcmp (str + 1, s + 1)) + return &reswords[key]; + } + } + return 0; +} + +/* The elements of `ridpointers' are identifier nodes + for the reserved type names and storage classes. + It is indexed by a RID_... value. */ + +tree ridpointers[(int) RID_MAX]; + +int check_newline (); + +void +init_lex () +{ + /* Start it at 0, because check_newline is called at the very beginning + and will increment it to 1. */ + lineno = 0; + + maxtoken = 40; + token_buffer = (char *) xmalloc (maxtoken + 2); + max_wide = 40; + wide_buffer = (int *) xmalloc ((max_wide + 1) * UNITS_PER_WORD); + + ridpointers[(int) RID_INT] = get_identifier ("int"); + ridpointers[(int) RID_CHAR] = get_identifier ("char"); + ridpointers[(int) RID_VOID] = get_identifier ("void"); + ridpointers[(int) RID_FLOAT] = get_identifier ("float"); + ridpointers[(int) RID_DOUBLE] = get_identifier ("double"); + ridpointers[(int) RID_SHORT] = get_identifier ("short"); + ridpointers[(int) RID_LONG] = get_identifier ("long"); + ridpointers[(int) RID_UNSIGNED] = get_identifier ("unsigned"); + ridpointers[(int) RID_SIGNED] = get_identifier ("signed"); + ridpointers[(int) RID_INLINE] = get_identifier ("inline"); + ridpointers[(int) RID_CONST] = get_identifier ("const"); + ridpointers[(int) RID_VOLATILE] = get_identifier ("volatile"); + ridpointers[(int) RID_AUTO] = get_identifier ("auto"); + ridpointers[(int) RID_STATIC] = get_identifier ("static"); + ridpointers[(int) RID_EXTERN] = get_identifier ("extern"); + ridpointers[(int) RID_TYPEDEF] = get_identifier ("typedef"); + ridpointers[(int) RID_REGISTER] = get_identifier ("register"); +} + +static void +reinit_parse_for_function () +{ +} + +/* If C is not whitespace, return C. + Otherwise skip whitespace and return first nonwhite char read. */ + +static int +skip_white_space (c) + register int c; +{ +#if 0 + register int inside; +#endif + + for (;;) + { + switch (c) + { + /* Don't recognize comments in cc1: all comments are removed by cpp, + and cpp output can include / and * consecutively as operators. */ +#if 0 + case '/': + c = getc (finput); + if (c != '*') + { + ungetc (c, finput); + return '/'; + } + + c = getc (finput); + + inside = 1; + while (inside) + { + if (c == '*') + { + while (c == '*') + c = getc (finput); + + if (c == '/') + { + inside = 0; + c = getc (finput); + } + } + else if (c == '\n') + { + lineno++; + c = getc (finput); + } + else if (c == EOF) + { + error ("unterminated comment"); + break; + } + else + c = getc (finput); + } + + break; +#endif + + case '\n': + c = check_newline (); + break; + + case ' ': + case '\t': + case '\f': + case '\r': + case '\v': + case '\b': + c = getc (finput); + break; + + case '\\': + c = getc (finput); + if (c == '\n') + lineno++; + else + error ("stray '\\' in program"); + c = getc (finput); + break; + + default: + return (c); + } + } +} + + + +/* Make the token buffer longer, preserving the data in it. + P should point to just beyond the last valid character in the old buffer. + The value we return is a pointer to the new buffer + at a place corresponding to P. */ + +static char * +extend_token_buffer (p) + char *p; +{ + int offset = p - token_buffer; + + maxtoken = maxtoken * 2 + 10; + token_buffer = (char *) xrealloc (token_buffer, maxtoken + 2); + + return token_buffer + offset; +} + +/* At the beginning of a line, increment the line number + and process any #-directive on this line. + If the line is a #-directive, read the entire line and return a newline. + Otherwise, return the line's first non-whitespace character. */ + +int +check_newline () +{ + register int c; + register int token; + + lineno++; + + /* Read first nonwhite char on the line. */ + + c = getc (finput); + while (c == ' ' || c == '\t') + c = getc (finput); + + if (c != '#') + { + /* If not #, return it so caller will use it. */ + return c; + } + + /* Read first nonwhite char after the `#'. */ + + c = getc (finput); + while (c == ' ' || c == '\t') + c = 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'. */ + + 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')) + 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')) + { + extern FILE *asm_out_file; + + if (pedantic) + error ("ANSI C does not allow #ident"); + + /* 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') + return c; + + ungetc (c, finput); + token = yylex (); + if (token != STRING + || TREE_CODE (yylval.ttype) != STRING_CST) + { + error ("invalid #ident"); + goto skipline; + } + +#ifdef ASM_OUTPUT_IDENT + ASM_OUTPUT_IDENT (asm_out_file, TREE_STRING_POINTER (yylval.ttype)); +#endif + + /* Skip the rest of this line. */ + goto skipline; + } + } + + error ("undefined or invalid # directive"); + goto skipline; + } + +linenum: + /* Here we have either `#line' or `# '. + In either case, it should be a line number; a digit should follow. */ + + while (c == ' ' || c == '\t') + c = getc (finput); + + /* If the # is the only nonwhite char on the line, + just ignore it. Check the new newline. */ + if (c == '\n') + return c; + + /* Something follows the #; read a token. */ + + ungetc (c, finput); + token = yylex (); + + if (token == CONSTANT + && TREE_CODE (yylval.ttype) == INTEGER_CST) + { + int old_lineno = lineno; + /* subtract one, because it is the following line that + gets the specified number */ + + 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); + if (c == '\n') + { + /* No more: store the line number and check following line. */ + lineno = l; + return c; + } + ungetc (c, finput); + + /* More follows: it must be a string constant (filename). */ + + token = yylex (); + if (token != STRING || TREE_CODE (yylval.ttype) != STRING_CST) + { + error ("invalid #line"); + goto skipline; + } + + input_filename + = (char *) permalloc (TREE_STRING_LENGTH (yylval.ttype) + 1); + strcpy (input_filename, TREE_STRING_POINTER (yylval.ttype)); + lineno = l; + + if (main_input_filename == 0) + main_input_filename = input_filename; + + /* Is this the last nonwhite stuff on the line? */ + c = getc (finput); + while (c == ' ' || c == '\t') + c = getc (finput); + if (c == '\n') + return c; + ungetc (c, finput); + + token = yylex (); + + /* `1' after file name means entering new file. + `2' after file name means just left a file. */ + + if (token == CONSTANT + && TREE_CODE (yylval.ttype) == INTEGER_CST) + { + if (TREE_INT_CST_LOW (yylval.ttype) == 1) + { + 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++; + } + else if (input_file_stack->next) + { + struct file_stack *p = input_file_stack; + input_file_stack = p->next; + free (p); + input_file_stack_tick++; + } + else + error ("#-lines for entering and leaving files don't match"); + } + } + else + error ("invalid #-line"); + + /* skip the rest of this line. */ + skipline: + if (c == '\n') + return c; + while ((c = getc (finput)) != EOF && c != '\n'); + return c; +} + +#define isalnum(char) ((char >= 'a' && char <= 'z') || (char >= 'A' && char <= 'Z') || (char >= '0' && char <= '9')) +#define isdigit(char) (char >= '0' && char <= '9') +#define ENDFILE -1 /* token that represents end-of-file */ + + +static int +readescape () +{ + register int c = getc (finput); + register int count, code; + int firstdig; + + switch (c) + { + case 'x': + code = 0; + count = 0; + while (1) + { + c = getc (finput); + if (!(c >= 'a' && c <= 'f') + && !(c >= 'A' && c <= 'F') + && !(c >= '0' && c <= '9')) + { + ungetc (c, finput); + 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 (count == 0) + firstdig = code; + count++; + } + if (count == 0) + error ("\\x used with no following hex digits"); + else if ((count - 1) * 4 >= TYPE_PRECISION (integer_type_node) + || (count > 1 + && ((1 << (TYPE_PRECISION (integer_type_node) - (count - 1) * 4)) + <= firstdig))) + warning ("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); + } + ungetc (c, finput); + return code; + + case '\\': case '\'': case '"': + return c; + + case '\n': + lineno++; + return -1; + + 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': + return TARGET_BELL; + + case 'v': + return TARGET_VT; + + case 'E': + return 033; + + case '?': + /* `\(', etc, are used at beginning of line to avoid confusing Emacs. */ + case '(': + case '{': + case '[': + return c; + } + if (c >= 040 && c <= 0177) + warning ("unknown escape sequence `\\%c'", c); + else + warning ("unknown escape sequence: `\\' followed by char code 0x%x", c); + return c; +} + +void +yyerror (string) + char *string; +{ + char buf[200]; + + strcpy (buf, string); + + /* We can't print string and character constants well + because the token_buffer contains the result of processing escapes. */ + if (end_of_file) + strcat (buf, " at end of input"); + else if (token_buffer[0] == 0) + strcat (buf, " at null character"); + else if (token_buffer[0] == '"') + strcat (buf, " before string constant"); + else if (token_buffer[0] == '\'') + strcat (buf, " before character constant"); + else if (token_buffer[0] < 040 || token_buffer[0] >= 0177) + sprintf (buf + strlen (buf), " before character 0%o", token_buffer[0]); + else + strcat (buf, " before `%s'"); + + error (buf, token_buffer); +} + +static int nextchar = -1; + +static int +yylex () +{ + register int c; + register char *p; + register int value; + int wide_flag = 0; + + if (nextchar >= 0) + c = nextchar, nextchar = -1; + else + c = getc (finput); + + /* Effectively do c = skip_white_space (c) + but do it faster in the usual cases. */ + while (1) + switch (c) + { + case ' ': + case '\t': + case '\f': + case '\r': + case '\v': + case '\b': + c = getc (finput); + break; + + case '\n': + case '/': + case '\\': + c = skip_white_space (c); + default: + goto found_nonwhite; + } + found_nonwhite: + + token_buffer[0] = c; + token_buffer[1] = 0; + +/* yylloc.first_line = lineno; */ + + switch (c) + { + case EOF: + end_of_file = 1; + token_buffer[0] = 0; + 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); + if (c == '\'') + { + wide_flag = 1; + goto char_constant; + } + if (c == '"') + { + wide_flag = 1; + goto string_constant; + } + ungetc (c, finput); + } + + case 'A': case 'B': case 'C': case 'D': case 'E': + 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 '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': + case '_': + letter: + p = token_buffer; + while (isalnum (c) || c == '_' || c == '$') + { + if (p >= token_buffer + maxtoken) + p = extend_token_buffer (p); + if (c == '$' && ! dollars_in_ident) + break; + + *p++ = c; + c = getc (finput); + } + + *p = 0; + nextchar = c; + + value = IDENTIFIER; + yylval.itype = 0; + + /* Try to recognize a keyword. Uses minimum-perfect hash function */ + + { + register struct resword *ptr; + + if (ptr = is_reserved_word (token_buffer, p - token_buffer)) + { + if (ptr->rid) + yylval.ttype = ridpointers[(int) ptr->rid]; + if ((! flag_no_asm + /* -fno-asm means don't recognize the non-ANSI keywords. */ + || ((int) ptr->token != ASM + && (int) ptr->token != TYPEOF + && ptr->rid != RID_INLINE) + /* Recognize __asm and __inline despite -fno-asm. */ + || token_buffer[0] == '_') + /* -ftraditional means don't recognize nontraditional keywords + typeof, const, volatile, signed or inline. */ + && (! flag_traditional + || ((int) ptr->token != TYPE_QUAL + && (int) ptr->token != TYPEOF + && ptr->rid != RID_SIGNED + && ptr->rid != RID_INLINE) + /* Recognize __inline, etc. despite -ftraditional. */ + || token_buffer[0] == '_')) + value = (int) ptr->token; + } + } + + /* If we did not find a keyword, look for an identifier + (or a typename). */ + + if (value == IDENTIFIER) + { + yylval.ttype = get_identifier (token_buffer); + lastiddecl = lookup_name (yylval.ttype); + + if (lastiddecl != 0 && TREE_CODE (lastiddecl) == TYPE_DECL) + value = TYPENAME; + } + + break; + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + case '.': + { + int base = 10; + int count = 0; + int largest_digit = 0; + int numdigits = 0; + /* for multi-precision arithmetic, + we store only 8 live bits in each short, + giving us 64 bits of reliable precision */ + short shorts[8]; + int overflow = 0; + + enum anon1 { NOT_FLOAT, AFTER_POINT, TOO_MANY_POINTS} floatflag + = NOT_FLOAT; + + for (count = 0; count < 8; count++) + shorts[count] = 0; + + p = token_buffer; + *p++ = c; + + if (c == '0') + { + *p++ = (c = getc (finput)); + if ((c == 'x') || (c == 'X')) + { + base = 16; + *p++ = (c = getc (finput)); + } + else + { + base = 8; + numdigits++; + } + } + + /* Read all the digits-and-decimal-points. */ + + while (c == '.' + || (isalnum (c) && (c != 'l') && (c != 'L') + && (c != 'u') && (c != 'U') + && (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) + { + error ("malformed floating constant"); + floatflag = TOO_MANY_POINTS; + } + else + floatflag = AFTER_POINT; + + base = 10; + *p++ = c = getc (finput); + /* 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 (c == '.') + { + c = getc (finput); + if (c == '.') + { + *p++ = c; + *p = 0; + return ELLIPSIS; + } + error ("parse error at `..'"); + } + ungetc (c, finput); + token_buffer[1] = 0; + value = '.'; + goto done; + } + } + else + { + /* It is not a decimal point. + It should be a digit (perhaps a hex digit). */ + + if (isdigit (c)) + { + c = c - '0'; + } + else if (base <= 10) + { + if ((c&~040) == 'E') + { + base = 10; + floatflag = AFTER_POINT; + break; /* start of exponent */ + } + error ("nondigits in number and not hexadecimal"); + c = 0; + } + else if (c >= 'a') + { + c = c - 'a' + 10; + } + else + { + c = c - 'A' + 10; + } + if (c >= largest_digit) + largest_digit = c; + numdigits++; + + for (count = 0; count < 8; count++) + { + shorts[count] *= base; + if (count) + { + shorts[count] += (shorts[count-1] >> 8); + shorts[count-1] &= (1<<8)-1; + } + else shorts[0] += c; + } + + if (shorts[7] >= 1<<8 + || shorts[7] < - (1 << 8)) + overflow = TRUE; + + if (p >= token_buffer + maxtoken - 3) + p = extend_token_buffer (p); + *p++ = (c = getc (finput)); + } + } + + if (numdigits == 0) + error ("numeric constant with no digits"); + + if (largest_digit >= base) + error ("numeric constant contains digits beyond the radix"); + + /* Remove terminating char from the token buffer and delimit the string */ + *--p = 0; + + if (floatflag != NOT_FLOAT) + { + tree type = double_type_node; + char f_seen = 0; + char l_seen = 0; + REAL_VALUE_TYPE value; + + /* Read explicit exponent if any, and put it in tokenbuf. */ + + if ((c == 'e') || (c == 'E')) + { + if (p >= token_buffer + maxtoken - 3) + p = extend_token_buffer (p); + *p++ = c; + c = getc (finput); + if ((c == '+') || (c == '-')) + { + *p++ = c; + c = getc (finput); + } + if (! isdigit (c)) + error ("floating constant exponent has no digits"); + while (isdigit (c)) + { + if (p >= token_buffer + maxtoken - 3) + p = extend_token_buffer (p); + *p++ = c; + c = getc (finput); + } + } + + *p = 0; + errno = 0; + value = REAL_VALUE_ATOF (token_buffer); +#ifdef ERANGE + if (errno == ERANGE && !flag_traditional) + { + char *p1 = token_buffer; + /* Check for "0.0" and variants; + Sunos 4 spuriously returns ERANGE for them. */ + while (*p1 == '0') p1++; + if (*p1 == '.') + { + p1++; + while (*p1 == '0') p1++; + } + if (*p1 == 'e' || *p1 == 'E') + { + /* with significand==0, ignore the exponent */ + p1++; + while (*p1 != 0) p1++; + } + /* ERANGE is also reported for underflow, + so test the value to distinguish overflow from that. */ + if (*p1 != 0 && (value > 1.0 || value < -1.0)) + warning ("floating point number exceeds range of `double'"); + } +#endif + + /* Read the suffixes to choose a data type. */ + while (1) + { + if (c == 'f' || c == 'F') + { + float floater; + if (f_seen) + error ("two `f's in floating constant"); + f_seen = 1; + type = float_type_node; + floater = value; + value = floater; + } + else if (c == 'l' || c == 'L') + { + if (l_seen) + error ("two `l's in floating constant"); + l_seen = 1; + type = long_double_type_node; + } + else + { + 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 = getc (finput); + } + } + break; + } + if (p >= token_buffer + maxtoken - 3) + p = extend_token_buffer (p); + *p++ = c; + c = getc (finput); + } + + /* Create a node with determined type and value. */ + yylval.ttype = build_real (type, value); + + ungetc (c, finput); + *p = 0; + } + else + { + tree type; + int spec_unsigned = 0; + int spec_long = 0; + int spec_long_long = 0; + + while (1) + { + if (c == 'u' || c == 'U') + { + if (spec_unsigned) + error ("two `u's in integer constant"); + spec_unsigned = 1; + } + else if (c == 'l' || c == 'L') + { + if (spec_long) + { + if (spec_long_long) + error ("three `l's in integer constant"); + else if (pedantic) + warning ("ANSI C forbids long long integer constants"); + spec_long_long = 1; + } + spec_long = 1; + } + else + { + 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 = getc (finput); + } + } + break; + } + if (p >= token_buffer + maxtoken - 3) + p = extend_token_buffer (p); + *p++ = c; + c = getc (finput); + } + + ungetc (c, finput); + + if ((overflow || shorts[7] || shorts[6] || shorts[5] || shorts[4]) + && !spec_long_long) + warning ("integer constant out of range"); + + /* If it won't fit in a signed long long, make it unsigned. + We can't distinguish based on the tree node because + any integer constant fits any long long type. */ + if (shorts[7] >= (1<<8)) + spec_unsigned = 1; + + /* This is simplified by the fact that our constant + is always positive. */ + yylval.ttype + = (build_int_2 + ((shorts[3]<<24) + (shorts[2]<<16) + (shorts[1]<<8) + shorts[0], + (spec_long_long + ? (shorts[7]<<24) + (shorts[6]<<16) + (shorts[5]<<8) + shorts[4] + : 0))); + + if (!spec_long && !spec_unsigned + && int_fits_type_p (yylval.ttype, integer_type_node)) + type = integer_type_node; + + else if (!spec_long && (base != 10 || spec_unsigned) + && int_fits_type_p (yylval.ttype, unsigned_type_node)) + 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)) + type = long_unsigned_type_node; + + else if (! spec_unsigned + && int_fits_type_p (yylval.ttype, + long_long_integer_type_node)) + type = long_long_integer_type_node; + + else if (int_fits_type_p (yylval.ttype, + long_long_unsigned_type_node)) + type = long_long_unsigned_type_node; + + else + { + type = long_long_integer_type_node; + warning ("integer constant out of range"); + } + + TREE_TYPE (yylval.ttype) = type; + *p = 0; + } + + value = CONSTANT; break; + } + + case '\'': + char_constant: + { + register int result = 0; + register num_chars = 0; + int width = TYPE_PRECISION (char_type_node); + int max_chars; + + if (wide_flag) width = TYPE_PRECISION (integer_type_node); + + max_chars = TYPE_PRECISION (integer_type_node) / width; + + while (1) + { + tryagain: + + c = getc (finput); + + if (c == '\'' || c == EOF) + break; + + if (c == '\\') + { + c = readescape (); + if (c < 0) + goto tryagain; + if (width < HOST_BITS_PER_INT + && (unsigned) c >= (1 << width)) + warning ("escape sequence out of range for character"); + } + else if (c == '\n') + { + if (pedantic) + warning ("ANSI C forbids newline in character constant"); + lineno++; + } + + num_chars++; + if (num_chars > maxtoken - 4) + extend_token_buffer (token_buffer); + + token_buffer[num_chars] = c; + + /* Merge character into result; ignore excess chars. */ + if (num_chars < max_chars + 1) + { + if (width < HOST_BITS_PER_INT) + result = (result << width) | (c & ((1 << width) - 1)); + else + result = c; + } + } + + token_buffer[num_chars + 1] = '\''; + token_buffer[num_chars + 2] = 0; + + if (c != '\'') + error ("malformatted character constant"); + else if (num_chars == 0) + error ("empty character constant"); + else if (num_chars > max_chars) + { + num_chars = max_chars; + error ("character constant too long"); + } + else if (num_chars != 1 && ! flag_traditional) + warning ("multi-character character constant"); + + /* If char type is signed, sign-extend the constant. */ + if (! wide_flag) + { + int num_bits = num_chars * width; + if (TREE_UNSIGNED (char_type_node) + || ((result >> (num_bits - 1)) & 1) == 0) + yylval.ttype + = build_int_2 (result & ((unsigned) ~0 + >> (HOST_BITS_PER_INT - num_bits)), + 0); + else + yylval.ttype + = build_int_2 (result | ~((unsigned) ~0 + >> (HOST_BITS_PER_INT - num_bits)), + -1); + } + else + yylval.ttype = build_int_2 (result, 0); + + TREE_TYPE (yylval.ttype) = integer_type_node; + value = CONSTANT; break; + } + + case '"': + string_constant: + { + int *widep; + + c = getc (finput); + p = token_buffer + 1; + + if (wide_flag) + widep = wide_buffer; + + while (c != '"' && c >= 0) + { + if (c == '\\') + { + c = readescape (); + if (c < 0) + goto skipnewline; + if (!wide_flag && c >= (1 << TYPE_PRECISION (char_type_node))) + warning ("escape sequence out of range for character"); + } + else if (c == '\n') + { + if (pedantic) + warning ("ANSI C forbids newline in string constant"); + lineno++; + } + + /* Store the char in C into the appropriate buffer. */ + + if (wide_flag) + { + if (widep == wide_buffer + max_wide) + { + int n = widep - wide_buffer; + max_wide *= 2; + wide_buffer + = (int *) xrealloc (wide_buffer, + (max_wide + 1) * UNITS_PER_WORD); + widep = wide_buffer + n; + } + *widep++ = c; + } + else + { + if (p == token_buffer + maxtoken) + p = extend_token_buffer (p); + *p++ = c; + } + + skipnewline: + c = getc (finput); + } + + /* We have read the entire constant. + Construct a STRING_CST for the result. */ + + if (wide_flag) + { + /* If this is a L"..." wide-string, make a vector + of the ints in wide_buffer. */ + *widep = 0; + /* We have not implemented the case where `int' + on the target and on the execution machine differ in size. */ + if (TYPE_PRECISION (integer_type_node) + != sizeof (int) * BITS_PER_UNIT) + abort (); + yylval.ttype + = build_string ((widep - wide_buffer + 1) * sizeof (int), + wide_buffer); + TREE_TYPE (yylval.ttype) = int_array_type_node; + } + else + { + *p = 0; + yylval.ttype = build_string (p - token_buffer, token_buffer + 1); + TREE_TYPE (yylval.ttype) = char_array_type_node; + } + + *p++ = '"'; + *p = 0; + + value = STRING; break; + } + + case '+': + case '-': + case '&': + case '|': + case '<': + case '>': + case '*': + case '/': + case '%': + case '^': + case '!': + case '=': + { + register int c1; + + combine: + + switch (c) + { + case '+': + yylval.code = PLUS_EXPR; break; + case '-': + yylval.code = MINUS_EXPR; break; + case '&': + yylval.code = BIT_AND_EXPR; break; + case '|': + yylval.code = BIT_IOR_EXPR; break; + case '*': + yylval.code = MULT_EXPR; break; + case '/': + yylval.code = TRUNC_DIV_EXPR; break; + case '%': + yylval.code = TRUNC_MOD_EXPR; break; + case '^': + yylval.code = BIT_XOR_EXPR; break; + case LSHIFT: + yylval.code = LSHIFT_EXPR; break; + case RSHIFT: + yylval.code = RSHIFT_EXPR; break; + case '<': + yylval.code = LT_EXPR; break; + case '>': + yylval.code = GT_EXPR; break; + } + + token_buffer[1] = c1 = getc (finput); + token_buffer[2] = 0; + + if (c1 == '=') + { + switch (c) + { + case '<': + value = ARITHCOMPARE; yylval.code = LE_EXPR; goto done; + case '>': + value = ARITHCOMPARE; yylval.code = GE_EXPR; goto done; + case '!': + value = EQCOMPARE; yylval.code = NE_EXPR; goto done; + case '=': + value = EQCOMPARE; yylval.code = EQ_EXPR; goto done; + } + value = ASSIGN; goto done; + } + else if (c == c1) + switch (c) + { + case '+': + value = PLUSPLUS; goto done; + case '-': + value = MINUSMINUS; goto done; + case '&': + value = ANDAND; goto done; + case '|': + value = OROR; goto done; + case '<': + c = LSHIFT; + goto combine; + case '>': + c = RSHIFT; + goto combine; + } + else if ((c == '-') && (c1 == '>')) + { value = POINTSAT; goto done; } + ungetc (c1, finput); + token_buffer[1] = 0; + + if ((c == '<') || (c == '>')) + value = ARITHCOMPARE; + else value = c; + goto done; + } + + case 0: + /* Don't make yyparse think this is eof. */ + value = 1; + break; + + default: + value = c; + } + +done: +/* yylloc.last_line = lineno; */ + + return value; +} diff --git a/gcc-1.40/c-parse.y b/gcc-1.40/c-parse.y new file mode 100644 index 0000000..882ca4f --- /dev/null +++ b/gcc-1.40/c-parse.y @@ -0,0 +1,2882 @@ +/* YACC parser for C syntax. + Copyright (C) 1987, 1988, 1989 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 1, 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. */ + + +/* To whomever it may concern: I have heard that such a thing was once +written by AT&T, but I have never seen it. */ + +%expect 8 + +/* These are the 8 conflicts you should get in parse.output; + the state numbers may vary if minor changes in the grammar are made. + +State 41 contains 1 shift/reduce conflict. (Two ways to recover from error.) +State 92 contains 1 shift/reduce conflict. (Two ways to recover from error.) +State 99 contains 1 shift/reduce conflict. (Two ways to recover from error.) +State 103 contains 1 shift/reduce conflict. (Two ways to recover from error.) +State 119 contains 1 shift/reduce conflict. (See comment at component_decl.) +State 183 contains 1 shift/reduce conflict. (Two ways to recover from error.) +State 193 contains 1 shift/reduce conflict. (Two ways to recover from error.) +State 199 contains 1 shift/reduce conflict. (Two ways to recover from error.) +*/ + +%{ +#include "config.h" +#include "tree.h" +#include "input.h" +#include "c-parse.h" +#include "c-tree.h" + +#include +#include + +#ifndef errno +extern int errno; +#endif + +void yyerror (); + +/* Cause the `yydebug' variable to be defined. */ +#define YYDEBUG 1 +%} + +%start program + +%union {long itype; tree ttype; enum tree_code code; } + +/* All identifiers that are not reserved words + and are not declared typedefs in the current block */ +%token IDENTIFIER + +/* All identifiers that are declared typedefs in the current block. + In some contexts, they are treated just like IDENTIFIER, + but they can also serve as typespecs in declarations. */ +%token TYPENAME + +/* Reserved words that specify storage class. + yylval contains an IDENTIFIER_NODE which indicates which one. */ +%token SCSPEC + +/* Reserved words that specify type. + yylval contains an IDENTIFIER_NODE which indicates which one. */ +%token TYPESPEC + +/* Reserved words that qualify type: "const" or "volatile". + yylval contains an IDENTIFIER_NODE which indicates which one. */ +%token TYPE_QUAL + +/* Character or numeric constants. + yylval is the node for the constant. */ +%token CONSTANT + +/* String constants in raw form. + yylval is a STRING_CST node. */ +%token STRING + +/* "...", used for functions with variable arglists. */ +%token ELLIPSIS + +/* the reserved words */ +%token SIZEOF ENUM STRUCT UNION IF ELSE WHILE DO FOR SWITCH CASE DEFAULT +%token BREAK CONTINUE RETURN GOTO ASM TYPEOF ALIGNOF +%token ATTRIBUTE + +/* Add precedence rules to solve dangling else s/r conflict */ +%nonassoc IF +%nonassoc ELSE + +/* Define the operator tokens and their precedences. + The value is an integer because, if used, it is the tree code + to use in the expression made from the operator. */ + +%right ASSIGN '=' +%right '?' ':' +%left OROR +%left ANDAND +%left '|' +%left '^' +%left '&' +%left EQCOMPARE +%left ARITHCOMPARE +%left LSHIFT RSHIFT +%left '+' '-' +%left '*' '/' '%' +%right UNARY PLUSPLUS MINUSMINUS +%left HYPERUNARY +%left POINTSAT '.' '(' '[' + +%type unop + +%type identifier IDENTIFIER TYPENAME CONSTANT expr nonnull_exprlist exprlist +%type expr_no_commas cast_expr unary_expr primary string STRING +%type typed_declspecs reserved_declspecs +%type typed_typespecs reserved_typespecquals +%type declmods typespec typespecqual_reserved +%type SCSPEC TYPESPEC TYPE_QUAL nonempty_type_quals maybe_type_qual +%type initdecls notype_initdecls initdcl notype_initdcl +%type init initlist maybeasm +%type asm_operands nonnull_asm_operands asm_operand asm_clobbers +%type maybe_attribute attribute_list attrib + +%type compstmt + +%type declarator +%type notype_declarator after_type_declarator +%type parm_declarator + +%type structsp component_decl_list component_decl_list2 +%type component_decl components component_declarator +%type enumlist enumerator +%type typename absdcl absdcl1 type_quals +%type xexpr parms parm identifiers + +%type parmlist parmlist_1 parmlist_2 +%type parmlist_or_identifiers parmlist_or_identifiers_1 + +%type setspecs + +%{ +/* 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 + used in a context which makes it a reference to a variable. */ +static tree lastiddecl; + +static tree make_pointer_declarator (); +static tree combine_strings (); +static void reinit_parse_for_function (); + +/* List of types and structure classes of the current declaration. */ +tree current_declspecs; + +/* Stack of saved values of current_declspecs. */ +tree declspec_stack; + +int undeclared_variable_notice; /* 1 if we explained undeclared var errors. */ + +static int yylex (); +%} + +%% +program: /* empty */ + | extdefs + ; + +/* 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. */ + +extdefs: + {$$ = NULL_TREE; } extdef + | extdefs {$$ = NULL_TREE; } extdef + ; + +extdef: + fndef + | datadef + | ASM '(' string ')' ';' + { if (pedantic) + warning ("ANSI C forbids use of `asm' keyword"); + if (TREE_CHAIN ($3)) $3 = combine_strings ($3); + assemble_asm ($3); } + ; + +datadef: + setspecs notype_initdecls ';' + { if (pedantic) + error ("ANSI C forbids data definition lacking type or storage class"); + else if (!flag_traditional) + warning ("data definition lacks type or storage class"); } + | declmods setspecs notype_initdecls ';' + {} + | typed_declspecs setspecs initdecls ';' + {} + | declmods ';' + { error ("empty declaration"); } + | typed_declspecs ';' + { shadow_tag ($1); } + | error ';' + | error '}' + | ';' + { if (pedantic) + warning ("ANSI C does not allow extra `;' outside of a function"); } + ; + +fndef: + typed_declspecs setspecs declarator + { if (! start_function ($1, $3)) + YYFAIL; + reinit_parse_for_function (); } + xdecls + { store_parm_decls (); } + compstmt_or_error + { finish_function (lineno); } + | typed_declspecs setspecs declarator error + { } + | declmods setspecs notype_declarator + { if (! start_function ($1, $3)) + YYFAIL; + reinit_parse_for_function (); } + xdecls + { store_parm_decls (); } + compstmt_or_error + { finish_function (lineno); } + | declmods setspecs notype_declarator error + { } + | setspecs notype_declarator + { if (! start_function (0, $2)) + YYFAIL; + reinit_parse_for_function (); } + xdecls + { store_parm_decls (); } + compstmt_or_error + { finish_function (lineno); } + | setspecs notype_declarator error + { } + ; + +identifier: + IDENTIFIER + | TYPENAME + ; + +unop: '&' + { $$ = ADDR_EXPR; } + | '-' + { $$ = NEGATE_EXPR; } + | '+' + { $$ = CONVERT_EXPR; } + | PLUSPLUS + { $$ = PREINCREMENT_EXPR; } + | MINUSMINUS + { $$ = PREDECREMENT_EXPR; } + | '~' + { $$ = BIT_NOT_EXPR; } + | '!' + { $$ = TRUTH_NOT_EXPR; } + ; + +expr: nonnull_exprlist + { $$ = build_compound_expr ($1); } + ; + +exprlist: + /* empty */ + { $$ = NULL_TREE; } + | nonnull_exprlist + ; + +nonnull_exprlist: + expr_no_commas + { $$ = build_tree_list (NULL_TREE, $1); } + | nonnull_exprlist ',' expr_no_commas + { chainon ($1, build_tree_list (NULL_TREE, $3)); } + ; + +unary_expr: + primary + | '*' cast_expr %prec UNARY + { $$ = build_indirect_ref ($2, "unary *"); } + | unop cast_expr %prec UNARY + { $$ = build_unary_op ($1, $2, 0); } + | SIZEOF unary_expr %prec UNARY + { if (TREE_CODE ($2) == COMPONENT_REF + && TREE_PACKED (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); + $$ = c_sizeof (TREE_TYPE ($2)); } + | SIZEOF '(' typename ')' %prec HYPERUNARY + { $$ = c_sizeof (groktypename ($3)); } + | ALIGNOF unary_expr %prec UNARY + { if (TREE_CODE ($2) == COMPONENT_REF + && TREE_PACKED (TREE_OPERAND ($2, 1))) + error ("`__alignof' applied to a bit-field"); + if (TREE_CODE ($2) == INDIRECT_REF) + { + tree t = TREE_OPERAND ($2, 0); + tree best = t; + int bestalign = TYPE_ALIGN (TREE_TYPE (TREE_TYPE (t))); + while (TREE_CODE (t) == NOP_EXPR + && TREE_CODE (TREE_TYPE (TREE_OPERAND (t, 0))) == POINTER_TYPE) + { + int thisalign; + t = TREE_OPERAND (t, 0); + thisalign = TYPE_ALIGN (TREE_TYPE (TREE_TYPE (t))); + if (thisalign > bestalign) + best = t, bestalign = thisalign; + } + $$ = c_alignof (TREE_TYPE (TREE_TYPE (best))); + } + else + { + /* ANSI says arrays and fns are converted inside comma. + But we can't 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); + $$ = c_alignof (TREE_TYPE ($2)); + } + } + | ALIGNOF '(' typename ')' %prec HYPERUNARY + { $$ = c_alignof (groktypename ($3)); } + ; + +cast_expr: + unary_expr + | '(' typename ')' cast_expr %prec UNARY + { tree type = groktypename ($2); + $$ = build_c_cast (type, $4); } + | '(' typename ')' '{' initlist maybecomma '}' %prec UNARY + { tree type = groktypename ($2); + if (pedantic) + warning ("ANSI C forbids constructor expressions"); + $$ = digest_init (type, build_nt (CONSTRUCTOR, NULL_TREE, nreverse ($5)), 0); + if (TREE_CODE (type) == ARRAY_TYPE && TYPE_SIZE (type) == 0) + { + int failure = complete_array_type (type, $$, 1); + if (failure) + abort (); + } + } + ; + +expr_no_commas: + cast_expr + | expr_no_commas '+' expr_no_commas + { $$ = build_binary_op ($2, $1, $3); } + | expr_no_commas '-' expr_no_commas + { $$ = build_binary_op ($2, $1, $3); } + | expr_no_commas '*' expr_no_commas + { $$ = build_binary_op ($2, $1, $3); } + | expr_no_commas '/' expr_no_commas + { $$ = build_binary_op ($2, $1, $3); } + | expr_no_commas '%' expr_no_commas + { $$ = build_binary_op ($2, $1, $3); } + | expr_no_commas LSHIFT expr_no_commas + { $$ = build_binary_op ($2, $1, $3); } + | expr_no_commas RSHIFT expr_no_commas + { $$ = build_binary_op ($2, $1, $3); } + | expr_no_commas ARITHCOMPARE expr_no_commas + { $$ = build_binary_op ($2, $1, $3); } + | expr_no_commas EQCOMPARE expr_no_commas + { $$ = build_binary_op ($2, $1, $3); } + | expr_no_commas '&' expr_no_commas + { $$ = build_binary_op ($2, $1, $3); } + | expr_no_commas '|' expr_no_commas + { $$ = build_binary_op ($2, $1, $3); } + | expr_no_commas '^' expr_no_commas + { $$ = build_binary_op ($2, $1, $3); } + | expr_no_commas ANDAND expr_no_commas + { $$ = build_binary_op (TRUTH_ANDIF_EXPR, $1, $3); } + | expr_no_commas OROR expr_no_commas + { $$ = build_binary_op (TRUTH_ORIF_EXPR, $1, $3); } + | expr_no_commas '?' xexpr ':' expr_no_commas + { $$ = build_conditional_expr ($1, $3, $5); } + | expr_no_commas '=' expr_no_commas + { $$ = build_modify_expr ($1, NOP_EXPR, $3); } + | expr_no_commas ASSIGN expr_no_commas + { $$ = build_modify_expr ($1, $2, $3); } + ; + +primary: + IDENTIFIER + { $$ = lastiddecl; + if (!$$ || $$ == error_mark_node) + { + if (yychar == YYEMPTY) + yychar = YYLEX; + if (yychar == '(') + { + $$ = implicitly_declare ($1); + assemble_external ($$); + TREE_USED ($$) = 1; + } + else if (current_function_decl == 0) + { + error ("`%s' undeclared, outside of functions", + IDENTIFIER_POINTER ($1)); + $$ = error_mark_node; + } + else + { + if (IDENTIFIER_GLOBAL_VALUE ($1) != error_mark_node + || IDENTIFIER_ERROR_LOCUS ($1) != current_function_decl) + { + error ("`%s' undeclared (first use this function)", + IDENTIFIER_POINTER ($1)); + + if (! undeclared_variable_notice) + { + error ("(Each undeclared identifier is reported only once"); + error ("for each function it appears in.)"); + undeclared_variable_notice = 1; + } + } + $$ = error_mark_node; + /* Prevent repeated error messages. */ + IDENTIFIER_GLOBAL_VALUE ($1) = error_mark_node; + IDENTIFIER_ERROR_LOCUS ($1) = current_function_decl; + } + } + else if (! TREE_USED ($$)) + { + if (TREE_EXTERNAL ($$)) + assemble_external ($$); + TREE_USED ($$) = 1; + } + if (TREE_CODE ($$) == CONST_DECL) + $$ = DECL_INITIAL ($$); + } + | CONSTANT + | string + { $$ = combine_strings ($1); } + | '(' expr ')' + { $$ = $2; } + | '(' error ')' + { $$ = error_mark_node; } + | '(' + { if (current_function_decl == 0) + { + error ("braced-group within expression allowed only inside a function"); + YYFAIL; + } + keep_next_level (); + $$ = expand_start_stmt_expr (); } + compstmt ')' + { tree rtl_exp; + if (pedantic) + warning ("ANSI C forbids braced-groups within expressions"); + rtl_exp = expand_end_stmt_expr ($2); + $$ = $3; + TREE_USED ($$) = 0; + /* Since the statements have side effects, + consider this volatile. */ + TREE_VOLATILE ($$) = 1; + TREE_TYPE ($$) = TREE_TYPE (rtl_exp); + STMT_BODY ($$) = rtl_exp; } + | primary '(' exprlist ')' %prec '.' + { $$ = build_function_call ($1, $3); } + | primary '[' expr ']' %prec '.' + { $$ = build_array_ref ($1, $3); } + | primary '.' identifier + { $$ = build_component_ref ($1, $3); } + | primary POINTSAT identifier + { $$ = build_component_ref (build_indirect_ref ($1, "->"), $3); } + | primary PLUSPLUS + { $$ = build_unary_op (POSTINCREMENT_EXPR, $1, 0); } + | primary MINUSMINUS + { $$ = build_unary_op (POSTDECREMENT_EXPR, $1, 0); } + ; + +/* Produces a STRING_CST with perhaps more STRING_CSTs chained onto it. */ +string: + STRING + | string STRING + { $$ = chainon ($1, $2); } + ; + +xdecls: + /* empty */ + | decls + ; + +decls: + decl + | errstmt + | decls decl + | decl errstmt + ; + +/* records the type and storage class specs to use for processing + the declarators that follow. + Maintains a stack of outer-level values of current_declspecs, + for the sake of parm declarations nested in function declarators. */ +setspecs: /* empty */ + { $$ = suspend_momentary (); + declspec_stack = tree_cons (0, current_declspecs, + declspec_stack); + current_declspecs = $0; } + ; + +decl: + typed_declspecs setspecs initdecls ';' + { current_declspecs = TREE_VALUE (declspec_stack); + declspec_stack = TREE_CHAIN (declspec_stack); + resume_momentary ($2); } + | declmods setspecs notype_initdecls ';' + { current_declspecs = TREE_VALUE (declspec_stack); + declspec_stack = TREE_CHAIN (declspec_stack); + resume_momentary ($2); } + | typed_declspecs ';' + { shadow_tag ($1); } + | declmods ';' + { warning ("empty declaration"); } + ; + +/* 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. */ + +typed_declspecs: + typespec reserved_declspecs + { $$ = tree_cons (NULL_TREE, $1, $2); } + | declmods typespec reserved_declspecs + { $$ = chainon ($3, tree_cons (NULL_TREE, $2, $1)); } + ; + +reserved_declspecs: /* empty */ + { $$ = NULL_TREE; } + | reserved_declspecs typespecqual_reserved + { $$ = tree_cons (NULL_TREE, $2, $1); } + | reserved_declspecs SCSPEC + { $$ = tree_cons (NULL_TREE, $2, $1); } + ; + +/* List of just storage classes and type modifiers. + A declaration can start with just this, but then it cannot be used + to redeclare a typedef-name. */ + +declmods: + TYPE_QUAL + { $$ = tree_cons (NULL_TREE, $1, NULL_TREE); } + | SCSPEC + { $$ = tree_cons (NULL_TREE, $1, NULL_TREE); } + | declmods TYPE_QUAL + { $$ = tree_cons (NULL_TREE, $2, $1); } + | declmods SCSPEC + { $$ = tree_cons (NULL_TREE, $2, $1); } + ; + + +/* Used instead of declspecs where storage classes are not allowed + (that is, for typenames and structure components). + Don't accept a typedef-name if anything but a modifier precedes it. */ + +typed_typespecs: + typespec reserved_typespecquals + { $$ = tree_cons (NULL_TREE, $1, $2); } + | nonempty_type_quals typespec reserved_typespecquals + { $$ = chainon ($3, tree_cons (NULL_TREE, $2, $1)); } + ; + +reserved_typespecquals: /* empty */ + { $$ = NULL_TREE; } + | reserved_typespecquals typespecqual_reserved + { $$ = tree_cons (NULL_TREE, $2, $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: TYPESPEC + | structsp + | TYPENAME + | TYPEOF '(' expr ')' + { $$ = TREE_TYPE ($3); + if (pedantic) + warning ("ANSI C forbids `typeof'"); } + | TYPEOF '(' typename ')' + { $$ = groktypename ($3); + if (pedantic) + warning ("ANSI C forbids `typeof'"); } + ; + +/* A typespec that is a reserved word, or a type qualifier. */ + +typespecqual_reserved: TYPESPEC + | TYPE_QUAL + | structsp + ; + +initdecls: + initdcl + | initdecls ',' initdcl + ; + +notype_initdecls: + notype_initdcl + | notype_initdecls ',' initdcl + ; + +maybeasm: + /* empty */ + { $$ = NULL_TREE; } + | ASM '(' string ')' + { if (TREE_CHAIN ($3)) $3 = combine_strings ($3); + $$ = $3; + if (pedantic) + warning ("ANSI C forbids use of `asm' keyword"); + } + ; + +initdcl: + declarator maybeasm maybe_attribute '=' + { $$ = start_decl ($1, current_declspecs, 1); } + init +/* Note how the declaration of the variable is in effect while its init is parsed! */ + { finish_decl ($5, $6, $2); } + | declarator maybeasm maybe_attribute + { tree d = start_decl ($1, current_declspecs, 0); + finish_decl (d, NULL_TREE, $2); } + ; + +notype_initdcl: + notype_declarator maybeasm maybe_attribute '=' + { $$ = start_decl ($1, current_declspecs, 1); } + init +/* Note how the declaration of the variable is in effect while its init is parsed! */ + { finish_decl ($5, $6, $2); } + | notype_declarator maybeasm maybe_attribute + { tree d = start_decl ($1, current_declspecs, 0); + finish_decl (d, NULL_TREE, $2); } + ; +/* the * rules are dummies to accept the Apollo extended syntax + so that the header files compile. */ +maybe_attribute: + /* empty */ + { $$ = NULL_TREE; } + | ATTRIBUTE '(' '(' attribute_list ')' ')' + { $$ = $4; } + ; + +attribute_list + : attrib + | attribute_list ',' attrib + ; + +attrib + : IDENTIFIER + { warning ("`%s' attribute directive ignored", + IDENTIFIER_POINTER ($1)); + $$ = $1; } + | IDENTIFIER '(' CONSTANT ')' + { /* if not "aligned(1)", then issue warning */ + if (strcmp (IDENTIFIER_POINTER ($1), "aligned") != 0 + || TREE_CODE ($3) != INTEGER_CST + || TREE_INT_CST_LOW ($3) != 1) + warning ("`%s' attribute directive ignored", + IDENTIFIER_POINTER ($1)); + $$ = $1; } + | IDENTIFIER '(' identifiers ')' + { warning ("`%s' attribute directive ignored", + IDENTIFIER_POINTER ($1)); + $$ = $1; } + ; + +init: + expr_no_commas + | '{' '}' + { $$ = build_nt (CONSTRUCTOR, NULL_TREE, NULL_TREE); + if (pedantic) + warning ("ANSI C forbids empty initializer braces"); } + | '{' initlist '}' + { $$ = build_nt (CONSTRUCTOR, NULL_TREE, nreverse ($2)); } + | '{' initlist ',' '}' + { $$ = build_nt (CONSTRUCTOR, NULL_TREE, nreverse ($2)); } + | error + { $$ = NULL_TREE; } + ; + +/* This chain is built in reverse order, + and put in forward order where initlist is used. */ +initlist: + init + { $$ = build_tree_list (NULL_TREE, $1); } + | initlist ',' init + { $$ = tree_cons (NULL_TREE, $3, $1); } + ; + +/* Any kind of declarator (thus, all declarators allowed + after an explicit typespec). */ + +declarator: + after_type_declarator + | notype_declarator + ; + +/* A declarator that is allowed only after an explicit typespec. */ + +after_type_declarator: + '(' after_type_declarator ')' + { $$ = $2; } + | after_type_declarator '(' parmlist_or_identifiers %prec '.' + { $$ = build_nt (CALL_EXPR, $1, $3, NULL_TREE); } +/* | after_type_declarator '(' error ')' %prec '.' + { $$ = build_nt (CALL_EXPR, $1, NULL_TREE, NULL_TREE); + poplevel (0, 0, 0); } */ + | after_type_declarator '[' expr ']' %prec '.' + { $$ = build_nt (ARRAY_REF, $1, $3); } + | after_type_declarator '[' ']' %prec '.' + { $$ = build_nt (ARRAY_REF, $1, NULL_TREE); } + | '*' type_quals after_type_declarator %prec UNARY + { $$ = make_pointer_declarator ($2, $3); } + | TYPENAME + ; + +/* Kinds of declarator that can appear in a parameter list + in addition to notype_declarator. This is like after_type_declarator + but does not allow a typedef name in parentheses as an identifier + (because it would conflict with a function with that typedef as arg). */ + +parm_declarator: + parm_declarator '(' parmlist_or_identifiers %prec '.' + { $$ = build_nt (CALL_EXPR, $1, $3, NULL_TREE); } +/* | parm_declarator '(' error ')' %prec '.' + { $$ = build_nt (CALL_EXPR, $1, NULL_TREE, NULL_TREE); + poplevel (0, 0, 0); } */ + | parm_declarator '[' expr ']' %prec '.' + { $$ = build_nt (ARRAY_REF, $1, $3); } + | parm_declarator '[' ']' %prec '.' + { $$ = build_nt (ARRAY_REF, $1, NULL_TREE); } + | '*' type_quals parm_declarator %prec UNARY + { $$ = make_pointer_declarator ($2, $3); } + | TYPENAME + ; + +/* A declarator allowed whether or not there has been + an explicit typespec. These cannot redeclare a typedef-name. */ + +notype_declarator: + notype_declarator '(' parmlist_or_identifiers %prec '.' + { $$ = build_nt (CALL_EXPR, $1, $3, NULL_TREE); } +/* | notype_declarator '(' error ')' %prec '.' + { $$ = build_nt (CALL_EXPR, $1, NULL_TREE, NULL_TREE); + poplevel (0, 0, 0); } */ + | '(' notype_declarator ')' + { $$ = $2; } + | '*' type_quals notype_declarator %prec UNARY + { $$ = make_pointer_declarator ($2, $3); } + | notype_declarator '[' expr ']' %prec '.' + { $$ = build_nt (ARRAY_REF, $1, $3); } + | notype_declarator '[' ']' %prec '.' + { $$ = build_nt (ARRAY_REF, $1, NULL_TREE); } + | IDENTIFIER + ; + +structsp: + STRUCT identifier '{' + { $$ = start_struct (RECORD_TYPE, $2); + /* Start scope of tag before parsing components. */ + } + component_decl_list '}' + { $$ = finish_struct ($4, $5); + /* Really define the structure. */ + } + | STRUCT '{' component_decl_list '}' + { $$ = finish_struct (start_struct (RECORD_TYPE, NULL_TREE), + $3); } + | STRUCT identifier + { $$ = xref_tag (RECORD_TYPE, $2); } + | UNION identifier '{' + { $$ = start_struct (UNION_TYPE, $2); } + component_decl_list '}' + { $$ = finish_struct ($4, $5); } + | UNION '{' component_decl_list '}' + { $$ = finish_struct (start_struct (UNION_TYPE, NULL_TREE), + $3); } + | UNION identifier + { $$ = xref_tag (UNION_TYPE, $2); } + | ENUM identifier '{' + { $3 = suspend_momentary (); + $$ = start_enum ($2); } + enumlist maybecomma_warn '}' + { $$ = finish_enum ($4, nreverse ($5)); + resume_momentary ($3); } + | ENUM '{' + { $2 = suspend_momentary (); + $$ = start_enum (NULL_TREE); } + enumlist maybecomma_warn '}' + { $$ = finish_enum ($3, nreverse ($4)); + resume_momentary ($2); } + | ENUM identifier + { $$ = xref_tag (ENUMERAL_TYPE, $2); } + ; + +maybecomma: + /* empty */ + | ',' + ; + +maybecomma_warn: + /* empty */ + | ',' + { if (pedantic) warning ("comma at end of enumerator list"); } + ; + +component_decl_list: + component_decl_list2 + { $$ = $1; } + | component_decl_list2 component_decl + { $$ = chainon ($1, $2); + warning ("no semicolon at end of struct or union"); } + ; + +component_decl_list2: /* empty */ + { $$ = NULL_TREE; } + | component_decl_list2 component_decl ';' + { $$ = chainon ($1, $2); } + | component_decl_list2 ';' + { if (pedantic) + warning ("extra semicolon in struct or union specified"); } + ; + +/* There is a shift-reduce conflict here, because `components' may + start with a `typename'. It happens that shifting (the default resolution) + does the right thing, because it treats the `typename' as part of + a `typed_typespecs'. + + It is possible that this same technique would allow the distinction + between `notype_initdecls' and `initdecls' to be eliminated. + But I am being cautious and not trying it. */ + +component_decl: + typed_typespecs setspecs components + { $$ = $3; + current_declspecs = TREE_VALUE (declspec_stack); + declspec_stack = TREE_CHAIN (declspec_stack); + resume_momentary ($2); } + | nonempty_type_quals setspecs components + { $$ = $3; + current_declspecs = TREE_VALUE (declspec_stack); + declspec_stack = TREE_CHAIN (declspec_stack); + resume_momentary ($2); } + | error + { $$ = NULL_TREE; } + ; + +components: + /* empty */ + { if (pedantic) + warning ("ANSI C forbids member declarations with no members"); + $$ = NULL_TREE; } + | component_declarator + | components ',' component_declarator + { $$ = chainon ($1, $3); } + ; + +component_declarator: + declarator maybe_attribute + { $$ = grokfield (input_filename, lineno, $1, current_declspecs, NULL_TREE); } + | declarator ':' expr_no_commas maybe_attribute + { $$ = grokfield (input_filename, lineno, $1, current_declspecs, $3); } + | ':' expr_no_commas + { $$ = grokfield (input_filename, lineno, NULL_TREE, current_declspecs, $2); } + ; + +/* We chain the enumerators in reverse order. + They are put in forward order where enumlist is used. + (The order used to be significant, but no longer is so. + However, we still maintain the order, just to be clean.) */ + +enumlist: + enumerator + | enumlist ',' enumerator + { $$ = chainon ($3, $1); } + ; + + +enumerator: + identifier + { $$ = build_enumerator ($1, NULL_TREE); } + | identifier '=' expr_no_commas + { $$ = build_enumerator ($1, $3); } + ; + +typename: + typed_typespecs absdcl + { $$ = build_tree_list ($1, $2); } + | nonempty_type_quals absdcl + { $$ = build_tree_list ($1, $2); } + ; + +absdcl: /* an absolute declarator */ + /* empty */ + { $$ = NULL_TREE; } + | absdcl1 + ; + +nonempty_type_quals: + TYPE_QUAL + { $$ = tree_cons (NULL_TREE, $1, NULL_TREE); } + | nonempty_type_quals TYPE_QUAL + { $$ = tree_cons (NULL_TREE, $2, $1); } + ; + +type_quals: + /* empty */ + { $$ = NULL_TREE; } + | type_quals TYPE_QUAL + { $$ = tree_cons (NULL_TREE, $2, $1); } + ; + +absdcl1: /* a nonempty absolute declarator */ + '(' absdcl1 ')' + { $$ = $2; } + /* `(typedef)1' is `int'. */ + | '*' type_quals absdcl1 %prec UNARY + { $$ = make_pointer_declarator ($2, $3); } + | '*' type_quals %prec UNARY + { $$ = make_pointer_declarator ($2, NULL_TREE); } + | absdcl1 '(' parmlist %prec '.' + { $$ = build_nt (CALL_EXPR, $1, $3, NULL_TREE); } + | absdcl1 '[' expr ']' %prec '.' + { $$ = build_nt (ARRAY_REF, $1, $3); } + | absdcl1 '[' ']' %prec '.' + { $$ = build_nt (ARRAY_REF, $1, NULL_TREE); } + | '(' parmlist %prec '.' + { $$ = build_nt (CALL_EXPR, NULL_TREE, $2, NULL_TREE); } + | '[' expr ']' %prec '.' + { $$ = build_nt (ARRAY_REF, NULL_TREE, $2); } + | '[' ']' %prec '.' + { $$ = build_nt (ARRAY_REF, NULL_TREE, NULL_TREE); } + ; + +/* at least one statement, the first of which parses without error. */ +/* stmts is used only after decls, so an invalid first statement + is actually regarded as an invalid decl and part of the decls. */ + +stmts: + stmt + | stmts stmt + | stmts errstmt + ; + +xstmts: + /* empty */ + | stmts + ; + +errstmt: error ';' + ; + +pushlevel: /* empty */ + { pushlevel (0); + clear_last_expr (); + push_momentary (); + expand_start_bindings (0); } + ; + +/* This is the body of a function definition. + It causes syntax errors to ignore to the next openbrace. */ +compstmt_or_error: + compstmt + {} + | error compstmt + ; + +compstmt: '{' '}' + { $$ = 0; } + | '{' pushlevel decls xstmts '}' + { expand_end_bindings (getdecls (), 1, 0); + $$ = poplevel (1, 1, 0); + pop_momentary (); } + | '{' pushlevel error '}' + { expand_end_bindings (getdecls (), kept_level_p (), 0); + $$ = poplevel (kept_level_p (), 0, 0); + pop_momentary (); } + | '{' pushlevel stmts '}' + { expand_end_bindings (getdecls (), kept_level_p (), 0); + $$ = poplevel (kept_level_p (), 0, 0); + pop_momentary (); } + ; + +simple_if: + IF '(' expr ')' + { emit_line_note (input_filename, lineno); + expand_start_cond (truthvalue_conversion ($3), 0); } + stmt + ; + +stmt: + compstmt {} + | expr ';' + { emit_line_note (input_filename, lineno); + /* Do default conversion if safe and possibly important, + in case within ({...}). */ + if ((TREE_CODE (TREE_TYPE ($1)) == ARRAY_TYPE + && lvalue_p ($1)) + || TREE_CODE (TREE_TYPE ($1)) == FUNCTION_TYPE) + $1 = default_conversion ($1); + expand_expr_stmt ($1); + clear_momentary (); } + | simple_if ELSE + { expand_start_else (); } + stmt + { expand_end_else (); } + | simple_if %prec IF + { expand_end_cond (); } + | WHILE + { emit_nop (); + emit_line_note (input_filename, lineno); + expand_start_loop (1); } + '(' expr ')' + { emit_line_note (input_filename, lineno); + expand_exit_loop_if_false (truthvalue_conversion ($4)); } + stmt + { expand_end_loop (); } + | DO + { emit_nop (); + emit_line_note (input_filename, lineno); + expand_start_loop_continue_elsewhere (1); } + stmt WHILE + { expand_loop_continue_here (); } + '(' expr ')' ';' + { emit_line_note (input_filename, lineno); + expand_exit_loop_if_false (truthvalue_conversion ($7)); + expand_end_loop (); + clear_momentary (); } + | FOR + '(' xexpr ';' + { emit_nop (); + emit_line_note (input_filename, lineno); + if ($3) expand_expr_stmt ($3); + expand_start_loop_continue_elsewhere (1); } + xexpr ';' + { emit_line_note (input_filename, lineno); + if ($6) + expand_exit_loop_if_false (truthvalue_conversion ($6)); } + xexpr ')' + /* Don't let the tree nodes for $9 be discarded + by clear_momentary during the parsing of the next stmt. */ + { push_momentary (); + $10 = lineno; } + stmt + { emit_line_note (input_filename, $10); + expand_loop_continue_here (); + if ($9) + expand_expr_stmt ($9); + pop_momentary (); + expand_end_loop (); } + | SWITCH '(' expr ')' + { emit_line_note (input_filename, lineno); + c_expand_start_case ($3); + /* Don't let the tree nodes for $3 be discarded by + clear_momentary during the parsing of the next stmt. */ + push_momentary (); } + stmt + { expand_end_case ($3); + pop_momentary (); } + | CASE expr ':' + { register tree value = fold ($2); + register tree label + = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE); + + /* 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); + + if (TREE_CODE (value) != INTEGER_CST + && value != error_mark_node) + { + error ("case label does not reduce to an integer constant"); + value = error_mark_node; + } + else + /* Promote char or short to int. */ + value = default_conversion (value); + if (value != error_mark_node) + { + int success = pushcase (value, label); + if (success == 1) + error ("case label not within a switch statement"); + else if (success == 2) + error ("duplicate case value"); + else if (success == 3) + warning ("case value out of range"); + } + } + stmt + | DEFAULT ':' + { + register tree label + = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE); + int success = pushcase (NULL_TREE, label); + if (success == 1) + error ("default label not within a switch statement"); + else if (success == 2) + error ("multiple default labels in one switch"); + } + stmt + | BREAK ';' + { emit_line_note (input_filename, lineno); + if ( ! expand_exit_something ()) + error ("break statement not within loop or switch"); } + | CONTINUE ';' + { emit_line_note (input_filename, lineno); + if (! expand_continue_loop ()) + error ("continue statement not within a loop"); } + | RETURN ';' + { emit_line_note (input_filename, lineno); + c_expand_return (NULL_TREE); } + | RETURN expr ';' + { emit_line_note (input_filename, lineno); + c_expand_return ($2); } + | ASM maybe_type_qual '(' string ')' ';' + { if (TREE_CHAIN ($4)) $4 = combine_strings ($4); + emit_line_note (input_filename, lineno); + expand_asm ($4); } + /* This is the case with just output operands. */ + | ASM 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); } + /* This is the case with input operands as well. */ + | ASM 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); } + /* This is the case with clobbered registers as well. */ + | ASM maybe_type_qual '(' 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); } + | GOTO identifier ';' + { tree decl; + emit_line_note (input_filename, lineno); + decl = lookup_label ($2); + TREE_USED (decl) = 1; + expand_goto (decl); } + | identifier ':' + { tree label = define_label (input_filename, lineno, $1); + emit_nop (); + if (label) + expand_label (label); } + stmt + | ';' + ; + +/* Either a type-qualifier or nothing. First thing in an `asm' statement. */ + +maybe_type_qual: + /* empty */ + { if (pedantic) + warning ("ANSI C forbids use of `asm' keyword"); + emit_line_note (input_filename, lineno); } + | TYPE_QUAL + { if (pedantic) + warning ("ANSI C forbids use of `asm' keyword"); + emit_line_note (input_filename, lineno); } + ; + +xexpr: + /* empty */ + { $$ = NULL_TREE; } + | expr + ; + +/* 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 */ + { $$ = NULL_TREE; } + | nonnull_asm_operands + ; + +nonnull_asm_operands: + asm_operand + | nonnull_asm_operands ',' asm_operand + { $$ = chainon ($1, $3); } + ; + +asm_operand: + STRING '(' expr ')' + { $$ = build_tree_list ($1, $3); } + ; + +asm_clobbers: + string + { $$ = tree_cons (NULL_TREE, combine_strings ($1), NULL_TREE); } + | asm_clobbers ',' string + { $$ = tree_cons (NULL_TREE, combine_strings ($3), $1); } + ; + +/* This is what appears inside the parens in a function declarator. + Its value is a list of ..._TYPE nodes. */ +parmlist: + { pushlevel (0); + declare_parm_level (); } + parmlist_1 + { $$ = $2; + parmlist_tags_warning (); + poplevel (0, 0, 0); } + ; + +/* This is referred to where either a parmlist or an identifier list is ok. + Its value is a list of ..._TYPE nodes or a list of identifiers. */ +parmlist_or_identifiers: + { pushlevel (0); + declare_parm_level (); } + parmlist_or_identifiers_1 + { $$ = $2; + parmlist_tags_warning (); + poplevel (0, 0, 0); } + ; + +parmlist_or_identifiers_1: + parmlist_2 ')' + | identifiers ')' + { $$ = tree_cons (NULL_TREE, NULL_TREE, $1); } + | error ')' + { $$ = tree_cons (NULL_TREE, NULL_TREE, NULL_TREE); } + ; + +parmlist_1: + parmlist_2 ')' + | error ')' + { $$ = tree_cons (NULL_TREE, NULL_TREE, NULL_TREE); } + ; + +/* This is what appears inside the parens in a function declarator. + Is value is represented in the format that grokdeclarator expects. */ +parmlist_2: /* empty */ + { $$ = get_parm_info (0); } + | parms + { $$ = get_parm_info (1); } + | parms ',' ELLIPSIS + { $$ = get_parm_info (0); } + ; + +parms: + parm + { push_parm_decl ($1); } + | parms ',' parm + { push_parm_decl ($3); } + ; + +/* A single parameter declaration or parameter type name, + as found in a parmlist. */ +parm: + typed_declspecs parm_declarator + { $$ = build_tree_list ($1, $2) ; } + | typed_declspecs notype_declarator + { $$ = build_tree_list ($1, $2) ; } + | typed_declspecs absdcl + { $$ = build_tree_list ($1, $2); } + | declmods notype_declarator + { $$ = build_tree_list ($1, $2) ; } + | declmods absdcl + { $$ = build_tree_list ($1, $2); } + ; + +/* A nonempty list of identifiers. */ +identifiers: + IDENTIFIER + { $$ = build_tree_list (NULL_TREE, $1); } + | identifiers ',' IDENTIFIER + { $$ = chainon ($1, build_tree_list (NULL_TREE, $3)); } + ; +%% + +/* 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 + 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. */ + +static tree +make_pointer_declarator (type_quals, target) + tree type_quals, target; +{ + return build (INDIRECT_REF, type_quals, target); +} + +/* Given a chain of STRING_CST nodes, + concatenate them into one STRING_CST + and give it a suitable array-of-chars data type. */ + +static tree +combine_strings (strings) + tree strings; +{ + register tree value, t; + register int length = 1; + int wide_length = 0; + int wide_flag = 0; + int nchars; + + if (TREE_CHAIN (strings)) + { + /* More than one in the chain, so concatenate. */ + register char *p, *q; + + /* Don't include the \0 at the end of each substring, + except for the last one. + Count wide strings and ordinary strings separately. */ + for (t = strings; t; t = TREE_CHAIN (t)) + { + if (TREE_TYPE (t) == int_array_type_node) + { + wide_length += (TREE_STRING_LENGTH (t) - UNITS_PER_WORD); + wide_flag = 1; + } + else + length += (TREE_STRING_LENGTH (t) - 1); + } + + /* If anything is wide, the non-wides will be converted, + which makes them take more space. */ + if (wide_flag) + length = length * UNITS_PER_WORD + wide_length; + + p = (char *) savealloc (length); + + /* Copy the individual strings into the new combined string. + If the combined string is wide, convert the chars to ints + for any individual strings that are not wide. */ + + q = p; + for (t = strings; t; t = TREE_CHAIN (t)) + { + int len = (TREE_STRING_LENGTH (t) + - ((TREE_TYPE (t) == int_array_type_node) + ? UNITS_PER_WORD : 1)); + if ((TREE_TYPE (t) == int_array_type_node) == wide_flag) + { + bcopy (TREE_STRING_POINTER (t), q, len); + q += len; + } + else + { + int i; + for (i = 0; i < len; i++) + ((int *) q)[i] = TREE_STRING_POINTER (t)[i]; + q += len * UNITS_PER_WORD; + } + } + if (wide_flag) + { + int i; + for (i = 0; i < UNITS_PER_WORD; i++) + *q++ = 0; + } + else + *q = 0; + + value = make_node (STRING_CST); + TREE_STRING_POINTER (value) = p; + TREE_STRING_LENGTH (value) = length; + TREE_LITERAL (value) = 1; + } + else + { + value = strings; + length = TREE_STRING_LENGTH (value); + if (TREE_TYPE (value) == int_array_type_node) + wide_flag = 1; + } + + /* Compute the number of elements, for the array type. */ + nchars = wide_flag ? length / UNITS_PER_WORD : length; + + /* Create the array type for the string constant. + -Wwrite-strings says make the string constant an array of const char + so that copying it to a non-const pointer will get a warning. */ + if (warn_write_strings) + { + tree elements + = build_type_variant (wide_flag ? integer_type_node : char_type_node, + 1, 0); + TREE_TYPE (value) + = build_array_type (elements, + build_index_type (build_int_2 (nchars - 1, 0))); + } + else + TREE_TYPE (value) + = build_array_type (wide_flag ? integer_type_node : char_type_node, + build_index_type (build_int_2 (nchars - 1, 0))); + TREE_LITERAL (value) = 1; + TREE_STATIC (value) = 1; + return value; +} + +FILE *finput; /* input file. + Normally a pipe from the preprocessor. */ + +/* lexical analyzer */ + +static int maxtoken; /* Current nominal length of token buffer. */ +static char *token_buffer; /* Pointer to token buffer. + Actual allocated length is maxtoken + 2. */ +static int max_wide; /* Current nominal length of wide_buffer. */ +static int *wide_buffer; /* Pointer to wide-string buffer. + Actual allocated length is max_wide + 1. */ + +/* Nonzero if end-of-file has been seen on input. */ +static int end_of_file; + +/* Data type that represents the GNU C reserved words. */ +struct resword { char *name; short token; enum rid rid; }; + +#define MIN_WORD_LENGTH 2 /* minimum size for C keyword */ +#define MAX_WORD_LENGTH 13 /* maximum size for C keyword */ +#define MIN_HASH_VALUE 7 /* range of the hash keys values */ +#define MAX_HASH_VALUE 91 /* for the perfect hash generator */ +#define NORID RID_UNUSED + +/* This function performs the minimum-perfect hash mapping from input + string to reswords table index. It only looks at the first and + last characters in the string, thus assuring the O(1) lookup time + (this keeps our constant down to an insignificant amount!). Compiling + the following 2 functions as inline removes all overhead of the + function calls. */ + +#ifdef __GNUC__ +__inline +#endif +static int +hash (str, len) + register char *str; + register int len; +{ +/* This table is used to build the hash table index that recognizes + reserved words in 0(1) steps. It is larger than strictly necessary, + but I'm trading off the space for the time-saving luxury of avoiding + subtraction of an offset. All those ``91's'' (actually just a + short-hand for MAX_HASH_VALUE #defined above) are used to speed up + the search when the string found on the input stream doesn't have a + first or last character that is part of the set of alphabetic + characters that comprise the first or last characters in C + reserved words. */ + + static int hash_table[] = + { + 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, + 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, + 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, + 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, + 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, + 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, + 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, + 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, + 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, + 91, 91, 91, 91, 91, 1, 91, 2, 1, 32, + 7, 5, 18, 20, 1, 17, 91, 1, 18, 1, + 28, 1, 23, 91, 12, 20, 1, 41, 7, 15, + 91, 91, 10, 91, 91, 91, 91, 91, + }; + register int hval = len ; + + switch (hval) + { + default: + case 3: + hval += hash_table[str[2]]; + case 2: + case 1: + return hval + hash_table[str[0]] + hash_table[str[len - 1]]; + } +} + +/* This routine attempts to match the string found in the reswords table + with the one from the input stream. If all the relevant details + match then an actual strcmp comparison is performed and the address of + correct struct resword entry is returned. Otherwise, a NULL + pointer is returned. */ + +#ifdef __GNUC__ +__inline +#endif +struct resword * +is_reserved_word (str, len) + register char *str; + register int len; +{ + /* This is the hash table of keywords. + The order of keywords has been chosen for perfect hashing. + Therefore, this table cannot be updated by hand. + Use the program ``gperf,'' available with the latest libg++ + distribution, to generate an updated table. A file called + c-parse.gperf, distributed with GNU C, contains the keyword file. */ + + static struct resword reswords[] = + { + { "", }, { "", }, { "", }, { "", }, { "", }, { "", }, { "", }, + {"asm", ASM, NORID }, + {"auto", SCSPEC, RID_AUTO }, + {"__asm", ASM, NORID }, + {"do", DO, NORID }, + {"__asm__", ASM, NORID }, + {"break", BREAK, NORID }, + {"__typeof__", TYPEOF, NORID }, + { "", }, + {"__alignof__", ALIGNOF, NORID }, + { "", }, + {"__attribute__", ATTRIBUTE, NORID }, + { "", }, + {"__attribute", ATTRIBUTE, NORID }, + { "", }, + {"__volatile__", TYPE_QUAL, RID_VOLATILE }, + {"int", TYPESPEC, RID_INT }, + {"__volatile", TYPE_QUAL, RID_VOLATILE }, + { "", }, + {"float", TYPESPEC, RID_FLOAT }, + {"goto", GOTO, NORID }, + {"short", TYPESPEC, RID_SHORT }, + {"__typeof", TYPEOF, NORID }, + {"__inline__", SCSPEC, RID_INLINE }, + {"__alignof", ALIGNOF, NORID }, + {"__inline", SCSPEC, RID_INLINE }, + {"__signed__", TYPESPEC, RID_SIGNED }, + {"default", DEFAULT, NORID }, + {"else", ELSE, NORID }, + {"void", TYPESPEC, RID_VOID }, + {"__signed", TYPESPEC, RID_SIGNED }, + {"if", IF, NORID }, + {"volatile", TYPE_QUAL, RID_VOLATILE }, + {"struct", STRUCT, NORID }, + {"extern", SCSPEC, RID_EXTERN }, + {"__const", TYPE_QUAL, RID_CONST }, + {"while", WHILE, NORID }, + {"__const__", TYPE_QUAL, RID_CONST }, + {"switch", SWITCH, NORID }, + {"for", FOR, NORID }, + {"inline", SCSPEC, RID_INLINE }, + {"return", RETURN, NORID }, + {"typeof", TYPEOF, NORID }, + {"typedef", SCSPEC, RID_TYPEDEF }, + {"char", TYPESPEC, RID_CHAR }, + {"enum", ENUM, NORID }, + {"register", SCSPEC, RID_REGISTER }, + {"signed", TYPESPEC, RID_SIGNED }, + {"sizeof", SIZEOF, NORID }, + { "", }, { "", }, { "", }, { "", }, + {"double", TYPESPEC, RID_DOUBLE }, + {"static", SCSPEC, RID_STATIC }, + {"case", CASE, NORID }, + { "", }, { "", }, { "", }, { "", }, + {"const", TYPE_QUAL, RID_CONST }, + { "", }, { "", }, { "", }, + {"long", TYPESPEC, RID_LONG }, + { "", }, { "", }, + {"continue", CONTINUE, NORID }, + { "", }, { "", }, + {"unsigned", TYPESPEC, RID_UNSIGNED }, + { "", }, { "", }, { "", }, { "", }, { "", }, { "", }, { "", }, { "", }, { "", }, + { "", }, { "", }, { "", }, { "", }, { "", }, + {"union", UNION, NORID }, + }; + + if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH) + { + register int key = hash (str, len); + + if (key <= MAX_HASH_VALUE) + { + register char *s = reswords[key].name; + + if (*s == *str && !strcmp (str + 1, s + 1)) + return &reswords[key]; + } + } + return 0; +} + +/* The elements of `ridpointers' are identifier nodes + for the reserved type names and storage classes. + It is indexed by a RID_... value. */ + +tree ridpointers[(int) RID_MAX]; + +int check_newline (); + +void +init_lex () +{ + /* Start it at 0, because check_newline is called at the very beginning + and will increment it to 1. */ + lineno = 0; + + maxtoken = 40; + token_buffer = (char *) xmalloc (maxtoken + 2); + max_wide = 40; + wide_buffer = (int *) xmalloc ((max_wide + 1) * UNITS_PER_WORD); + + ridpointers[(int) RID_INT] = get_identifier ("int"); + ridpointers[(int) RID_CHAR] = get_identifier ("char"); + ridpointers[(int) RID_VOID] = get_identifier ("void"); + ridpointers[(int) RID_FLOAT] = get_identifier ("float"); + ridpointers[(int) RID_DOUBLE] = get_identifier ("double"); + ridpointers[(int) RID_SHORT] = get_identifier ("short"); + ridpointers[(int) RID_LONG] = get_identifier ("long"); + ridpointers[(int) RID_UNSIGNED] = get_identifier ("unsigned"); + ridpointers[(int) RID_SIGNED] = get_identifier ("signed"); + ridpointers[(int) RID_INLINE] = get_identifier ("inline"); + ridpointers[(int) RID_CONST] = get_identifier ("const"); + ridpointers[(int) RID_VOLATILE] = get_identifier ("volatile"); + ridpointers[(int) RID_AUTO] = get_identifier ("auto"); + ridpointers[(int) RID_STATIC] = get_identifier ("static"); + ridpointers[(int) RID_EXTERN] = get_identifier ("extern"); + ridpointers[(int) RID_TYPEDEF] = get_identifier ("typedef"); + ridpointers[(int) RID_REGISTER] = get_identifier ("register"); +} + +static void +reinit_parse_for_function () +{ +} + +/* If C is not whitespace, return C. + Otherwise skip whitespace and return first nonwhite char read. */ + +static int +skip_white_space (c) + register int c; +{ +#if 0 + register int inside; +#endif + + for (;;) + { + switch (c) + { + /* Don't recognize comments in cc1: all comments are removed by cpp, + and cpp output can include / and * consecutively as operators. */ +#if 0 + case '/': + c = getc (finput); + if (c != '*') + { + ungetc (c, finput); + return '/'; + } + + c = getc (finput); + + inside = 1; + while (inside) + { + if (c == '*') + { + while (c == '*') + c = getc (finput); + + if (c == '/') + { + inside = 0; + c = getc (finput); + } + } + else if (c == '\n') + { + lineno++; + c = getc (finput); + } + else if (c == EOF) + { + error ("unterminated comment"); + break; + } + else + c = getc (finput); + } + + break; +#endif + + case '\n': + c = check_newline (); + break; + + case ' ': + case '\t': + case '\f': + case '\r': + case '\v': + case '\b': + c = getc (finput); + break; + + case '\\': + c = getc (finput); + if (c == '\n') + lineno++; + else + error ("stray '\\' in program"); + c = getc (finput); + break; + + default: + return (c); + } + } +} + + + +/* Make the token buffer longer, preserving the data in it. + P should point to just beyond the last valid character in the old buffer. + The value we return is a pointer to the new buffer + at a place corresponding to P. */ + +static char * +extend_token_buffer (p) + char *p; +{ + int offset = p - token_buffer; + + maxtoken = maxtoken * 2 + 10; + token_buffer = (char *) xrealloc (token_buffer, maxtoken + 2); + + return token_buffer + offset; +} + +/* At the beginning of a line, increment the line number + and process any #-directive on this line. + If the line is a #-directive, read the entire line and return a newline. + Otherwise, return the line's first non-whitespace character. */ + +int +check_newline () +{ + register int c; + register int token; + + lineno++; + + /* Read first nonwhite char on the line. */ + + c = getc (finput); + while (c == ' ' || c == '\t') + c = getc (finput); + + if (c != '#') + { + /* If not #, return it so caller will use it. */ + return c; + } + + /* Read first nonwhite char after the `#'. */ + + c = getc (finput); + while (c == ' ' || c == '\t') + c = 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'. */ + + 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')) + 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')) + { + extern FILE *asm_out_file; + + if (pedantic) + error ("ANSI C does not allow #ident"); + + /* 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') + return c; + + ungetc (c, finput); + token = yylex (); + if (token != STRING + || TREE_CODE (yylval.ttype) != STRING_CST) + { + error ("invalid #ident"); + goto skipline; + } + +#ifdef ASM_OUTPUT_IDENT + ASM_OUTPUT_IDENT (asm_out_file, TREE_STRING_POINTER (yylval.ttype)); +#endif + + /* Skip the rest of this line. */ + goto skipline; + } + } + + error ("undefined or invalid # directive"); + goto skipline; + } + +linenum: + /* Here we have either `#line' or `# '. + In either case, it should be a line number; a digit should follow. */ + + while (c == ' ' || c == '\t') + c = getc (finput); + + /* If the # is the only nonwhite char on the line, + just ignore it. Check the new newline. */ + if (c == '\n') + return c; + + /* Something follows the #; read a token. */ + + ungetc (c, finput); + token = yylex (); + + if (token == CONSTANT + && TREE_CODE (yylval.ttype) == INTEGER_CST) + { + int old_lineno = lineno; + /* subtract one, because it is the following line that + gets the specified number */ + + 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); + if (c == '\n') + { + /* No more: store the line number and check following line. */ + lineno = l; + return c; + } + ungetc (c, finput); + + /* More follows: it must be a string constant (filename). */ + + token = yylex (); + if (token != STRING || TREE_CODE (yylval.ttype) != STRING_CST) + { + error ("invalid #line"); + goto skipline; + } + + input_filename + = (char *) permalloc (TREE_STRING_LENGTH (yylval.ttype) + 1); + strcpy (input_filename, TREE_STRING_POINTER (yylval.ttype)); + lineno = l; + + if (main_input_filename == 0) + main_input_filename = input_filename; + + /* Is this the last nonwhite stuff on the line? */ + c = getc (finput); + while (c == ' ' || c == '\t') + c = getc (finput); + if (c == '\n') + return c; + ungetc (c, finput); + + token = yylex (); + + /* `1' after file name means entering new file. + `2' after file name means just left a file. */ + + if (token == CONSTANT + && TREE_CODE (yylval.ttype) == INTEGER_CST) + { + if (TREE_INT_CST_LOW (yylval.ttype) == 1) + { + 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++; + } + else if (input_file_stack->next) + { + struct file_stack *p = input_file_stack; + input_file_stack = p->next; + free (p); + input_file_stack_tick++; + } + else + error ("#-lines for entering and leaving files don't match"); + } + } + else + error ("invalid #-line"); + + /* skip the rest of this line. */ + skipline: + if (c == '\n') + return c; + while ((c = getc (finput)) != EOF && c != '\n'); + return c; +} + +#define isalnum(char) ((char >= 'a' && char <= 'z') || (char >= 'A' && char <= 'Z') || (char >= '0' && char <= '9')) +#define isdigit(char) (char >= '0' && char <= '9') +#define ENDFILE -1 /* token that represents end-of-file */ + + +static int +readescape () +{ + register int c = getc (finput); + register int count, code; + int firstdig; + + switch (c) + { + case 'x': + code = 0; + count = 0; + while (1) + { + c = getc (finput); + if (!(c >= 'a' && c <= 'f') + && !(c >= 'A' && c <= 'F') + && !(c >= '0' && c <= '9')) + { + ungetc (c, finput); + 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 (count == 0) + firstdig = code; + count++; + } + if (count == 0) + error ("\\x used with no following hex digits"); + else if ((count - 1) * 4 >= TYPE_PRECISION (integer_type_node) + || (count > 1 + && ((1 << (TYPE_PRECISION (integer_type_node) - (count - 1) * 4)) + <= firstdig))) + warning ("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); + } + ungetc (c, finput); + return code; + + case '\\': case '\'': case '"': + return c; + + case '\n': + lineno++; + return -1; + + 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': + return TARGET_BELL; + + case 'v': + return TARGET_VT; + + case 'E': + return 033; + + case '?': + /* `\(', etc, are used at beginning of line to avoid confusing Emacs. */ + case '(': + case '{': + case '[': + return c; + } + if (c >= 040 && c <= 0177) + warning ("unknown escape sequence `\\%c'", c); + else + warning ("unknown escape sequence: `\\' followed by char code 0x%x", c); + return c; +} + +void +yyerror (string) + char *string; +{ + char buf[200]; + + strcpy (buf, string); + + /* We can't print string and character constants well + because the token_buffer contains the result of processing escapes. */ + if (end_of_file) + strcat (buf, " at end of input"); + else if (token_buffer[0] == 0) + strcat (buf, " at null character"); + else if (token_buffer[0] == '"') + strcat (buf, " before string constant"); + else if (token_buffer[0] == '\'') + strcat (buf, " before character constant"); + else if (token_buffer[0] < 040 || token_buffer[0] >= 0177) + sprintf (buf + strlen (buf), " before character 0%o", token_buffer[0]); + else + strcat (buf, " before `%s'"); + + error (buf, token_buffer); +} + +static int nextchar = -1; + +static int +yylex () +{ + register int c; + register char *p; + register int value; + int wide_flag = 0; + + if (nextchar >= 0) + c = nextchar, nextchar = -1; + else + c = getc (finput); + + /* Effectively do c = skip_white_space (c) + but do it faster in the usual cases. */ + while (1) + switch (c) + { + case ' ': + case '\t': + case '\f': + case '\r': + case '\v': + case '\b': + c = getc (finput); + break; + + case '\n': + case '/': + case '\\': + c = skip_white_space (c); + default: + goto found_nonwhite; + } + found_nonwhite: + + token_buffer[0] = c; + token_buffer[1] = 0; + +/* yylloc.first_line = lineno; */ + + switch (c) + { + case EOF: + end_of_file = 1; + token_buffer[0] = 0; + 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); + if (c == '\'') + { + wide_flag = 1; + goto char_constant; + } + if (c == '"') + { + wide_flag = 1; + goto string_constant; + } + ungetc (c, finput); + } + + case 'A': case 'B': case 'C': case 'D': case 'E': + 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 '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': + case '_': + letter: + p = token_buffer; + while (isalnum (c) || c == '_' || c == '$') + { + if (p >= token_buffer + maxtoken) + p = extend_token_buffer (p); + if (c == '$' && ! dollars_in_ident) + break; + + *p++ = c; + c = getc (finput); + } + + *p = 0; + nextchar = c; + + value = IDENTIFIER; + yylval.itype = 0; + + /* Try to recognize a keyword. Uses minimum-perfect hash function */ + + { + register struct resword *ptr; + + if (ptr = is_reserved_word (token_buffer, p - token_buffer)) + { + if (ptr->rid) + yylval.ttype = ridpointers[(int) ptr->rid]; + if ((! flag_no_asm + /* -fno-asm means don't recognize the non-ANSI keywords. */ + || ((int) ptr->token != ASM + && (int) ptr->token != TYPEOF + && ptr->rid != RID_INLINE) + /* Recognize __asm and __inline despite -fno-asm. */ + || token_buffer[0] == '_') + /* -ftraditional means don't recognize nontraditional keywords + typeof, const, volatile, signed or inline. */ + && (! flag_traditional + || ((int) ptr->token != TYPE_QUAL + && (int) ptr->token != TYPEOF + && ptr->rid != RID_SIGNED + && ptr->rid != RID_INLINE) + /* Recognize __inline, etc. despite -ftraditional. */ + || token_buffer[0] == '_')) + value = (int) ptr->token; + } + } + + /* If we did not find a keyword, look for an identifier + (or a typename). */ + + if (value == IDENTIFIER) + { + yylval.ttype = get_identifier (token_buffer); + lastiddecl = lookup_name (yylval.ttype); + + if (lastiddecl != 0 && TREE_CODE (lastiddecl) == TYPE_DECL) + value = TYPENAME; + } + + break; + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + case '.': + { + int base = 10; + int count = 0; + int largest_digit = 0; + int numdigits = 0; + /* for multi-precision arithmetic, + we store only 8 live bits in each short, + giving us 64 bits of reliable precision */ + short shorts[8]; + int overflow = 0; + + enum anon1 { NOT_FLOAT, AFTER_POINT, TOO_MANY_POINTS} floatflag + = NOT_FLOAT; + + for (count = 0; count < 8; count++) + shorts[count] = 0; + + p = token_buffer; + *p++ = c; + + if (c == '0') + { + *p++ = (c = getc (finput)); + if ((c == 'x') || (c == 'X')) + { + base = 16; + *p++ = (c = getc (finput)); + } + else + { + base = 8; + numdigits++; + } + } + + /* Read all the digits-and-decimal-points. */ + + while (c == '.' + || (isalnum (c) && (c != 'l') && (c != 'L') + && (c != 'u') && (c != 'U') + && (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) + { + error ("malformed floating constant"); + floatflag = TOO_MANY_POINTS; + } + else + floatflag = AFTER_POINT; + + base = 10; + *p++ = c = getc (finput); + /* 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 (c == '.') + { + c = getc (finput); + if (c == '.') + { + *p++ = c; + *p = 0; + return ELLIPSIS; + } + error ("parse error at `..'"); + } + ungetc (c, finput); + token_buffer[1] = 0; + value = '.'; + goto done; + } + } + else + { + /* It is not a decimal point. + It should be a digit (perhaps a hex digit). */ + + if (isdigit (c)) + { + c = c - '0'; + } + else if (base <= 10) + { + if ((c&~040) == 'E') + { + base = 10; + floatflag = AFTER_POINT; + break; /* start of exponent */ + } + error ("nondigits in number and not hexadecimal"); + c = 0; + } + else if (c >= 'a') + { + c = c - 'a' + 10; + } + else + { + c = c - 'A' + 10; + } + if (c >= largest_digit) + largest_digit = c; + numdigits++; + + for (count = 0; count < 8; count++) + { + shorts[count] *= base; + if (count) + { + shorts[count] += (shorts[count-1] >> 8); + shorts[count-1] &= (1<<8)-1; + } + else shorts[0] += c; + } + + if (shorts[7] >= 1<<8 + || shorts[7] < - (1 << 8)) + overflow = TRUE; + + if (p >= token_buffer + maxtoken - 3) + p = extend_token_buffer (p); + *p++ = (c = getc (finput)); + } + } + + if (numdigits == 0) + error ("numeric constant with no digits"); + + if (largest_digit >= base) + error ("numeric constant contains digits beyond the radix"); + + /* Remove terminating char from the token buffer and delimit the string */ + *--p = 0; + + if (floatflag != NOT_FLOAT) + { + tree type = double_type_node; + char f_seen = 0; + char l_seen = 0; + REAL_VALUE_TYPE value; + + /* Read explicit exponent if any, and put it in tokenbuf. */ + + if ((c == 'e') || (c == 'E')) + { + if (p >= token_buffer + maxtoken - 3) + p = extend_token_buffer (p); + *p++ = c; + c = getc (finput); + if ((c == '+') || (c == '-')) + { + *p++ = c; + c = getc (finput); + } + if (! isdigit (c)) + error ("floating constant exponent has no digits"); + while (isdigit (c)) + { + if (p >= token_buffer + maxtoken - 3) + p = extend_token_buffer (p); + *p++ = c; + c = getc (finput); + } + } + + *p = 0; + errno = 0; + value = REAL_VALUE_ATOF (token_buffer); +#ifdef ERANGE + if (errno == ERANGE && !flag_traditional) + { + char *p1 = token_buffer; + /* Check for "0.0" and variants; + Sunos 4 spuriously returns ERANGE for them. */ + while (*p1 == '0') p1++; + if (*p1 == '.') + { + p1++; + while (*p1 == '0') p1++; + } + if (*p1 == 'e' || *p1 == 'E') + { + /* with significand==0, ignore the exponent */ + p1++; + while (*p1 != 0) p1++; + } + /* ERANGE is also reported for underflow, + so test the value to distinguish overflow from that. */ + if (*p1 != 0 && (value > 1.0 || value < -1.0)) + warning ("floating point number exceeds range of `double'"); + } +#endif + + /* Read the suffixes to choose a data type. */ + while (1) + { + if (c == 'f' || c == 'F') + { + float floater; + if (f_seen) + error ("two `f's in floating constant"); + f_seen = 1; + type = float_type_node; + floater = value; + value = floater; + } + else if (c == 'l' || c == 'L') + { + if (l_seen) + error ("two `l's in floating constant"); + l_seen = 1; + type = long_double_type_node; + } + else + { + 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 = getc (finput); + } + } + break; + } + if (p >= token_buffer + maxtoken - 3) + p = extend_token_buffer (p); + *p++ = c; + c = getc (finput); + } + + /* Create a node with determined type and value. */ + yylval.ttype = build_real (type, value); + + ungetc (c, finput); + *p = 0; + } + else + { + tree type; + int spec_unsigned = 0; + int spec_long = 0; + int spec_long_long = 0; + + while (1) + { + if (c == 'u' || c == 'U') + { + if (spec_unsigned) + error ("two `u's in integer constant"); + spec_unsigned = 1; + } + else if (c == 'l' || c == 'L') + { + if (spec_long) + { + if (spec_long_long) + error ("three `l's in integer constant"); + else if (pedantic) + warning ("ANSI C forbids long long integer constants"); + spec_long_long = 1; + } + spec_long = 1; + } + else + { + 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 = getc (finput); + } + } + break; + } + if (p >= token_buffer + maxtoken - 3) + p = extend_token_buffer (p); + *p++ = c; + c = getc (finput); + } + + ungetc (c, finput); + + if ((overflow || shorts[7] || shorts[6] || shorts[5] || shorts[4]) + && !spec_long_long) + warning ("integer constant out of range"); + + /* If it won't fit in a signed long long, make it unsigned. + We can't distinguish based on the tree node because + any integer constant fits any long long type. */ + if (shorts[7] >= (1<<8)) + spec_unsigned = 1; + + /* This is simplified by the fact that our constant + is always positive. */ + yylval.ttype + = (build_int_2 + ((shorts[3]<<24) + (shorts[2]<<16) + (shorts[1]<<8) + shorts[0], + (spec_long_long + ? (shorts[7]<<24) + (shorts[6]<<16) + (shorts[5]<<8) + shorts[4] + : 0))); + + if (!spec_long && !spec_unsigned + && int_fits_type_p (yylval.ttype, integer_type_node)) + type = integer_type_node; + + else if (!spec_long && (base != 10 || spec_unsigned) + && int_fits_type_p (yylval.ttype, unsigned_type_node)) + 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)) + type = long_unsigned_type_node; + + else if (! spec_unsigned + && int_fits_type_p (yylval.ttype, + long_long_integer_type_node)) + type = long_long_integer_type_node; + + else if (int_fits_type_p (yylval.ttype, + long_long_unsigned_type_node)) + type = long_long_unsigned_type_node; + + else + { + type = long_long_integer_type_node; + warning ("integer constant out of range"); + } + + TREE_TYPE (yylval.ttype) = type; + *p = 0; + } + + value = CONSTANT; break; + } + + case '\'': + char_constant: + { + register int result = 0; + register num_chars = 0; + int width = TYPE_PRECISION (char_type_node); + int max_chars; + + if (wide_flag) width = TYPE_PRECISION (integer_type_node); + + max_chars = TYPE_PRECISION (integer_type_node) / width; + + while (1) + { + tryagain: + + c = getc (finput); + + if (c == '\'' || c == EOF) + break; + + if (c == '\\') + { + c = readescape (); + if (c < 0) + goto tryagain; + if (width < HOST_BITS_PER_INT + && (unsigned) c >= (1 << width)) + warning ("escape sequence out of range for character"); + } + else if (c == '\n') + { + if (pedantic) + warning ("ANSI C forbids newline in character constant"); + lineno++; + } + + num_chars++; + if (num_chars > maxtoken - 4) + extend_token_buffer (token_buffer); + + token_buffer[num_chars] = c; + + /* Merge character into result; ignore excess chars. */ + if (num_chars < max_chars + 1) + { + if (width < HOST_BITS_PER_INT) + result = (result << width) | (c & ((1 << width) - 1)); + else + result = c; + } + } + + token_buffer[num_chars + 1] = '\''; + token_buffer[num_chars + 2] = 0; + + if (c != '\'') + error ("malformatted character constant"); + else if (num_chars == 0) + error ("empty character constant"); + else if (num_chars > max_chars) + { + num_chars = max_chars; + error ("character constant too long"); + } + else if (num_chars != 1 && ! flag_traditional) + warning ("multi-character character constant"); + + /* If char type is signed, sign-extend the constant. */ + if (! wide_flag) + { + int num_bits = num_chars * width; + if (TREE_UNSIGNED (char_type_node) + || ((result >> (num_bits - 1)) & 1) == 0) + yylval.ttype + = build_int_2 (result & ((unsigned) ~0 + >> (HOST_BITS_PER_INT - num_bits)), + 0); + else + yylval.ttype + = build_int_2 (result | ~((unsigned) ~0 + >> (HOST_BITS_PER_INT - num_bits)), + -1); + } + else + yylval.ttype = build_int_2 (result, 0); + + TREE_TYPE (yylval.ttype) = integer_type_node; + value = CONSTANT; break; + } + + case '"': + string_constant: + { + int *widep; + + c = getc (finput); + p = token_buffer + 1; + + if (wide_flag) + widep = wide_buffer; + + while (c != '"' && c >= 0) + { + if (c == '\\') + { + c = readescape (); + if (c < 0) + goto skipnewline; + if (!wide_flag && c >= (1 << TYPE_PRECISION (char_type_node))) + warning ("escape sequence out of range for character"); + } + else if (c == '\n') + { + if (pedantic) + warning ("ANSI C forbids newline in string constant"); + lineno++; + } + + /* Store the char in C into the appropriate buffer. */ + + if (wide_flag) + { + if (widep == wide_buffer + max_wide) + { + int n = widep - wide_buffer; + max_wide *= 2; + wide_buffer + = (int *) xrealloc (wide_buffer, + (max_wide + 1) * UNITS_PER_WORD); + widep = wide_buffer + n; + } + *widep++ = c; + } + else + { + if (p == token_buffer + maxtoken) + p = extend_token_buffer (p); + *p++ = c; + } + + skipnewline: + c = getc (finput); + } + + /* We have read the entire constant. + Construct a STRING_CST for the result. */ + + if (wide_flag) + { + /* If this is a L"..." wide-string, make a vector + of the ints in wide_buffer. */ + *widep = 0; + /* We have not implemented the case where `int' + on the target and on the execution machine differ in size. */ + if (TYPE_PRECISION (integer_type_node) + != sizeof (int) * BITS_PER_UNIT) + abort (); + yylval.ttype + = build_string ((widep - wide_buffer + 1) * sizeof (int), + wide_buffer); + TREE_TYPE (yylval.ttype) = int_array_type_node; + } + else + { + *p = 0; + yylval.ttype = build_string (p - token_buffer, token_buffer + 1); + TREE_TYPE (yylval.ttype) = char_array_type_node; + } + + *p++ = '"'; + *p = 0; + + value = STRING; break; + } + + case '+': + case '-': + case '&': + case '|': + case '<': + case '>': + case '*': + case '/': + case '%': + case '^': + case '!': + case '=': + { + register int c1; + + combine: + + switch (c) + { + case '+': + yylval.code = PLUS_EXPR; break; + case '-': + yylval.code = MINUS_EXPR; break; + case '&': + yylval.code = BIT_AND_EXPR; break; + case '|': + yylval.code = BIT_IOR_EXPR; break; + case '*': + yylval.code = MULT_EXPR; break; + case '/': + yylval.code = TRUNC_DIV_EXPR; break; + case '%': + yylval.code = TRUNC_MOD_EXPR; break; + case '^': + yylval.code = BIT_XOR_EXPR; break; + case LSHIFT: + yylval.code = LSHIFT_EXPR; break; + case RSHIFT: + yylval.code = RSHIFT_EXPR; break; + case '<': + yylval.code = LT_EXPR; break; + case '>': + yylval.code = GT_EXPR; break; + } + + token_buffer[1] = c1 = getc (finput); + token_buffer[2] = 0; + + if (c1 == '=') + { + switch (c) + { + case '<': + value = ARITHCOMPARE; yylval.code = LE_EXPR; goto done; + case '>': + value = ARITHCOMPARE; yylval.code = GE_EXPR; goto done; + case '!': + value = EQCOMPARE; yylval.code = NE_EXPR; goto done; + case '=': + value = EQCOMPARE; yylval.code = EQ_EXPR; goto done; + } + value = ASSIGN; goto done; + } + else if (c == c1) + switch (c) + { + case '+': + value = PLUSPLUS; goto done; + case '-': + value = MINUSMINUS; goto done; + case '&': + value = ANDAND; goto done; + case '|': + value = OROR; goto done; + case '<': + c = LSHIFT; + goto combine; + case '>': + c = RSHIFT; + goto combine; + } + else if ((c == '-') && (c1 == '>')) + { value = POINTSAT; goto done; } + ungetc (c1, finput); + token_buffer[1] = 0; + + if ((c == '<') || (c == '>')) + value = ARITHCOMPARE; + else value = c; + goto done; + } + + case 0: + /* Don't make yyparse think this is eof. */ + value = 1; + break; + + default: + value = c; + } + +done: +/* yylloc.last_line = lineno; */ + + return value; +} diff --git a/gcc-1.40/c-tree.h b/gcc-1.40/c-tree.h new file mode 100644 index 0000000..49def44 --- /dev/null +++ b/gcc-1.40/c-tree.h @@ -0,0 +1,154 @@ +/* Definitions for C parsing and type checking. + Copyright (C) 1987 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 1, 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. */ + +/* Language-dependent contents of an identifier. */ + +struct lang_identifier +{ + struct tree_identifier ignore; + tree global_value, local_value, label_value, implicit_decl; + tree error_locus; +}; + +/* Macros for access to language-specific slots in an identifier. */ + +#define IDENTIFIER_GLOBAL_VALUE(NODE) \ + (((struct lang_identifier *)(NODE))->global_value) +#define IDENTIFIER_LOCAL_VALUE(NODE) \ + (((struct lang_identifier *)(NODE))->local_value) +#define IDENTIFIER_LABEL_VALUE(NODE) \ + (((struct lang_identifier *)(NODE))->label_value) +#define IDENTIFIER_IMPLICIT_DECL(NODE) \ + (((struct lang_identifier *)(NODE))->implicit_decl) +#define IDENTIFIER_ERROR_LOCUS(NODE) \ + (((struct lang_identifier *)(NODE))->error_locus) + +/* Nonzero means reject anything that ANSI standard C forbids. */ +extern int pedantic; + +/* In a RECORD_TYPE or UNION_TYPE, nonzero if any component is read-only. */ +#define C_TYPE_FIELDS_READONLY(type) TYPE_SEP_UNIT (type) + +/* in c-typecheck.c */ +extern tree build_component_ref(), build_conditional_expr(), build_compound_expr(); +extern tree build_unary_op(), build_binary_op(), build_function_call(); +extern tree build_binary_op_nodefault (); +extern tree build_indirect_ref(), build_array_ref(), build_c_cast(); +extern tree build_modify_expr(); +extern tree c_sizeof (), c_alignof (); +extern void store_init_value (); +extern tree digest_init (); +extern tree c_expand_start_case (); +extern tree default_conversion (); + +/* Given two integer or real types, return the type for their sum. + Given two compatible ANSI C types, returns the merged type. */ + +extern tree commontype (); + +/* in c-decl.c */ +extern tree build_label (); + +extern int start_function (); +extern void finish_function (); +extern void store_parm_decls (); +extern tree get_parm_info (); + +extern void pushlevel (); +extern tree poplevel (); + +extern tree groktypename(), lookup_name(); + +extern tree lookup_label(), define_label(); + +extern tree implicitly_declare(), getdecls(), gettags (); + +extern tree start_decl(); +extern void finish_decl(); + +extern tree start_struct(), finish_struct(), xref_tag(); +extern tree grokfield(); + +extern tree start_enum(), finish_enum(); +extern tree build_enumerator(); + +extern tree make_index_type (); + +/* Add qualifiers to a type, in the fashion for C. */ +extern tree c_build_type_variant (); + +extern tree double_type_node, long_double_type_node, float_type_node; +extern tree char_type_node, unsigned_char_type_node, signed_char_type_node; + +extern tree short_integer_type_node, short_unsigned_type_node; +extern tree long_integer_type_node, long_unsigned_type_node; +extern tree long_long_integer_type_node, long_long_unsigned_type_node; +extern tree unsigned_type_node; +extern tree string_type_node, char_array_type_node, int_array_type_node; + +extern int current_function_returns_value; +extern int current_function_returns_null; + +extern tree ridpointers[]; + +/* Nonzero means `$' can be in an identifier. */ + +extern int dollars_in_ident; + +/* Nonzero means allow type mismatches in conditional expressions; + just make their values `void'. */ + +extern int flag_cond_mismatch; + +/* Nonzero means don't recognize the keyword `asm'. */ + +extern int flag_no_asm; + +/* Nonzero means warn about implicit declarations. */ + +extern int warn_implicit; + +/* Nonzero means warn about function definitions that default the return type + or that use a null return and have a return-type other than void. */ + +extern int warn_return_type; + +/* 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. */ + +extern int warn_write_strings; + +/* Nonzero means warn about sizeof(function) or addition/subtraction + of function pointers. */ + +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 pointer casts that can drop a type qualifier + from the pointer target type. */ + +extern int warn_cast_qual; + +/* Nonzero means do some things the same way PCC does. */ + +extern int flag_traditional; diff --git a/gcc-1.40/c-typeck.c b/gcc-1.40/c-typeck.c new file mode 100644 index 0000000..e1b4ad2 --- /dev/null +++ b/gcc-1.40/c-typeck.c @@ -0,0 +1,3807 @@ +/* Build expressions with type checking for C compiler. + Copyright (C) 1987, 1988, 1989 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 1, 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 part of the C front end. + It contains routines to build C expressions given their operands, + including computing the types of the result, C-specific error checks, + and some optimization. + + There are also routines to build RETURN_STMT nodes and CASE_STMT nodes, + and to process initializations in declarations (since they work + like a strange sort of assignment). */ + +#include "config.h" +#include +#include "tree.h" +#include "c-tree.h" +#include "flags.h" + + + +int mark_addressable (); +static tree convert_for_assignment (); +static int compparms (); +int comp_target_types (); +static tree shorten_compare (); +static void binary_op_error (); +static tree pointer_int_sum (); +static tree pointer_diff (); +static tree convert_sequence (); +static tree unary_complex_lvalue (); +static tree process_init_constructor (); +tree digest_init (); +tree truthvalue_conversion (); +static tree invert_truthvalue (); +void incomplete_type_error (); +void readonly_warning (); + +/* Return the _TYPE node describing the data type + of the data which NODE represents as a C expression. + Arrays and functions are converted to pointers + just as they are when they appear as C expressions. */ + +tree +datatype (node) + tree node; +{ + register tree type = TREE_TYPE (node); + if (TREE_CODE (type) == ARRAY_TYPE) + return TYPE_POINTER_TO (TREE_TYPE (type)); + if (TREE_CODE (type) == FUNCTION_TYPE) + return build_pointer_type (type); + return type; +} + +/* Do `exp = require_complete_type (exp);' to make sure exp + does not have an incomplete type. (That includes void types.) */ + +tree +require_complete_type (value) + tree value; +{ + tree type = TREE_TYPE (value); + + /* First, detect a valid value with a complete type. */ + if (TYPE_SIZE (type) != 0 + && type != void_type_node) + return value; + + incomplete_type_error (value, type); + return error_mark_node; +} + +/* Print an error message for invalid use of an incomplete type. + VALUE is the expression that was used (or 0 if that isn't known) + and TYPE is the type that was invalid. */ + +void +incomplete_type_error (value, type) + tree value; + tree type; +{ + char *errmsg; + + /* Avoid duplicate error message. */ + if (TREE_CODE (type) == ERROR_MARK) + return; + + if (value != 0 && (TREE_CODE (value) == VAR_DECL + || TREE_CODE (value) == PARM_DECL)) + error ("`%s' has an incomplete type", + IDENTIFIER_POINTER (DECL_NAME (value))); + else + { + retry: + /* We must print an error message. Be clever about what it says. */ + + 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'"; + break; + + case VOID_TYPE: + error ("invalid use of void expression"); + return; + + case ARRAY_TYPE: + if (TYPE_DOMAIN (type)) + { + type = TREE_TYPE (type); + goto retry; + } + error ("invalid use of array with unspecified bounds"); + return; + + default: + abort (); + } + + 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 ("invalid use of incomplete typedef `%s'", + IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type)))); + } +} + +/* Return a variant of TYPE which has all the type qualifiers of LIKE + as well as those of TYPE. */ + +static tree +qualify_type (type, like) + tree type, like; +{ + int constflag = TREE_READONLY (type) || TREE_READONLY (like); + int volflag = TREE_VOLATILE (type) || TREE_VOLATILE (like); + return c_build_type_variant (type, constflag, volflag); +} + +/* 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. + + This is the type for the result of most arithmetic operations + if the operands have the given two types. + + We do not deal with enumeral types here because they have already been + converted to integer types. */ + +tree +commontype (t1, t2) + tree t1, t2; +{ + register enum tree_code form1; + register enum tree_code form2; + + /* Save time if the two types are the same. */ + + if (t1 == t2) return t1; + + /* If one type is nonsense, use the other. */ + if (t1 == error_mark_node) + return t2; + if (t2 == error_mark_node) + return t1; + + /* Treat an enum type as the unsigned integer type of the same width. */ + + if (TREE_CODE (t1) == ENUMERAL_TYPE) + t1 = type_for_size (TYPE_PRECISION (t1), 1); + if (TREE_CODE (t2) == ENUMERAL_TYPE) + t2 = type_for_size (TYPE_PRECISION (t2), 1); + + form1 = TREE_CODE (t1); + form2 = TREE_CODE (t2); + + switch (form1) + { + case INTEGER_TYPE: + case REAL_TYPE: + /* If only one is real, use it as the result. */ + + if (form1 == REAL_TYPE && form2 != REAL_TYPE) + return t1; + + if (form2 == REAL_TYPE && form1 != REAL_TYPE) + return t2; + + /* Both real or both integers; use the one with greater precision. */ + + if (TYPE_PRECISION (t1) > TYPE_PRECISION (t2)) + return t1; + else if (TYPE_PRECISION (t2) > TYPE_PRECISION (t1)) + return t2; + + /* Same precision. Prefer longs to ints even when same size. */ + + if (t1 == long_unsigned_type_node + || t2 == long_unsigned_type_node) + return long_unsigned_type_node; + + if (t1 == long_integer_type_node + || t2 == long_integer_type_node) + { + /* But preserve unsignedness from the other type, + since long cannot hold all the values of an unsigned int. */ + if (TREE_UNSIGNED (t1) || TREE_UNSIGNED (t2)) + return long_unsigned_type_node; + return long_integer_type_node; + } + + /* Otherwise prefer the unsigned one. */ + + if (TREE_UNSIGNED (t1)) + return t1; + else return t2; + + case POINTER_TYPE: +#if 0 + /* For two pointers, do this recursively on the target type, + and combine the qualifiers of the two types' targets. */ + { + tree target = commontype (TYPE_MAIN_VARIANT (TREE_TYPE (t1)), + TYPE_MAIN_VARIANT (TREE_TYPE (t2))); + int constp + = TREE_READ_ONLY (TREE_TYPE (t1)) || TREE_READ_ONLY (TREE_TYPE (t2)); + int volatilep + = TREE_VOLATILE (TREE_TYPE (t1)) || TREE_VOLATILE (TREE_TYPE (t2)); + return build_pointer_type (c_build_type_variant (target, constp, volatilep)); + } +#endif + return build_pointer_type (commontype (TREE_TYPE (t1), TREE_TYPE (t2))); + + case ARRAY_TYPE: + { + tree elt = commontype (TREE_TYPE (t1), TREE_TYPE (t2)); + /* Save space: see if the result is identical to one of the args. */ + if (elt == TREE_TYPE (t1) && TYPE_DOMAIN (t1)) + return t1; + if (elt == TREE_TYPE (t2) && TYPE_DOMAIN (t2)) + return t2; + /* Merge the element types, and have a size if either arg has one. */ + return build_array_type (elt, TYPE_DOMAIN (TYPE_DOMAIN (t1) ? t1 : t2)); + } + + case FUNCTION_TYPE: + /* Function types: prefer the one that specified arg types. + If both do, merge the arg types. Also merge the return types. */ + { + tree valtype = commontype (TREE_TYPE (t1), TREE_TYPE (t2)); + tree p1 = TYPE_ARG_TYPES (t1); + tree p2 = TYPE_ARG_TYPES (t2); + int len; + tree newargs, n; + int i; + + /* Save space: see if the result is identical to one of the args. */ + if (valtype == TREE_TYPE (t1) && ! TYPE_ARG_TYPES (t2)) + return t1; + if (valtype == TREE_TYPE (t2) && ! TYPE_ARG_TYPES (t1)) + return t2; + + /* Simple way if one arg fails to specify argument types. */ + if (TYPE_ARG_TYPES (t1) == 0) + return build_function_type (valtype, TYPE_ARG_TYPES (t2)); + if (TYPE_ARG_TYPES (t2) == 0) + return build_function_type (valtype, TYPE_ARG_TYPES (t1)); + + /* If both args specify argument types, we must merge the two + lists, argument by argument. */ + + len = list_length (p1); + newargs = 0; + + for (i = 0; i < len; i++) + newargs = tree_cons (0, 0, newargs); + + n = newargs; + + for (; p1; + p1 = TREE_CHAIN (p1), p2 = TREE_CHAIN (p2), n = TREE_CHAIN (n)) + TREE_VALUE (n) = commontype (TREE_VALUE (p1), TREE_VALUE (p2)); + + return build_function_type (valtype, newargs); + } + + default: + return t1; + } + +} + +/* Return 1 if TYPE1 and TYPE2 are compatible types for assignment + or various other operations. This is what ANSI C speaks of as + "being the same". */ + +int +comptypes (type1, type2) + tree type1, type2; +{ + register tree t1 = type1; + register tree t2 = type2; + + /* Suppress errors caused by previously reported errors */ + + if (t1 == t2 || TREE_CODE (t1) == ERROR_MARK || TREE_CODE (t2) == ERROR_MARK) + return 1; + + /* Treat an enum type as the unsigned integer type of the same width. */ + + if (TREE_CODE (t1) == ENUMERAL_TYPE) + t1 = type_for_size (TYPE_PRECISION (t1), 1); + if (TREE_CODE (t2) == ENUMERAL_TYPE) + t2 = type_for_size (TYPE_PRECISION (t2), 1); + + if (t1 == t2) + return 1; + + /* Different classes of types can't be compatible. */ + + if (TREE_CODE (t1) != TREE_CODE (t2)) return 0; + + /* Qualifiers must match. */ + + if (TREE_READONLY (t1) != TREE_READONLY (t2)) + return 0; + if (TREE_THIS_VOLATILE (t1) != TREE_THIS_VOLATILE (t2)) + return 0; + + switch (TREE_CODE (t1)) + { + case POINTER_TYPE: + return (TREE_TYPE (t1) == TREE_TYPE (t2) + || comptypes (TREE_TYPE (t1), TREE_TYPE (t2))); + + case FUNCTION_TYPE: + return ((TREE_TYPE (t1) == TREE_TYPE (t2) + || comptypes (TREE_TYPE (t1), TREE_TYPE (t2))) + && compparms (TYPE_ARG_TYPES (t1), TYPE_ARG_TYPES (t2))); + + case ARRAY_TYPE: + /* Target types must match incl. qualifiers. */ + if (!(TREE_TYPE (t1) == TREE_TYPE (t2) + || comptypes (TREE_TYPE (t1), TREE_TYPE (t2)))) + return 0; + { + tree d1 = TYPE_DOMAIN (t1); + tree d2 = TYPE_DOMAIN (t2); + + /* Sizes must match unless one is missing or variable. */ + if (d1 == 0 || d2 == 0 || d1 == d2 + || TREE_CODE (TYPE_MIN_VALUE (d1)) != INTEGER_CST + || TREE_CODE (TYPE_MIN_VALUE (d2)) != INTEGER_CST + || TREE_CODE (TYPE_MAX_VALUE (d1)) != INTEGER_CST + || TREE_CODE (TYPE_MAX_VALUE (d2)) != INTEGER_CST) + return 1; + + return ((TREE_INT_CST_LOW (TYPE_MIN_VALUE (d1)) + == TREE_INT_CST_LOW (TYPE_MIN_VALUE (d2))) + && (TREE_INT_CST_HIGH (TYPE_MIN_VALUE (d1)) + == TREE_INT_CST_HIGH (TYPE_MIN_VALUE (d2))) + && (TREE_INT_CST_LOW (TYPE_MAX_VALUE (d1)) + == TREE_INT_CST_LOW (TYPE_MAX_VALUE (d2))) + && (TREE_INT_CST_HIGH (TYPE_MAX_VALUE (d1)) + == TREE_INT_CST_HIGH (TYPE_MAX_VALUE (d2)))); + } + } + return 0; +} + +/* Return 1 if TTL and TTR are pointers to types that are equivalent, + ignoring their qualifiers. */ + +int +comp_target_types (ttl, ttr) + tree ttl, ttr; +{ + return comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (ttl)), + TYPE_MAIN_VARIANT (TREE_TYPE (ttr))); +} + +/* Subroutines of `comptypes'. */ + +/* Return 1 if two parameter type lists PARMS1 and PARMS2 + are equivalent in the sense that functions with those parameter types + can have equivalent types. + If either list is empty, we win. + Otherwise, the two lists must be equivalent, element by element. */ + +static int +compparms (parms1, parms2) + tree parms1, parms2; +{ + register tree t1 = parms1, t2 = parms2; + + /* An unspecified parmlist matches any specified parmlist + whose argument types don't need default promotions. */ + + if (t1 == 0) + return compparms1 (t2); + if (t2 == 0) + return compparms1 (t1); + + while (1) + { + if (t1 == 0 && t2 == 0) + return 1; + /* If one parmlist is shorter than the other, + they fail to match. */ + if (t1 == 0 || t2 == 0) + return 0; + if (! comptypes (TREE_VALUE (t1), TREE_VALUE (t2))) + return 0; + t1 = TREE_CHAIN (t1); + t2 = TREE_CHAIN (t2); + } +} + +/* Return 1 if PARMS specifies a fixed number of parameters + and none of their types is affected by default promotions. */ + +int +compparms1 (parms) + tree parms; +{ + register tree t; + for (t = parms; t; t = TREE_CHAIN (t)) + { + register tree type = TREE_VALUE (t); + + if (TREE_CHAIN (t) == 0 && type != void_type_node) + return 0; + + if (type == float_type_node) + return 0; + + if (TREE_CODE (type) == INTEGER_TYPE + && TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)) + return 0; + } + return 1; +} + +/* Return an unsigned type the same as TYPE in other respects. */ + +tree +unsigned_type (type) + tree type; +{ + if (type == signed_char_type_node || type == char_type_node) + return unsigned_char_type_node; + if (type == integer_type_node) + return unsigned_type_node; + if (type == short_integer_type_node) + return short_unsigned_type_node; + if (type == long_integer_type_node) + return long_unsigned_type_node; + if (type == long_long_integer_type_node) + return long_long_unsigned_type_node; + return type; +} + +/* Return a signed type the same as TYPE in other respects. */ + +tree +signed_type (type) + tree type; +{ + if (type == unsigned_char_type_node || type == char_type_node) + return signed_char_type_node; + if (type == unsigned_type_node) + return integer_type_node; + if (type == short_unsigned_type_node) + return short_integer_type_node; + if (type == long_unsigned_type_node) + return long_integer_type_node; + if (type == long_long_unsigned_type_node) + return long_long_integer_type_node; + return type; +} + +/* Return a type the same as TYPE except unsigned or + signed according to UNSIGNEDP. */ + +tree +signed_or_unsigned_type (unsignedp, type) + int unsignedp; + tree type; +{ + if (TREE_CODE (type) != INTEGER_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); + return type; +} + +/* Return an integer type with BITS bits of precision, + that is unsigned if UNSIGNEDP is nonzero, otherwise signed. */ + +tree +type_for_size (bits, unsignedp) + int bits; + int unsignedp; +{ + 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 (integer_type_node)) + return unsignedp ? unsigned_type_node : 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); + + return 0; +} + +tree +get_floating_type (mode) + enum machine_mode mode; +{ + 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 (long_double_type_node)) + return long_double_type_node; + abort (); +} + +tree +c_sizeof (type) + tree type; +{ + enum tree_code code = TREE_CODE (type); + + if (code == FUNCTION_TYPE) + { + if (pedantic || warn_pointer_arith) + warning ("sizeof applied to a function type"); + return build_int (1); + } + if (code == VOID_TYPE) + { + if (pedantic || warn_pointer_arith) + warning ("sizeof applied to a void type"); + return build_int (1); + } + + /* Convert in case a char is more than one unit. */ + return convert_units (size_in_bytes (type), BITS_PER_UNIT, + TYPE_PRECISION (char_type_node)); +} + +tree +c_sizeof_nowarn (type) + tree type; +{ + enum tree_code code = TREE_CODE (type); + + if (code == FUNCTION_TYPE + || code == VOID_TYPE) + return build_int (1); + + /* Convert in case a char is more than one unit. */ + return convert_units (size_in_bytes (type), BITS_PER_UNIT, + TYPE_PRECISION (char_type_node)); +} + +/* Implement the __alignof keyword: Return the minimum required + alignment of TYPE, measured in bytes. */ + +tree +c_alignof (type) + tree type; +{ + enum tree_code code = TREE_CODE (type); + + if (code == FUNCTION_TYPE) + return build_int (FUNCTION_BOUNDARY / BITS_PER_UNIT); + + if (code == VOID_TYPE) + return build_int (1); + + return build_int (TYPE_ALIGN (type) / BITS_PER_UNIT); +} + +/* 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 + in a place where a variable is invalid. */ + && current_function_decl != 0 + && ! pedantic + && ! TREE_THIS_VOLATILE (decl) + && DECL_INITIAL (decl) != 0 + && TREE_CODE (DECL_INITIAL (decl)) != ERROR_MARK + /* 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. */ + && TREE_LITERAL (DECL_INITIAL (decl)) + /* Check for cases where this is sub-optimal, even though valid. */ + && TREE_CODE (DECL_INITIAL (decl)) != CONSTRUCTOR + && DECL_MODE (decl) != BLKmode) + return DECL_INITIAL (decl); + return decl; +} + +/* Perform default promotions for C data used in expressions. + Arrays and functions are converted to pointers; + enumeral types or short or char, to int. + In addition, manifest constants symbols are replaced by their values. */ + +tree +default_conversion (exp) + tree exp; +{ + register tree dt = TREE_TYPE (exp); + register enum tree_code form = TREE_CODE (dt); + + if (TREE_CODE (exp) == CONST_DECL) + exp = DECL_INITIAL (exp); + /* Replace a nonvolatile const static variable with its value. */ + else if (optimize + && TREE_CODE (exp) == VAR_DECL + && TREE_READONLY (exp)) + exp = decl_constant_value (exp); + + /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue. + Strip such NOP_EXPRs, since EXP is being used in non-lvalue context. */ + if (TREE_CODE (exp) == NOP_EXPR + && TREE_TYPE (exp) == TREE_TYPE (TREE_OPERAND (exp, 0))) + exp = TREE_OPERAND (exp, 0); + + if (form == ENUMERAL_TYPE + || (form == INTEGER_TYPE + && (TYPE_PRECISION (dt) + < TYPE_PRECISION (integer_type_node)))) + { + /* Traditionally, unsignedness is preserved in default promotions. */ + if (flag_traditional && TREE_UNSIGNED (dt)) + return convert (unsigned_type_node, exp); + return convert (integer_type_node, exp); + } + if (flag_traditional && dt == float_type_node) + return convert (double_type_node, exp); + if (form == VOID_TYPE) + { + error ("void value not ignored as it ought to be"); + return error_mark_node; + } + if (form == FUNCTION_TYPE) + { + return build_unary_op (ADDR_EXPR, exp, 0); + } + if (form == ARRAY_TYPE) + { + register tree adr; + tree restype = TREE_TYPE (dt); + tree ptrtype; + + if (TREE_CODE (exp) == INDIRECT_REF) + return convert (TYPE_POINTER_TO (restype), + TREE_OPERAND (exp, 0)); + + if (TREE_CODE (exp) == COMPOUND_EXPR) + { + tree op1 = default_conversion (TREE_OPERAND (exp, 1)); + return build (COMPOUND_EXPR, TREE_TYPE (op1), + TREE_OPERAND (exp, 0), op1); + } + + if (!lvalue_p (exp) + && ! (TREE_CODE (exp) == CONSTRUCTOR && TREE_STATIC (exp))) + { + error ("invalid use of non-lvalue array"); + return error_mark_node; + } + + if (TREE_READONLY (exp) || TREE_THIS_VOLATILE (exp)) + restype = c_build_type_variant (restype, TREE_READONLY (exp), + TREE_THIS_VOLATILE (exp)); + + ptrtype = build_pointer_type (restype); + + if (TREE_CODE (exp) == VAR_DECL) + { + /* ??? This is not really quite correct + in that the type of the operand of ADDR_EXPR + is not the target type of the type of the ADDR_EXPR itself. + Question is, can this lossage be avoided? */ + adr = build (ADDR_EXPR, ptrtype, exp); + if (mark_addressable (exp) == 0) + return error_mark_node; + TREE_LITERAL (adr) = staticp (exp); + TREE_VOLATILE (adr) = 0; /* Default would be, same as EXP. */ + return adr; + } + /* 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 exp; +} + +/* Make an expression to refer to the COMPONENT field of + structure or union value DATUM. COMPONENT is an IDENTIFIER_NODE. */ + +tree +build_component_ref (datum, component) + tree datum, component; +{ + register tree basename = datum; + register tree basetype = TREE_TYPE (basename); + register enum tree_code form = TREE_CODE (basetype); + register tree field = NULL; + register tree ref; + + /* First, see if there is a field or component with name COMPONENT. */ + + if (form == RECORD_TYPE || form == UNION_TYPE) + { + if (TYPE_SIZE (basetype) == 0) + { + incomplete_type_error (0, basetype); + return error_mark_node; + } + + /* Look up component name in the structure type definition. */ + + for (field = TYPE_FIELDS (basetype); field; field = TREE_CHAIN (field)) + { + if (DECL_NAME (field) == component) + break; + } + + if (!field) + { + error (form == RECORD_TYPE + ? "structure has no member named `%s'" + : "union has no member named `%s'", + IDENTIFIER_POINTER (component)); + return error_mark_node; + } + if (TREE_TYPE (field) == error_mark_node) + return error_mark_node; + + ref = build (COMPONENT_REF, TREE_TYPE (field), basename, field); + + if (TREE_READONLY (basename) || TREE_READONLY (field)) + TREE_READONLY (ref) = 1; + if (TREE_THIS_VOLATILE (basename) || TREE_VOLATILE (field)) + TREE_THIS_VOLATILE (ref) = 1; + + return ref; + } + else if (form != ERROR_MARK) + error ("request for member `%s' in something not a structure or union", + IDENTIFIER_POINTER (component)); + + return error_mark_node; +} + +/* Given an expression PTR for a pointer, return an expression + for the value pointed to. + ERRORSTRING is the name of the operator to appear in error messages. */ + +tree +build_indirect_ref (ptr, errorstring) + tree ptr; + char *errorstring; +{ + register tree pointer = default_conversion (ptr); + register tree dt = TREE_TYPE (pointer); + + if (TREE_CODE (dt) == POINTER_TYPE) + if (TREE_CODE (pointer) == ADDR_EXPR + && (TREE_TYPE (TREE_OPERAND (pointer, 0)) + == TREE_TYPE (dt))) + return TREE_OPERAND (pointer, 0); + else + { + tree t = TREE_TYPE (dt); + register tree ref = build (INDIRECT_REF, + TYPE_MAIN_VARIANT (t), pointer); + + if (TREE_CODE (t) == VOID_TYPE + || (TYPE_SIZE (t) == 0 && TREE_CODE (t) != ARRAY_TYPE)) + { + error ("dereferencing pointer to incomplete type"); + return error_mark_node; + } + + TREE_READONLY (ref) = TREE_READONLY (t); + TREE_VOLATILE (ref) = TREE_VOLATILE (t) || TREE_VOLATILE (pointer); + TREE_THIS_VOLATILE (ref) = TREE_VOLATILE (t); + return ref; + } + else if (TREE_CODE (pointer) != ERROR_MARK) + error ("invalid type argument of `%s'", errorstring); + return error_mark_node; +} + +/* This handles expressions of the form "a[i]", which denotes + an array reference. + + This is logically equivalent in C to *(a+i), but we may do it differently. + If A is a variable or a member, we generate a primitive ARRAY_REF. + This avoids forcing the array out of registers, and can work on + arrays that are not lvalues (for example, members of structures returned + by functions). */ + +tree +build_array_ref (array, index) + tree array, index; +{ + if (index == 0) + { + error ("subscript missing in array reference"); + return error_mark_node; + } + + if (TREE_CODE (TREE_TYPE (array)) == ARRAY_TYPE + && TREE_CODE (array) != INDIRECT_REF) + { + tree rval, type; + + index = default_conversion (index); + if (index != error_mark_node + && TREE_CODE (TREE_TYPE (index)) != INTEGER_TYPE) + { + error ("array subscript is not an integer"); + return error_mark_node; + } + + /* An array that is indexed by a non-constant + cannot be stored in a register; we must be able to do + address arithmetic on its address. + Likewise an array of elements of variable size. */ + if (TREE_CODE (index) != INTEGER_CST + || (TYPE_SIZE (TREE_TYPE (TREE_TYPE (array))) != 0 + && TREE_CODE (TYPE_SIZE (TREE_TYPE (TREE_TYPE (array)))) != INTEGER_CST)) + { + if (mark_addressable (array) == 0) + return error_mark_node; + } + + if (pedantic && !lvalue_p (array)) + warning ("ANSI C forbids subscripting non-lvalue array"); + + if (pedantic) + { + tree foo = array; + while (TREE_CODE (foo) == COMPONENT_REF) + foo = TREE_OPERAND (foo, 0); + if (TREE_CODE (foo) == VAR_DECL && TREE_REGDECL (foo)) + warning ("ANSI C forbids subscripting non-lvalue array"); + } + + type = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (array))); + rval = build (ARRAY_REF, type, array, index); + /* Array ref is const/volatile if the array elements are, + or if the array object is. */ + TREE_READONLY (rval) + |= (TREE_READONLY (TREE_TYPE (TREE_TYPE (array))) + | TREE_READONLY (array)); + TREE_VOLATILE (rval) + |= (TREE_VOLATILE (TREE_TYPE (TREE_TYPE (array))) + | TREE_VOLATILE (array)); + TREE_THIS_VOLATILE (rval) + |= TREE_VOLATILE (TREE_TYPE (TREE_TYPE (array))); + return require_complete_type (fold (rval)); + } + + { + tree ar = default_conversion (array); + tree ind = default_conversion (index); + + if ((TREE_CODE (TREE_TYPE (ar)) == POINTER_TYPE + && TREE_CODE (TREE_TYPE (ind)) != INTEGER_TYPE) + || (TREE_CODE (TREE_TYPE (ind)) == POINTER_TYPE + && TREE_CODE (TREE_TYPE (ar)) != INTEGER_TYPE)) + { + error ("array subscript is not an integer"); + return error_mark_node; + } + + 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 +build_function_call (function, params) + tree function, params; +{ + register tree fntype; + register tree value_type; + register tree coerced_params; + tree name = NULL_TREE; + tree actualparameterlist (); + + /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue. + Strip such NOP_EXPRs, since FUNCTION is used in non-lvalue context. */ + if (TREE_CODE (function) == NOP_EXPR + && TREE_TYPE (function) == TREE_TYPE (TREE_OPERAND (function, 0))) + function = TREE_OPERAND (function, 0); + + /* Convert anything with function type to a pointer-to-function. */ + if (TREE_CODE (function) == FUNCTION_DECL) + { + name = DECL_NAME (function); + /* Differs from default_conversion by not setting TREE_ADDRESSABLE + (because calling an inline function does not mean the function + needs to be separately compiled). */ + function = build (ADDR_EXPR, build_pointer_type (TREE_TYPE (function)), + function); + } + else + function = default_conversion (function); + + fntype = TREE_TYPE (function); + + if (TREE_CODE (fntype) == ERROR_MARK) + return error_mark_node; + + if (!(TREE_CODE (fntype) == POINTER_TYPE + && TREE_CODE (TREE_TYPE (fntype)) == FUNCTION_TYPE)) + { + error ("called object is not a function"); + return error_mark_node; + } + + /* fntype now gets the type of function pointed to. */ + fntype = TREE_TYPE (fntype); + + /* Convert the parameters to the types declared in the + function prototype, or apply default promotions. */ + + coerced_params = actualparameterlist (TYPE_ARG_TYPES (fntype), params, name); + + /* 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. */ + + if (TREE_CODE (function) == ADDR_EXPR + && TREE_CODE (TREE_OPERAND (function, 0)) == FUNCTION_DECL) + switch (DECL_FUNCTION_CODE (TREE_OPERAND (function, 0))) + { + case BUILT_IN_ABS: + case BUILT_IN_LABS: + case BUILT_IN_FABS: + if (coerced_params == 0) + return integer_zero_node; + return build_unary_op (ABS_EXPR, TREE_VALUE (coerced_params), 0); + } + + 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_VOLATILE (result) = 1; + if (value_type == void_type_node) + return result; + return require_complete_type (result); + } +} + +/* Convert the actual parameter expressions in the list VALUES + to the types in the list TYPELIST. + If parmdecls is exhausted, or when an element has NULL as its type, + perform the default conversions. + + NAME is an IDENTIFIER_NODE or 0. It is used only for error messages. + + This is also where warnings about wrong number of args are generated. + + Return a list of expressions for the parameters as converted. + + Both VALUES and the returned value are chains of TREE_LIST nodes + with the elements of the list in the TREE_VALUE slots of those nodes. */ + +tree +actualparameterlist (typelist, values, name) + tree typelist, values, name; +{ + register tree typetail, valtail; + register tree result = NULL; + + for (valtail = values, typetail = typelist; + valtail; + valtail = TREE_CHAIN (valtail)) + { + register tree type = typetail ? TREE_VALUE (typetail) : 0; + register tree val = TREE_VALUE (valtail); + register tree parm; + + if (type == void_type_node) + { + if (name) + error ("too many arguments to function `%s'", + IDENTIFIER_POINTER (name)); + else + error ("too many arguments to function"); + break; + } + + /* 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 + && TREE_TYPE (val) == TREE_TYPE (TREE_OPERAND (val, 0))) + val = TREE_OPERAND (val, 0); + + if (TREE_CODE (TREE_TYPE (val)) == ARRAY_TYPE + || TREE_CODE (TREE_TYPE (val)) == FUNCTION_TYPE) + val = default_conversion (val); + + val = require_complete_type (val); + + if (type != 0) + { + /* Formal parm type is specified by a function prototype. */ + tree parmval; + + if (TYPE_SIZE (type) == 0) + { + error ("parameter type of called function is incomplete"); + parmval = val; + } + else + { +#ifdef PROMOTE_PROTOTYPES + /* 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 + && (TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node))) + type = integer_type_node; +#endif + parmval = convert_for_assignment (type, val, "argument passing"); +#ifdef PROMOTE_PROTOTYPES + if (TREE_CODE (type) == INTEGER_TYPE + && (TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node))) + parmval = default_conversion (parmval); +#endif + } + parm = build_tree_list (0, parmval); + } + else if (TREE_CODE (TREE_TYPE (val)) == REAL_TYPE + && (TYPE_PRECISION (TREE_TYPE (val)) + < TYPE_PRECISION (double_type_node))) + /* Convert `float' to `double'. */ + parm = build_tree_list (NULL_TREE, convert (double_type_node, val)); + else + /* Convert `short' and `char' to full-size `int'. */ + parm = build_tree_list (NULL_TREE, default_conversion (val)); + + result = chainon (result, parm); + if (typetail) + typetail = TREE_CHAIN (typetail); + } + + if (typetail != 0 && TREE_VALUE (typetail) != void_type_node) + { + if (name) + error ("too few arguments to function `%s'", + IDENTIFIER_POINTER (name)); + else + error ("too few arguments to function"); + } + + return result; +} + +/* Build a binary-operation expression, after performing default + conversions on the operands. CODE is the kind of expression to build. */ + +tree +build_binary_op (code, arg1, arg2) + enum tree_code code; + tree arg1, arg2; +{ + return build_binary_op_nodefault (code, default_conversion (arg1), + default_conversion (arg2), code); +} + +/* Build a binary-operation expression without default conversions. + CODE is the kind of expression to build. + This function differs from `build' in several ways: + the data type of the result is computed and recorded in it, + warnings are generated if arg data types are invalid, + special handling for addition and subtraction of pointers is known, + and some optimization is done (operations on narrow ints + are done in the narrower type when that gives the same result). + Constant folding is also done before the result is returned. + + ERROR_CODE is the code that determines what to say in error messages. + It is usually, but not always, the same as CODE. + + Note that the operands will never have enumeral types + because either they have just had the default conversions performed + or they have both just been converted to some other type in which + the arithmetic is to be done. */ + +tree +build_binary_op_nodefault (code, op0, op1, error_code) + enum tree_code code; + tree op0, op1; + enum tree_code error_code; +{ + tree dt0 = datatype (op0), dt1 = datatype (op1); + + /* The expression codes of the data types of the arguments tell us + whether the arguments are integers, floating, pointers, etc. */ + register enum tree_code code0 = TREE_CODE (dt0); + register enum tree_code code1 = TREE_CODE (dt1); + + /* Expression code to give to the expression when it is built. + Normally this is CODE, which is what the caller asked for, + but in some special cases we change it. */ + register enum tree_code resultcode = code; + + /* Data type in which the computation is to be performed. + In the simplest cases this is the common type of the arguments. */ + register tree result_type = NULL; + + /* Nonzero means operands have already been type-converted + in whatever way is necessary. + Zero means they need to be converted to RESULT_TYPE. */ + int converted = 0; + + /* Nonzero means after finally constructing the expression + give it this type. Otherwise, give it type RESULT_TYPE. */ + tree final_type = 0; + + /* Nonzero if this is an operation like MIN or MAX which can + safely be computed in short if both args are promoted shorts. + Also implies COMMON. + -1 indicates a bitwise operation; this makes a difference + in the exact conditions for when it is safe to do the operation + in a narrower mode. */ + int shorten = 0; + + /* Nonzero if this is a comparison operation; + if both args are promoted shorts, compare the original shorts. + Also implies COMMON. */ + int short_compare = 0; + + /* Nonzero if this is a right-shift operation, which can be computed on the + original short and then promoted if the operand is a promoted short. */ + int short_shift = 0; + + /* Nonzero means set RESULT_TYPE to the common type of the args. */ + int common = 0; + + /* If an error was already reported for one of the arguments, + avoid reporting another error. */ + + if (code0 == ERROR_MARK || code1 == ERROR_MARK) + return error_mark_node; + + switch (code) + { + case PLUS_EXPR: + /* Handle the pointer + int case. */ + if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE) + return pointer_int_sum (PLUS_EXPR, op0, op1); + else if (code1 == POINTER_TYPE && code0 == INTEGER_TYPE) + return pointer_int_sum (PLUS_EXPR, op1, op0); + else + common = 1; + break; + + case MINUS_EXPR: + /* Subtraction of two similar pointers. + We must subtract them as integers, then divide by object size. */ + if (code0 == POINTER_TYPE && code1 == POINTER_TYPE + && comp_target_types (dt0, dt1)) + return pointer_diff (op0, op1); + /* 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); + else + common = 1; + break; + + case MULT_EXPR: + common = 1; + break; + + case TRUNC_DIV_EXPR: + case CEIL_DIV_EXPR: + 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 && code1 == INTEGER_TYPE)) + resultcode = RDIV_EXPR; + else + shorten = 1; + common = 1; + } + break; + + case BIT_AND_EXPR: + case BIT_ANDTC_EXPR: + case BIT_IOR_EXPR: + case BIT_XOR_EXPR: + if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE) + shorten = -1; + /* If one operand is a constant, and the other is a short type + that has been converted to an int, + really do the work in the short type and then convert the + result to int. If we are lucky, the constant will be 0 or 1 + in the short type, making the entire operation go away. */ + if (TREE_CODE (op0) == INTEGER_CST + && TREE_CODE (op1) == NOP_EXPR + && TYPE_PRECISION (dt1) > TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (op1, 0))) + && TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (op1, 0)))) + { + final_type = result_type; + op1 = TREE_OPERAND (op1, 0); + result_type = TREE_TYPE (op1); + } + if (TREE_CODE (op1) == INTEGER_CST + && TREE_CODE (op0) == NOP_EXPR + && TYPE_PRECISION (dt0) > TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (op0, 0))) + && TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (op0, 0)))) + { + final_type = result_type; + op0 = TREE_OPERAND (op0, 0); + result_type = TREE_TYPE (op0); + } + break; + + case TRUNC_MOD_EXPR: + if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE) + shorten = 1; + break; + + case TRUTH_ANDIF_EXPR: + case TRUTH_ORIF_EXPR: + case TRUTH_AND_EXPR: + case TRUTH_OR_EXPR: + if ((code0 == INTEGER_TYPE || code0 == POINTER_TYPE || code0 == REAL_TYPE) + && (code1 == INTEGER_TYPE || code1 == POINTER_TYPE || code1 == REAL_TYPE)) + { + /* Result of these operations is always an int, + but that does not mean the operands should be + converted to ints! */ + result_type = integer_type_node; + op0 = truthvalue_conversion (op0); + op1 = truthvalue_conversion (op1); + converted = 1; + } + break; + + /* Shift operations: result has same type as first operand; + always convert second operand to int. + Also set SHORT_SHIFT if shifting rightward. */ + + case RSHIFT_EXPR: + if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE) + { + result_type = dt0; + if (TREE_CODE (op1) == INTEGER_CST + && TREE_INT_CST_LOW (op1) > 0) + short_shift = 1; + /* Convert the shift-count to an integer, regardless of + size of value being shifted. */ + if (TREE_TYPE (op1) != integer_type_node) + op1 = convert (integer_type_node, op1); + } + break; + + case LSHIFT_EXPR: + if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE) + { + result_type = dt0; + if (TREE_CODE (op1) == INTEGER_CST + && TREE_INT_CST_LOW (op1) < 0) + short_shift = 1; + /* Convert the shift-count to an integer, regardless of + size of value being shifted. */ + if (TREE_TYPE (op1) != integer_type_node) + op1 = convert (integer_type_node, op1); + } + break; + + case RROTATE_EXPR: + case LROTATE_EXPR: + if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE) + { + result_type = dt0; + /* Convert the shift-count to an integer, regardless of + size of value being shifted. */ + if (TREE_TYPE (op1) != integer_type_node) + op1 = convert (integer_type_node, op1); + } + break; + + case EQ_EXPR: + case NE_EXPR: + /* Result of comparison is always int, + but don't convert the args to int! */ + result_type = integer_type_node; + converted = 1; + if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE) + && (code1 == INTEGER_TYPE || code1 == REAL_TYPE)) + short_compare = 1; + else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE) + { + register tree tt0 = TREE_TYPE (dt0); + register tree tt1 = TREE_TYPE (dt1); + /* Anything compares with void *. void * compares with anything. + Otherwise, the targets must be the same. */ + if (comp_target_types (dt0, dt1)) + ; + else if (TYPE_MAIN_VARIANT (tt0) == void_type_node) + { + if (pedantic && TREE_CODE (tt1) == FUNCTION_TYPE) + warning ("ANSI C forbids comparison of `void *' with function pointer"); + } + else if (TYPE_MAIN_VARIANT (tt1) == void_type_node) + { + if (pedantic && TREE_CODE (tt0) == FUNCTION_TYPE) + warning ("ANSI C forbids comparison of `void *' with function pointer"); + } + else + warning ("comparison of distinct pointer types lacks a cast"); + } + else if (code0 == POINTER_TYPE && TREE_CODE (op1) == INTEGER_CST + && integer_zerop (op1)) + op1 = null_pointer_node; + else if (code1 == POINTER_TYPE && TREE_CODE (op0) == INTEGER_CST + && integer_zerop (op0)) + op0 = null_pointer_node; + else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE) + { + if (! flag_traditional) + warning ("comparison between pointer and integer"); + op1 = convert (TREE_TYPE (op0), op1); + } + else if (code0 == INTEGER_TYPE && code1 == POINTER_TYPE) + { + if (! flag_traditional) + warning ("comparison between pointer and integer"); + op0 = convert (TREE_TYPE (op1), op0); + } + else + /* If args are not valid, clear out RESULT_TYPE + to cause an error message later. */ + result_type = 0; + break; + + case MAX_EXPR: + case MIN_EXPR: + if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE) + && (code1 == INTEGER_TYPE || code1 == REAL_TYPE)) + shorten = 1; + else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE) + { + if (! comp_target_types (dt0, dt1)) + warning ("comparison of distinct pointer types lacks a cast"); + else if (pedantic + && TREE_CODE (TREE_TYPE (dt0)) == FUNCTION_TYPE) + warning ("ANSI C forbids ordered comparisons of pointers to functions"); + result_type = commontype (dt0, dt1); + } + break; + + case LE_EXPR: + case GE_EXPR: + case LT_EXPR: + case GT_EXPR: + if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE) + && (code1 == INTEGER_TYPE || code1 == REAL_TYPE)) + short_compare = 1; + else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE) + { + if (! comp_target_types (dt0, dt1)) + warning ("comparison of distinct pointer types lacks a cast"); + else if (pedantic + && TREE_CODE (TREE_TYPE (dt0)) == FUNCTION_TYPE) + warning ("ANSI C forbids ordered comparisons of pointers to functions"); + result_type = integer_type_node; + } + else if (code0 == POINTER_TYPE && TREE_CODE (op1) == INTEGER_CST + && integer_zerop (op1)) + { + result_type = integer_type_node; + op1 = null_pointer_node; + if (! flag_traditional) + warning ("ordered comparison of pointer with integer zero"); + } + else if (code1 == POINTER_TYPE && TREE_CODE (op0) == INTEGER_CST + && integer_zerop (op0)) + { + result_type = integer_type_node; + op0 = null_pointer_node; + if (pedantic) + warning ("ordered comparison of pointer with integer zero"); + } + else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE) + { + result_type = integer_type_node; + if (! flag_traditional) + warning ("comparison between pointer and integer"); + op1 = convert (TREE_TYPE (op0), op1); + } + else if (code0 == INTEGER_TYPE && code1 == POINTER_TYPE) + { + result_type = integer_type_node; + if (! flag_traditional) + warning ("comparison between pointer and integer"); + op0 = convert (TREE_TYPE (op1), op0); + } + converted = 1; + break; + } + + if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE) + && (code1 == INTEGER_TYPE || code1 == REAL_TYPE)) + { + if (shorten || common || short_compare) + result_type = commontype (dt0, dt1); + + /* For certain operations (which identify themselves by shorten != 0) + if both args were extended from the same smaller type, + do the arithmetic in that type and then extend. + + shorten !=0 and !=1 indicates a bitwise operation. + For them, this optimization is safe only if + both args are zero-extended or both are sign-extended. + Otherwise, we might change the result. + Eg, (short)-1 | (unsigned short)-1 is (int)-1 + but calculated in (unsigned short) it would be (unsigned short)-1. */ + + if (shorten) + { + int unsigned0, unsigned1; + tree arg0 = get_narrower (op0, &unsigned0); + tree arg1 = get_narrower (op1, &unsigned1); + /* UNS is 1 if the operation to be done is an unsigned one. */ + int uns = TREE_UNSIGNED (result_type); + tree type; + + final_type = result_type; + + /* Handle the case that OP0 does not *contain* a conversion + but it *requires* conversion to FINAL_TYPE. */ + + if (op0 == arg0 && TREE_TYPE (op0) != final_type) + unsigned0 = TREE_UNSIGNED (TREE_TYPE (op0)); + if (op1 == arg1 && TREE_TYPE (op1) != final_type) + unsigned1 = TREE_UNSIGNED (TREE_TYPE (op1)); + + /* Now UNSIGNED0 is 1 if ARG0 zero-extends to FINAL_TYPE. */ + + /* For bitwise operations, signedness of nominal type + does not matter. Consider only how operands were extended. */ + if (shorten == -1) + uns = unsigned0; + + /* Note that in all three cases below we refrain from optimizing + an unsigned operation on sign-extended args. + That would not be valid. */ + + /* Both args variable: if both extended in same way + from same width, do it in that width. + Do it unsigned if args were zero-extended. */ + if ((TYPE_PRECISION (TREE_TYPE (arg0)) + < TYPE_PRECISION (result_type)) + && (TYPE_PRECISION (TREE_TYPE (arg1)) + == TYPE_PRECISION (TREE_TYPE (arg0))) + && unsigned0 == unsigned1 + && (unsigned0 || !uns)) + result_type + = signed_or_unsigned_type (unsigned0, + commontype (TREE_TYPE (arg0), TREE_TYPE (arg1))); + else if (TREE_CODE (arg0) == INTEGER_CST + && (unsigned1 || !uns) + && (TYPE_PRECISION (TREE_TYPE (arg1)) + < TYPE_PRECISION (result_type)) + && (type = signed_or_unsigned_type (unsigned1, + TREE_TYPE (arg1)), + int_fits_type_p (arg0, type))) + result_type = type; + else if (TREE_CODE (arg1) == INTEGER_CST + && (unsigned0 || !uns) + && (TYPE_PRECISION (TREE_TYPE (arg0)) + < TYPE_PRECISION (result_type)) + && (type = signed_or_unsigned_type (unsigned0, + TREE_TYPE (arg0)), + int_fits_type_p (arg1, type))) + result_type = type; + } + + /* Shifts can be shortened if shifting right. */ + + if (short_shift) + { + int unsigned_arg; + tree arg0 = get_narrower (op0, &unsigned_arg); + + final_type = result_type; + + if (arg0 == op0 && final_type == TREE_TYPE (op0)) + unsigned_arg = TREE_UNSIGNED (TREE_TYPE (op0)); + + if (TYPE_PRECISION (TREE_TYPE (arg0)) < TYPE_PRECISION (result_type) + /* If arg is sign-extended and then unsigned-shifted, + we can simulate this with a signed shift in arg's type + only if the extended result is at least twice as wide + as the arg. Otherwise, the shift could use up all the + ones made by sign-extension and bring in zeros. + We can't optimize that case at all, but in most machines + it never happens because available widths are 2**N. */ + && (!TREE_UNSIGNED (final_type) + || unsigned_arg + || 2 * TYPE_PRECISION (TREE_TYPE (arg0)) <= TYPE_PRECISION (result_type))) + { + /* Do an unsigned shift if the operand was zero-extended. */ + result_type + = signed_or_unsigned_type (unsigned_arg, + TREE_TYPE (arg0)); + /* Convert value-to-be-shifted to that type. */ + if (TREE_TYPE (op0) != result_type) + op0 = convert (result_type, op0); + converted = 1; + } + } + + /* Comparison operations are shortened too but differently. + They identify themselves by setting short_compare = 1. */ + + if (short_compare) + { + /* Don't write &op0, etc., because that would prevent op0 + from being kept in a register. + Instead, make copies of the our local variables and + pass the copies by reference, then copy them back afterward. */ + tree xop0 = op0, xop1 = op1, xresult_type = result_type; + enum tree_code xresultcode = resultcode; + tree val + = shorten_compare (&xop0, &xop1, &xresult_type, &xresultcode); + if (val != 0) + return val; + op0 = xop0, op1 = xop1, result_type = xresult_type; + resultcode = xresultcode; + } + } + + /* At this point, RESULT_TYPE must be nonzero to avoid an error message. + If CONVERTED is zero, both args will be converted to type RESULT_TYPE. + Then the expression will be built. + It will be given type FINAL_TYPE if that is nonzero; + otherwise, it will be given type RESULT_TYPE. */ + + if (!result_type) + { + binary_op_error (error_code); + return error_mark_node; + } + + if (! converted) + { + if (TREE_TYPE (op0) != result_type) + op0 = convert (result_type, op0); + if (TREE_TYPE (op1) != result_type) + op1 = convert (result_type, op1); + } + + { + register tree result = build (resultcode, result_type, op0, op1); + register tree folded; + + folded = fold (result); + if (folded == result) + TREE_LITERAL (folded) = TREE_LITERAL (op0) & TREE_LITERAL (op1); + if (final_type != 0) + return convert (final_type, folded); + return folded; + } +} + +/* Return a tree for the sum or difference (RESULTCODE says which) + of pointer PTROP and integer INTOP. */ + +static tree +pointer_int_sum (resultcode, ptrop, intop) + enum tree_code resultcode; + register tree ptrop, intop; +{ + tree size_exp; + + register tree result; + register tree folded; + + /* The result is a pointer of the same type that is being added. */ + + register tree result_type = datatype (ptrop); + + if (TREE_CODE (TREE_TYPE (result_type)) == VOID_TYPE) + { + if (pedantic || warn_pointer_arith) + warning ("pointer of type `void *' used in arithmetic"); + size_exp = integer_one_node; + } + else if (TREE_CODE (TREE_TYPE (result_type)) == FUNCTION_TYPE) + { + if (pedantic || warn_pointer_arith) + warning ("pointer to a function used in arithmetic"); + size_exp = integer_one_node; + } + else + size_exp = c_sizeof (TREE_TYPE (result_type)); + + /* If what we are about to multiply by the size of the elements + contains a constant term, apply distributive law + and multiply that constant term separately. + This helps produce common subexpressions. */ + + if ((TREE_CODE (intop) == PLUS_EXPR || TREE_CODE (intop) == MINUS_EXPR) + && ! TREE_LITERAL (intop) + && TREE_LITERAL (TREE_OPERAND (intop, 1)) + && TREE_LITERAL (size_exp)) + { + enum tree_code subcode = resultcode; + if (TREE_CODE (intop) == MINUS_EXPR) + subcode = (subcode == PLUS_EXPR ? MINUS_EXPR : PLUS_EXPR); + ptrop = build_binary_op (subcode, ptrop, TREE_OPERAND (intop, 1)); + intop = TREE_OPERAND (intop, 0); + } + + /* 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 (intop)) != POINTER_SIZE) + intop = convert (type_for_size (POINTER_SIZE, 0), intop); + + /* Replace the integer argument + with a suitable product by the object size. */ + + intop = build_binary_op (MULT_EXPR, intop, size_exp); + + /* Create the sum or difference. */ + + result = build (resultcode, result_type, ptrop, intop); + + folded = fold (result); + if (folded == result) + TREE_LITERAL (folded) = TREE_LITERAL (ptrop) & TREE_LITERAL (intop); + return folded; +} + +/* Return a tree for the difference of pointers OP0 and OP1. + The resulting tree has type int. */ + +static tree +pointer_diff (op0, op1) + register tree op0, op1; +{ + tree dt0 = datatype (op0); + enum tree_code resultcode; + register tree result, folded; + tree restype = type_for_size (POINTER_SIZE, 0); + + if (pedantic) + { + if (TREE_CODE (TREE_TYPE (dt0)) == VOID_TYPE) + warning ("pointer of type `void *' used in subtraction"); + if (TREE_CODE (TREE_TYPE (dt0)) == FUNCTION_TYPE) + warning ("pointer to a function used in subtraction"); + } + + /* 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)); + op1 = c_sizeof_nowarn (TREE_TYPE (dt0)); + + /* Create the sum or difference. */ + + result = build (EXACT_DIV_EXPR, restype, op0, op1); + + folded = fold (result); + if (folded == result) + TREE_LITERAL (folded) = TREE_LITERAL (op0) & TREE_LITERAL (op1); + return folded; +} + +/* Print an error message for invalid operands to arith operation CODE. + NOP_EXPR is used as a special case (see truthvalue_conversion). */ + +static void +binary_op_error (code) + enum tree_code code; +{ + register char *opname; + switch (code) + { + case NOP_EXPR: + error ("invalid truth-value expression"); + return; + + case PLUS_EXPR: + opname = "+"; break; + case MINUS_EXPR: + opname = "-"; break; + case MULT_EXPR: + opname = "*"; break; + case MAX_EXPR: + opname = "max"; break; + case MIN_EXPR: + opname = "min"; break; + case EQ_EXPR: + opname = "=="; break; + case NE_EXPR: + opname = "!="; break; + case LE_EXPR: + opname = "<="; break; + case GE_EXPR: + opname = ">="; break; + case LT_EXPR: + opname = "<"; break; + case GT_EXPR: + opname = ">"; break; + case LSHIFT_EXPR: + opname = "<<"; break; + case RSHIFT_EXPR: + opname = ">>"; break; + case TRUNC_MOD_EXPR: + opname = "%"; break; + case TRUNC_DIV_EXPR: + opname = "/"; break; + case BIT_AND_EXPR: + opname = "&"; break; + case BIT_IOR_EXPR: + opname = "|"; break; + case TRUTH_ANDIF_EXPR: + opname = "&&"; break; + case TRUTH_ORIF_EXPR: + opname = "||"; break; + case BIT_XOR_EXPR: + opname = "^"; break; + } + error ("invalid operands to binary %s", opname); +} + +/* Subroutine of build_binary_op_nodefault, 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. + + The arguments of this function are all pointers to local variables + of build_binary_op_nodefault: OP0_PTR is &OP0, OP1_PTR is &OP1, + RESTYPE_PTR is &RESULT_TYPE and RESCODE_PTR is &RESULTCODE. + + If this function returns nonzero, it means that the comparison has + a constant value. What this function returns is an expression for + that value. */ + +static tree +shorten_compare (op0_ptr, op1_ptr, restype_ptr, rescode_ptr) + tree *op0_ptr, *op1_ptr; + tree *restype_ptr; + enum tree_code *rescode_ptr; +{ + register tree type; + tree op0 = *op0_ptr; + tree op1 = *op1_ptr; + int unsignedp0, unsignedp1; + int real1, real2; + tree primop0, primop1; + enum tree_code code = *rescode_ptr; + + /* Throw away any conversions to wider types + already present in the operands. */ + + primop0 = get_narrower (op0, &unsignedp0); + primop1 = get_narrower (op1, &unsignedp1); + + /* Handle the case that OP0 does not *contain* a conversion + but it *requires* conversion to FINAL_TYPE. */ + + if (op0 == primop0 && TREE_TYPE (op0) != *restype_ptr) + unsignedp0 = TREE_UNSIGNED (TREE_TYPE (op0)); + if (op1 == primop1 && TREE_TYPE (op1) != *restype_ptr) + unsignedp1 = TREE_UNSIGNED (TREE_TYPE (op1)); + + /* If one of the operands must be floated, we cannot optimize. */ + real1 = TREE_CODE (TREE_TYPE (primop0)) == REAL_TYPE; + real2 = TREE_CODE (TREE_TYPE (primop1)) == REAL_TYPE; + + /* If first arg is constant, swap the args (changing operation + so value is preserved), for canonicalization. */ + + if (TREE_LITERAL (primop0)) + { + register tree tem = primop0; + register int temi = unsignedp0; + primop0 = primop1; + primop1 = tem; + tem = op0; + op0 = op1; + op1 = tem; + *op0_ptr = op0; + *op1_ptr = op1; + unsignedp0 = unsignedp1; + unsignedp1 = temi; + temi = real1; + real1 = real2; + real2 = temi; + + switch (code) + { + case LT_EXPR: + code = GT_EXPR; + break; + case GT_EXPR: + code = LT_EXPR; + break; + case LE_EXPR: + code = GE_EXPR; + break; + case GE_EXPR: + code = LE_EXPR; + break; + } + *rescode_ptr = code; + } + + /* If comparing an integer against a constant more bits wide, + maybe we can deduce a value of 1 or 0 independent of the data. + Or else truncate the constant now + rather than extend the variable at run time. + + This is only interesting if the constant is the wider arg. + Also, it is not safe if the constant is unsigned and the + variable arg is signed, since in this case the variable + would be sign-extended and then regarded as unsigned. + Our technique fails in this case because the lowest/highest + possible unsigned results don't follow naturally from the + lowest/highest possible values of the variable operand. + For just EQ_EXPR and NE_EXPR there is another technique that + could be used: see if the constant can be faithfully represented + in the other operand's type, by truncating it and reextending it + and see if that preserves the constant's value. */ + + if (!real1 && !real2 + && TREE_CODE (primop1) == INTEGER_CST + && TYPE_PRECISION (TREE_TYPE (primop0)) < TYPE_PRECISION (*restype_ptr)) + { + int min_gt, max_gt, min_lt, max_lt; + tree maxval, minval; + /* 1 if comparison is nominally unsigned. */ + int unsignedp = TREE_UNSIGNED (*restype_ptr); + tree val; + + type = signed_or_unsigned_type (unsignedp0, TREE_TYPE (primop0)); + + maxval = TYPE_MAX_VALUE (type); + minval = TYPE_MIN_VALUE (type); + + if (unsignedp && !unsignedp0) + *restype_ptr = signed_type (*restype_ptr); + + if (TREE_TYPE (primop1) != *restype_ptr) + primop1 = convert (*restype_ptr, primop1); + if (type != *restype_ptr) + { + minval = convert (*restype_ptr, minval); + maxval = convert (*restype_ptr, maxval); + } + + if (unsignedp && unsignedp0) + { + min_gt = INT_CST_LT_UNSIGNED (primop1, minval); + max_gt = INT_CST_LT_UNSIGNED (primop1, maxval); + min_lt = INT_CST_LT_UNSIGNED (minval, primop1); + max_lt = INT_CST_LT_UNSIGNED (maxval, primop1); + } + else + { + min_gt = INT_CST_LT (primop1, minval); + max_gt = INT_CST_LT (primop1, maxval); + min_lt = INT_CST_LT (minval, primop1); + max_lt = INT_CST_LT (maxval, primop1); + } + + val = 0; + /* This used to be a switch, but Genix compiler can't handle that. */ + if (code == NE_EXPR) + { + if (max_lt || min_gt) + val = integer_one_node; + } + else if (code == EQ_EXPR) + { + if (max_lt || min_gt) + val = integer_zero_node; + } + else if (code == LT_EXPR) + { + if (max_lt) + val = integer_one_node; + if (!min_lt) + val = integer_zero_node; + } + else if (code == GT_EXPR) + { + if (min_gt) + val = integer_one_node; + if (!max_gt) + val = integer_zero_node; + } + else if (code == LE_EXPR) + { + if (!max_gt) + val = integer_one_node; + if (min_gt) + val = integer_zero_node; + } + else if (code == GE_EXPR) + { + if (!min_lt) + val = integer_one_node; + if (max_lt) + val = integer_zero_node; + } + + /* If primop0 was sign-extended and unsigned comparison specd, + we did a signed comparison above using the signed type bounds. + But the comparison we output must be unsigned. + + Also, for inequalities, VAL is no good; but if the signed + comparison had *any* fixed result, it follows that the + unsigned comparison just tests the sign in reverse + (positive values are LE, negative ones GE). + So we can generate an unsigned comparison + against an extreme value of the signed type. */ + + if (unsignedp && !unsignedp0) + { + if (val != 0) + switch (code) + { + case LT_EXPR: + case GE_EXPR: + primop1 = TYPE_MIN_VALUE (type); + val = 0; + break; + + case LE_EXPR: + case GT_EXPR: + primop1 = TYPE_MAX_VALUE (type); + val = 0; + break; + } + type = unsigned_type (type); + } + + if (max_lt && !unsignedp0) + { + /* This is the case of (char)x >?< 0x80, which people used to use + expecting old C compilers to change the 0x80 into -0x80. */ + if (val == integer_zero_node) + warning ("comparison is always 0 due to limited range of data type"); + if (val == integer_one_node) + warning ("comparison is always 1 due to limited range of data type"); + } + + if (val != 0) + { + /* Don't forget to evaluate PRIMOP0 if it has side effects. */ + if (TREE_VOLATILE (primop0)) + return build (COMPOUND_EXPR, TREE_TYPE (val), primop0, val); + return val; + } + + /* Value is not predetermined, but do the comparison + in the type of the operand that is not constant. + TYPE is already properly set. */ + } + else if (real1 && real2 + && TYPE_PRECISION (TREE_TYPE (primop0)) == TYPE_PRECISION (TREE_TYPE (primop1))) + type = TREE_TYPE (primop0); + + /* If args' natural types are both narrower than nominal type + and both extend in the same manner, compare them + in the type of the wider arg. + Otherwise must actually extend both to the nominal + common type lest different ways of extending + alter the result. + (eg, (short)-1 == (unsigned short)-1 should be 0.) */ + + else if (unsignedp0 == unsignedp1 && real1 == real2 + && TYPE_PRECISION (TREE_TYPE (primop0)) < TYPE_PRECISION (*restype_ptr) + && TYPE_PRECISION (TREE_TYPE (primop1)) < TYPE_PRECISION (*restype_ptr)) + { + type = commontype (TREE_TYPE (primop0), TREE_TYPE (primop1)); + type = signed_or_unsigned_type (unsignedp0 + || TREE_UNSIGNED (*restype_ptr), + type); + /* Make sure shorter operand is extended the right way + to match the longer operand. */ + primop0 = convert (signed_or_unsigned_type (unsignedp0, TREE_TYPE (primop0)), + primop0); + primop1 = convert (signed_or_unsigned_type (unsignedp1, TREE_TYPE (primop1)), + primop1); + } + else + { + /* Here we must do the comparison on the nominal type + using the args exactly as we received them. */ + type = *restype_ptr; + primop0 = op0; + primop1 = op1; + } + + *op0_ptr = convert (type, primop0); + *op1_ptr = convert (type, primop1); + + *restype_ptr = integer_type_node; + + return 0; +} + +/* Construct and perhaps optimize a tree representation + for a unary operation. CODE, a tree_code, specifies the operation + and XARG is the operand. NOCONVERT nonzero suppresses + the default promotions (such as from short to int). */ + +tree +build_unary_op (code, xarg, noconvert) + enum tree_code code; + tree xarg; + int noconvert; +{ + /* No default_conversion here. It causes trouble for ADDR_EXPR. */ + register tree arg = xarg; + register tree argtype = 0; + register enum tree_code typecode = TREE_CODE (TREE_TYPE (arg)); + char *errstring = NULL; + tree val; + + if (typecode == ERROR_MARK) + return error_mark_node; + if (typecode == ENUMERAL_TYPE) + typecode = INTEGER_TYPE; + + switch (code) + { + case CONVERT_EXPR: + /* This is used for unary plus, because a CONVERT_EXPR + is enough to prevent anybody from looking inside for + associativity, but won't generate any code. */ + if (!(typecode == INTEGER_TYPE || typecode == REAL_TYPE)) + errstring = "wrong type argument to unary plus"; + else if (!noconvert) + arg = default_conversion (arg); + break; + + case NEGATE_EXPR: + if (!(typecode == INTEGER_TYPE || typecode == REAL_TYPE)) + errstring = "wrong type argument to unary minus"; + else if (!noconvert) + arg = default_conversion (arg); + break; + + case BIT_NOT_EXPR: + if (typecode != INTEGER_TYPE) + errstring = "wrong type argument to bit-complement"; + else if (!noconvert) + arg = default_conversion (arg); + break; + + case ABS_EXPR: + if (!(typecode == INTEGER_TYPE || typecode == REAL_TYPE)) + errstring = "wrong type argument to abs"; + else if (!noconvert) + arg = default_conversion (arg); + break; + + case TRUTH_NOT_EXPR: + if (typecode != INTEGER_TYPE + && typecode != REAL_TYPE && typecode != POINTER_TYPE + /* This will convert to a pointer. */ + && typecode != ARRAY_TYPE && typecode != FUNCTION_TYPE) + { + errstring = "wrong type argument to unary exclamation mark"; + break; + } + arg = truthvalue_conversion (arg); + val = invert_truthvalue (arg); + if (val) return val; + break; + + case NOP_EXPR: + break; + + case PREINCREMENT_EXPR: + case POSTINCREMENT_EXPR: + case PREDECREMENT_EXPR: + case POSTDECREMENT_EXPR: + /* Handle complex lvalues (when permitted) + by reduction to simpler cases. */ + + val = unary_complex_lvalue (code, arg); + if (val != 0) + return val; + + /* Report invalid types. */ + + if (typecode != POINTER_TYPE + && typecode != INTEGER_TYPE && typecode != REAL_TYPE) + { + if (code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR) + errstring ="wrong type argument to increment"; + else + errstring ="wrong type argument to decrement"; + break; + } + + /* Report something read-only. */ + + if (TREE_READONLY (arg)) + readonly_warning (arg, + ((code == PREINCREMENT_EXPR + || code == POSTINCREMENT_EXPR) + ? "increment" : "decrement")); + + { + register tree inc; + tree result_type = TREE_TYPE (arg); + + arg = get_unwidened (arg, 0); + argtype = TREE_TYPE (arg); + + /* Compute the increment. */ + + if (typecode == POINTER_TYPE) + { + if (pedantic + && (TREE_CODE (TREE_TYPE (result_type)) == FUNCTION_TYPE + || TREE_CODE (TREE_TYPE (result_type)) == VOID_TYPE)) + warning ("wrong type argument to %s", + ((code == PREINCREMENT_EXPR + || code == POSTINCREMENT_EXPR) + ? "increment" : "decrement")); + inc = c_sizeof_nowarn (TREE_TYPE (result_type)); + } + else + inc = integer_one_node; + + inc = convert (argtype, inc); + + /* Handle incrementing a cast-expression. */ + + if (!pedantic) + switch (TREE_CODE (arg)) + { + 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: + { + tree incremented, modify, value; + arg = stabilize_reference (arg); + if (code == PREINCREMENT_EXPR || code == PREDECREMENT_EXPR) + value = arg; + else + value = save_expr (arg); + incremented = build (((code == PREINCREMENT_EXPR + || code == POSTINCREMENT_EXPR) + ? PLUS_EXPR : MINUS_EXPR), + argtype, value, inc); + TREE_VOLATILE (incremented) = 1; + modify = build_modify_expr (arg, NOP_EXPR, incremented); + return build (COMPOUND_EXPR, TREE_TYPE (arg), modify, value); + } + } + + /* Complain about anything else that is not a true lvalue. */ + if (!lvalue_or_else (arg, ((code == PREINCREMENT_EXPR + || code == POSTINCREMENT_EXPR) + ? "increment" : "decrement"))) + return error_mark_node; + + val = build (code, TREE_TYPE (arg), arg, inc); + TREE_VOLATILE (val) = 1; + return convert (result_type, val); + } + + case ADDR_EXPR: + /* Note that this operation never does default_conversion + regardless of NOCONVERT. */ + + /* Let &* cancel out to simplify resulting code. */ + if (TREE_CODE (arg) == INDIRECT_REF) + { + /* Don't let this be an lvalue. */ + if (lvalue_p (TREE_OPERAND (arg, 0))) + return build (NOP_EXPR, TREE_TYPE (TREE_OPERAND (arg, 0)), + TREE_OPERAND (arg, 0)); + return TREE_OPERAND (arg, 0); + } + + /* For &x[y], return x+y */ + if (TREE_CODE (arg) == ARRAY_REF) + { + if (mark_addressable (TREE_OPERAND (arg, 0)) == 0) + return error_mark_node; + return build_binary_op (PLUS_EXPR, TREE_OPERAND (arg, 0), + TREE_OPERAND (arg, 1)); + } + + /* Handle complex lvalues (when permitted) + by reduction to simpler cases. */ + val = unary_complex_lvalue (code, arg); + if (val != 0) + return val; + + /* Address of a cast is just a cast of the address + of the operand of the cast. */ + switch (TREE_CODE (arg)) + { + 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: + if (pedantic) + warning ("ANSI C forbids the address of a cast expression"); + return convert (build_pointer_type (TREE_TYPE (arg)), + build_unary_op (ADDR_EXPR, TREE_OPERAND (arg, 0), + 0)); + } + + /* Allow the address of a constructor if all the elements + are constant. */ + if (TREE_CODE (arg) == CONSTRUCTOR && TREE_LITERAL (arg)) + ; + /* Anything not already handled and not a true memory reference + is an error. */ + else if (typecode != FUNCTION_TYPE && !lvalue_or_else (arg, "unary `&'")) + return error_mark_node; + + /* Ordinary case; arg is a COMPONENT_REF or a decl. */ + argtype = TREE_TYPE (arg); + if (TREE_READONLY (arg) || TREE_THIS_VOLATILE (arg)) + argtype = c_build_type_variant (argtype, + TREE_READONLY (arg), + TREE_THIS_VOLATILE (arg)); + + argtype = build_pointer_type (argtype); + + if (mark_addressable (arg) == 0) + return error_mark_node; + + { + tree addr; + + if (TREE_CODE (arg) == COMPONENT_REF) + { + tree field = TREE_OPERAND (arg, 1); + + addr = build_unary_op (ADDR_EXPR, TREE_OPERAND (arg, 0), 0); + + if (TREE_PACKED (field)) + { + error ("attempt to take address of bit-field structure member `%s'", + IDENTIFIER_POINTER (DECL_NAME (field))); + return error_mark_node; + } + + addr = convert (argtype, addr); + + if (DECL_OFFSET (field) != 0) + { + tree offset = build_int_2 ((DECL_OFFSET (field) + / BITS_PER_UNIT), + 0); + TREE_TYPE (offset) = argtype; + addr = fold (build (PLUS_EXPR, argtype, addr, offset)); + } + } + else + addr = build (code, argtype, arg); + + /* Address of a static or external variable or + function counts as a constant */ + TREE_LITERAL (addr) = staticp (arg); + return addr; + } + } + + if (!errstring) + { + if (argtype == 0) + argtype = TREE_TYPE (arg); + return fold (build (code, argtype, arg)); + } + + error (errstring); + return error_mark_node; +} + +/* 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. */ + +static tree +convert_sequence (conversions, arg) + tree conversions; + tree arg; +{ + switch (TREE_CODE (conversions)) + { + 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: + return convert (TREE_TYPE (conversions), + convert_sequence (TREE_OPERAND (conversions, 0), + arg)); + + default: + return arg; + } +} + +/* Apply unary lvalue-demanding operator CODE to the expression ARG + for certain kinds of expressions which are not really lvalues + but which we can accept as lvalues. + + If ARG is not a kind of expression we can handle, return zero. */ + +static tree +unary_complex_lvalue (code, arg) + enum tree_code code; + tree arg; +{ + if (pedantic) + return 0; + + /* Handle (a, b) used as an "lvalue". */ + if (TREE_CODE (arg) == COMPOUND_EXPR) + { + tree real_result = build_unary_op (code, TREE_OPERAND (arg, 1), 0); + return build (COMPOUND_EXPR, TREE_TYPE (real_result), + TREE_OPERAND (arg, 0), real_result); + } + + /* Handle (a ? b : c) used as an "lvalue". */ + if (TREE_CODE (arg) == COND_EXPR) + return (build_conditional_expr + (TREE_OPERAND (arg, 0), + build_unary_op (code, TREE_OPERAND (arg, 1), 0), + build_unary_op (code, TREE_OPERAND (arg, 2), 0))); + + return 0; +} + +/* Warn about storing in something that is `const'. */ + +void +readonly_warning (arg, string) + tree arg; + char *string; +{ + char buf[80]; + strcpy (buf, string); + + if (TREE_CODE (arg) == COMPONENT_REF) + { + if (TREE_READONLY (TREE_OPERAND (arg, 0))) + readonly_warning (TREE_OPERAND (arg, 0), string); + else + { + strcat (buf, " of read-only member `%s'"); + warning (buf, IDENTIFIER_POINTER (DECL_NAME (TREE_OPERAND (arg, 1)))); + } + } + else if (TREE_CODE (arg) == VAR_DECL) + { + strcat (buf, " of read-only variable `%s'"); + warning (buf, IDENTIFIER_POINTER (DECL_NAME (arg))); + } + else + { + warning ("%s of read-only location", buf); + } +} + +/* 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), + but we optimize comparisons, &&, ||, and ! */ + +tree +truthvalue_conversion (expr) + tree expr; +{ + register enum tree_code form; + + /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue. + Strip such NOP_EXPRs, since EXPR 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); + + form = TREE_CODE (expr); + + if (form == EQ_EXPR && integer_zerop (TREE_OPERAND (expr, 1))) + return build_unary_op (TRUTH_NOT_EXPR, TREE_OPERAND (expr, 0), 0); + + /* A one-bit unsigned bit-field is already acceptable. */ + if (form == COMPONENT_REF + && 1 == TREE_INT_CST_LOW (DECL_SIZE (TREE_OPERAND (expr, 1))) + && 1 == DECL_SIZE_UNIT (TREE_OPERAND (expr, 1)) + && TREE_UNSIGNED (TREE_OPERAND (expr, 1))) + return expr; + + if (form == TRUTH_ANDIF_EXPR || form == TRUTH_ORIF_EXPR + || form == TRUTH_AND_EXPR || form == TRUTH_OR_EXPR + || form == TRUTH_NOT_EXPR + || form == EQ_EXPR || form == NE_EXPR + || form == LE_EXPR || form == GE_EXPR + || form == LT_EXPR || form == GT_EXPR + || form == ERROR_MARK) + return expr; + + /* Unary minus has no effect on whether its argument is nonzero. */ + if (form == NEGATE_EXPR) + return truthvalue_conversion (TREE_OPERAND (expr, 0)); + + /* Distribute the conversion into the arms of a COND_EXPR. */ + if (form == COND_EXPR) + return build (COND_EXPR, integer_type_node, + TREE_OPERAND (expr, 0), + truthvalue_conversion (TREE_OPERAND (expr, 1)), + truthvalue_conversion (TREE_OPERAND (expr, 2))); + + /* Sign-extension and zero-extension has no effect. */ + if (form == NOP_EXPR + && TREE_CODE (TREE_TYPE (expr)) == INTEGER_TYPE + && (TYPE_PRECISION (TREE_TYPE (expr)) + > TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (expr, 0))))) + return truthvalue_conversion (TREE_OPERAND (expr, 0)); + + return build_binary_op_nodefault (NE_EXPR, default_conversion (expr), + integer_zero_node, NOP_EXPR); +} + +/* Return a simplified tree node for the truth-negation of ARG + (perhaps by altering ARG). + If it can't be simplified, return 0. */ + +static tree +invert_truthvalue (arg) + tree arg; +{ + switch (TREE_CODE (arg)) + { + case NE_EXPR: + TREE_SET_CODE (arg, EQ_EXPR); + return arg; + + case EQ_EXPR: + TREE_SET_CODE (arg, NE_EXPR); + return arg; + + case GE_EXPR: + TREE_SET_CODE (arg, LT_EXPR); + return arg; + + case GT_EXPR: + TREE_SET_CODE (arg, LE_EXPR); + return arg; + + case LE_EXPR: + TREE_SET_CODE (arg, GT_EXPR); + return arg; + + case LT_EXPR: + TREE_SET_CODE (arg, GE_EXPR); + return arg; + + case TRUTH_AND_EXPR: + return build (TRUTH_OR_EXPR, TREE_TYPE (arg), + build_unary_op (TRUTH_NOT_EXPR, + TREE_OPERAND (arg, 0), 0), + build_unary_op (TRUTH_NOT_EXPR, + TREE_OPERAND (arg, 1), 0)); + + case TRUTH_OR_EXPR: + return build (TRUTH_AND_EXPR, TREE_TYPE (arg), + build_unary_op (TRUTH_NOT_EXPR, + TREE_OPERAND (arg, 0), 0), + build_unary_op (TRUTH_NOT_EXPR, + TREE_OPERAND (arg, 1), 0)); + + case TRUTH_ANDIF_EXPR: + return build (TRUTH_ORIF_EXPR, TREE_TYPE (arg), + build_unary_op (TRUTH_NOT_EXPR, + TREE_OPERAND (arg, 0), 0), + build_unary_op (TRUTH_NOT_EXPR, + TREE_OPERAND (arg, 1), 0)); + + case TRUTH_ORIF_EXPR: + return build (TRUTH_ANDIF_EXPR, TREE_TYPE (arg), + build_unary_op (TRUTH_NOT_EXPR, + TREE_OPERAND (arg, 0), 0), + build_unary_op (TRUTH_NOT_EXPR, + TREE_OPERAND (arg, 1), 0)); + + case TRUTH_NOT_EXPR: + return TREE_OPERAND (arg, 0); + + case COND_EXPR: + return build (COND_EXPR, TREE_TYPE (arg), TREE_OPERAND (arg, 0), + build_unary_op (TRUTH_NOT_EXPR, TREE_OPERAND (arg, 1), 0), + build_unary_op (TRUTH_NOT_EXPR, TREE_OPERAND (arg, 2), 0)); + } + return 0; +} + +/* Mark EXP saying that we need to be able to take the + address of it; it should not be allocated in a register. + Value is 1 if successful. */ + +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 VAR_DECL: + case CONST_DECL: + case PARM_DECL: + case RESULT_DECL: + if (TREE_REGDECL (x) && !TREE_ADDRESSABLE (x)) + { + if (TREE_PUBLIC (x)) + { + error ("address of global register variable `%s' requested", + IDENTIFIER_POINTER (DECL_NAME (x))); + return 0; + } + warning ("address of register variable `%s' requested", + IDENTIFIER_POINTER (DECL_NAME (x))); + } + put_var_into_stack (x); + + /* drops in */ + case FUNCTION_DECL: + TREE_ADDRESSABLE (x) = 1; + TREE_ADDRESSABLE (DECL_NAME (x)) = 1; + + default: + return 1; + } +} + +/* Build and return a conditional expression IFEXP ? OP1 : OP2. */ + +tree +build_conditional_expr (ifexp, op1, op2) + tree ifexp, op1, op2; +{ + register tree type1; + register tree type2; + register enum tree_code code1; + register enum tree_code code2; + register tree result_type = NULL; + + /* 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) + warning ("ANSI C forbids omitting the middle term of a ?: expression"); + ifexp = op1 = save_expr (ifexp); + } + + ifexp = truthvalue_conversion (default_conversion (ifexp)); + + if (TREE_CODE (ifexp) == ERROR_MARK + || TREE_CODE (TREE_TYPE (op1)) == ERROR_MARK + || TREE_CODE (TREE_TYPE (op2)) == ERROR_MARK) + return error_mark_node; + +#if 0 /* Produces wrong result if within sizeof. */ + /* 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 (TREE_TYPE (op1) == TREE_TYPE (op2) + && TREE_CODE (TREE_TYPE (op1)) != ARRAY_TYPE + && TREE_CODE (TREE_TYPE (op1)) != ENUMERAL_TYPE + && TREE_CODE (TREE_TYPE (op1)) != FUNCTION_TYPE) + { + if (TREE_LITERAL (ifexp) + && (TREE_CODE (ifexp) == INTEGER_CST + || TREE_CODE (ifexp) == ADDR_EXPR)) + return (integer_zerop (ifexp) ? op2 : op1); + + return build (COND_EXPR, TREE_TYPE (op1), ifexp, op1, op2); + } +#endif + + /* They don't match; promote them both and then try to reconcile them. */ + + if (TREE_CODE (TREE_TYPE (op1)) != VOID_TYPE) + op1 = default_conversion (op1); + if (TREE_CODE (TREE_TYPE (op2)) != VOID_TYPE) + op2 = default_conversion (op2); + + type1 = TREE_TYPE (op1); + code1 = TREE_CODE (type1); + type2 = TREE_TYPE (op2); + code2 = TREE_CODE (type2); + + /* Quickly detect the usual case where op1 and op2 have the same type + after promotion. */ + if (type1 == type2) + result_type = type1; + else if ((code1 == INTEGER_TYPE || code1 == REAL_TYPE) + && (code2 == INTEGER_TYPE || code2 == REAL_TYPE)) + { + result_type = commontype (type1, type2); + } + else if (code1 == VOID_TYPE || code2 == VOID_TYPE) + { + if (pedantic && (code1 != VOID_TYPE || code2 != VOID_TYPE)) + warning ("ANSI C forbids conditional expr with only one void side"); + result_type = void_type_node; + } + else if (code1 == POINTER_TYPE && code2 == POINTER_TYPE) + { + if (comp_target_types (type1, type2)) + result_type = commontype (type1, type2); + else if (integer_zerop (op1) && TREE_TYPE (type1) == void_type_node) + result_type = qualify_type (type2, type1); + else if (integer_zerop (op2) && TREE_TYPE (type2) == void_type_node) + result_type = qualify_type (type1, type2); + else if (TYPE_MAIN_VARIANT (TREE_TYPE (type1)) == void_type_node) + { + if (pedantic && TREE_CODE (type2) == FUNCTION_TYPE) + warning ("ANSI C forbids conditional expr between `void *' and function pointer"); + result_type = qualify_type (type1, type2); + } + else if (TYPE_MAIN_VARIANT (TREE_TYPE (type2)) == void_type_node) + { + if (pedantic && TREE_CODE (type1) == FUNCTION_TYPE) + warning ("ANSI C forbids conditional expr between `void *' and function pointer"); + result_type = qualify_type (type2, type1); + } + else + { + warning ("pointer type mismatch in conditional expression"); + result_type = build_pointer_type (void_type_node); + } + } + else if (code1 == POINTER_TYPE && code2 == INTEGER_TYPE) + { + if (!integer_zerop (op2)) + warning ("pointer/integer type mismatch in conditional expression"); + else + { + op2 = null_pointer_node; +#if 0 /* The spec seems to say this is permitted. */ + if (pedantic && TREE_CODE (type1) == FUNCTION_TYPE) + warning ("ANSI C forbids conditional expr between 0 and function pointer"); +#endif + } + result_type = type1; + } + else if (code2 == POINTER_TYPE && code1 == INTEGER_TYPE) + { + if (!integer_zerop (op1)) + warning ("pointer/integer type mismatch in conditional expression"); + else + { + op1 = null_pointer_node; +#if 0 /* The spec seems to say this is permitted. */ + if (pedantic && TREE_CODE (type2) == FUNCTION_TYPE) + warning ("ANSI C forbids conditional expr between 0 and function pointer"); +#endif + } + result_type = type2; + } + + if (!result_type) + { + if (flag_cond_mismatch) + result_type = void_type_node; + else + { + error ("type mismatch in conditional expression"); + return error_mark_node; + } + } + + if (result_type != TREE_TYPE (op1)) + op1 = convert (result_type, op1); + if (result_type != TREE_TYPE (op2)) + op2 = convert (result_type, op2); + +#if 0 + if (code1 == RECORD_TYPE || code1 == UNION_TYPE) + { + result_type = TREE_TYPE (op1); + if (TREE_LITERAL (ifexp)) + return (integer_zerop (ifexp) ? op2 : op1); + + if (TYPE_MODE (result_type) == BLKmode) + { + register tree tempvar + = build_decl (VAR_DECL, NULL_TREE, result_type); + register tree xop1 = build_modify_expr (tempvar, op1); + register tree xop2 = build_modify_expr (tempvar, op2); + register tree result = build (COND_EXPR, result_type, + ifexp, xop1, xop2); + + layout_decl (tempvar); + /* No way to handle variable-sized objects here. + I fear that the entire handling of BLKmode conditional exprs + needs to be redone. */ + if (! TREE_LITERAL (DECL_SIZE (tempvar))) + abort (); + DECL_RTL (tempvar) + = assign_stack_local (DECL_MODE (tempvar), + (TREE_INT_CST_LOW (DECL_SIZE (tempvar)) + * DECL_SIZE_UNIT (tempvar) + + BITS_PER_UNIT - 1) + / BITS_PER_UNIT); + + TREE_VOLATILE (result) + = TREE_VOLATILE (ifexp) | TREE_VOLATILE (op1) + | TREE_VOLATILE (op2); + return build (COMPOUND_EXPR, result_type, result, tempvar); + } + } +#endif /* 0 */ + + if (TREE_CODE (ifexp) == INTEGER_CST) + return (integer_zerop (ifexp) ? op2 : op1); + + return build (COND_EXPR, result_type, ifexp, op1, op2); +} + +/* Given a list of expressions, return a compound expression + that performs them all and returns the value of the last of them. */ + +tree +build_compound_expr (list) + tree list; +{ + register tree rest; + + if (TREE_CHAIN (list) == 0) + { + /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue. + Strip such NOP_EXPRs, since LIST is used in non-lvalue context. */ + if (TREE_CODE (list) == NOP_EXPR + && TREE_TYPE (list) == TREE_TYPE (TREE_OPERAND (list, 0))) + list = TREE_OPERAND (list, 0); + + return TREE_VALUE (list); + } + + rest = build_compound_expr (TREE_CHAIN (list)); + + /* This is patched out so that sizeof (0, array) is distinguishable from + sizeof array. */ +#if 0 + if (! TREE_VOLATILE (TREE_VALUE (list))) + return rest; +#endif + + return build (COMPOUND_EXPR, TREE_TYPE (rest), TREE_VALUE (list), rest); +} + +/* Build an expression representing a cast to type TYPE of expression EXPR. */ + +tree +build_c_cast (type, expr) + register tree type; + tree expr; +{ + register tree value = expr; + + if (type == error_mark_node || expr == error_mark_node) + return error_mark_node; + type = TYPE_MAIN_VARIANT (type); + + /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue. + Strip such NOP_EXPRs, since VALUE is being used in non-lvalue context. */ + if (TREE_CODE (value) == NOP_EXPR + && TREE_TYPE (value) == TREE_TYPE (TREE_OPERAND (value, 0))) + value = TREE_OPERAND (value, 0); + + if (TREE_CODE (type) == ARRAY_TYPE) + { + error ("cast specifies array type"); + return error_mark_node; + } + + if (type == TREE_TYPE (value)) + { + if (pedantic) + { + if (TREE_CODE (type) == RECORD_TYPE + || TREE_CODE (type) == UNION_TYPE) + warning ("ANSI C forbids casting nonscalar to the same type"); + } + } + else + { + tree otype; + /* Convert functions and arrays to pointers, + but don't convert any other types. */ + if (TREE_CODE (TREE_TYPE (value)) == FUNCTION_TYPE + || TREE_CODE (TREE_TYPE (value)) == ARRAY_TYPE) + value = default_conversion (value); + otype = TREE_TYPE (value); + + /* Optionally warn about potentially worrysome casts. */ + + if (warn_cast_qual + && TREE_CODE (type) == POINTER_TYPE + && TREE_CODE (otype) == POINTER_TYPE) + { + if (TREE_VOLATILE (TREE_TYPE (otype)) + && ! TREE_VOLATILE (TREE_TYPE (type))) + warning ("cast discards `volatile' from pointer target type"); + if (TREE_READONLY (TREE_TYPE (otype)) + && ! TREE_READONLY (TREE_TYPE (type))) + warning ("cast discards `const' from pointer target type"); + } + + value = convert (type, value); + } + + if (value == expr) + { + /* Always produce some operator for an explicit cast, + so we can tell (for -pedantic) that the cast is no lvalue. */ + tree nvalue = build (NOP_EXPR, type, value); + TREE_LITERAL (nvalue) = TREE_LITERAL (value); + return nvalue; + } + return value; +} + +/* 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. */ + +tree +build_modify_expr (lhs, modifycode, rhs) + tree lhs, rhs; + enum tree_code modifycode; +{ + register tree result; + tree newrhs; + tree lhstype = TREE_TYPE (lhs); + tree olhstype = lhstype; + + /* Types that aren't fully specified cannot be used in assignments. */ + lhs = require_complete_type (lhs); + + /* Avoid duplicate error messages from operands that had errors. */ + if (TREE_CODE (lhs) == ERROR_MARK || TREE_CODE (rhs) == ERROR_MARK) + return error_mark_node; + + /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue. + Strip such NOP_EXPRs, since RHS is being used in non-lvalue context. */ + if (TREE_CODE (rhs) == NOP_EXPR + && TREE_TYPE (rhs) == TREE_TYPE (TREE_OPERAND (rhs, 0))) + rhs = TREE_OPERAND (rhs, 0); + + newrhs = rhs; + + /* Handle control structure constructs used as "lvalues". */ + + if (!pedantic) + switch (TREE_CODE (lhs)) + { + /* Handle (a, b) used as an "lvalue". */ + case COMPOUND_EXPR: + return build (COMPOUND_EXPR, lhstype, + TREE_OPERAND (lhs, 0), + build_modify_expr (TREE_OPERAND (lhs, 1), + modifycode, rhs)); + + /* Handle (a ? b : c) used as an "lvalue". */ + case COND_EXPR: + rhs = save_expr (rhs); + { + /* Produce (a ? (b = rhs) : (c = rhs)) + except that the RHS goes through a save-expr + so the code to compute it is only emitted once. */ + tree cond + = build_conditional_expr + (TREE_OPERAND (lhs, 0), + build_modify_expr (TREE_OPERAND (lhs, 1), + modifycode, rhs), + build_modify_expr (TREE_OPERAND (lhs, 2), + modifycode, rhs)); + /* Make sure the code to compute the rhs comes out + before the split. */ + return build (COMPOUND_EXPR, TREE_TYPE (lhs), + /* Cast to void to suppress warning + from warn_if_unused_value. */ + convert (void_type_node, rhs), + cond); + } + } + + /* 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 != NOP_EXPR) + { + lhs = stabilize_reference (lhs); + newrhs = build_binary_op (modifycode, lhs, rhs); + } + + /* Handle a cast used as an "lvalue". + We have already performed any binary operator using the value as cast. + Now convert the result to the true type of the lhs and store there; + then cast the result back to the specified type to be the value + of the assignment. */ + + if (!pedantic) + switch (TREE_CODE (lhs)) + { + 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: + if (TREE_CODE (TREE_TYPE (newrhs)) == ARRAY_TYPE + || TREE_CODE (TREE_TYPE (newrhs)) == FUNCTION_TYPE) + newrhs = default_conversion (newrhs); + { + tree inner_lhs = TREE_OPERAND (lhs, 0); + tree result = build_modify_expr (inner_lhs, NOP_EXPR, + convert (TREE_TYPE (inner_lhs), + newrhs)); + return convert (TREE_TYPE (lhs), result); + } + } + + /* Now we have handled acceptable kinds of LHS that are not truly lvalues. + Reject anything strange now. */ + + if (!lvalue_or_else (lhs, "assignment")) + return error_mark_node; + + /* Warn about storing in something that is `const'. */ + + if (TREE_READONLY (lhs) + || ((TREE_CODE (lhstype) == RECORD_TYPE + || TREE_CODE (lhstype) == UNION_TYPE) + && C_TYPE_FIELDS_READONLY (lhstype))) + readonly_warning (lhs, "assignment"); + + /* 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)); + + /* If storing in a field that is in actuality a short or narrower than one, + we must store in the field in its actual type. */ + + if (lhstype != TREE_TYPE (lhs)) + { + lhs = copy_node (lhs); + TREE_TYPE (lhs) = lhstype; + } + + /* Convert new value to destination type. */ + + newrhs = convert_for_assignment (lhstype, newrhs, "assignment"); + if (TREE_CODE (newrhs) == ERROR_MARK) + return error_mark_node; + + result = build (MODIFY_EXPR, lhstype, lhs, newrhs); + TREE_VOLATILE (result) = 1; + + /* If we got the LHS in a different type for storing in, + convert the result back to the nominal type of LHS + so that the value we return always has the same type + as the LHS argument. */ + + if (olhstype == TREE_TYPE (result)) + return result; + return convert_for_assignment (olhstype, result, "assignment"); +} + +/* 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; +{ + return 1; +} + +/* Convert value RHS to type TYPE as preparation for an assignment + to an lvalue of type TYPE. + The real work of conversion is done by `convert'. + The purpose of this function is to generate error messages + for assignments that are not allowed in C. + ERRTYPE is a string to use in error messages: + "assignment", "return", etc. */ + +static tree +convert_for_assignment (type, rhs, errtype) + tree type, rhs; + char *errtype; +{ + register enum tree_code codel = TREE_CODE (type); + register tree rhstype; + register enum tree_code coder; + + /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue. + Strip such NOP_EXPRs, since RHS is used in non-lvalue context. */ + if (TREE_CODE (rhs) == NOP_EXPR + && TREE_TYPE (rhs) == TREE_TYPE (TREE_OPERAND (rhs, 0))) + rhs = TREE_OPERAND (rhs, 0); + + if (TREE_CODE (TREE_TYPE (rhs)) == ARRAY_TYPE + || TREE_CODE (TREE_TYPE (rhs)) == FUNCTION_TYPE) + rhs = default_conversion (rhs); + + rhstype = TREE_TYPE (rhs); + coder = TREE_CODE (rhstype); + + if (coder == ERROR_MARK) + return error_mark_node; + + if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (rhstype)) + return rhs; + + if (coder == VOID_TYPE) + { + error ("void value not ignored as it ought to be"); + return error_mark_node; + } + /* Arithmetic types all interconvert, and enum is treated like int. */ + if ((codel == INTEGER_TYPE || codel == REAL_TYPE || codel == ENUMERAL_TYPE) + && + (coder == INTEGER_TYPE || coder == REAL_TYPE || coder == ENUMERAL_TYPE)) + { + return convert (type, rhs); + } + /* Conversions among pointers */ + else if (codel == POINTER_TYPE && coder == POINTER_TYPE) + { + register tree ttl = TREE_TYPE (type); + register tree ttr = TREE_TYPE (rhstype); + /* Any non-function converts to a [const][volatile] void * + and vice versa; otherwise, targets must be the same. + Meanwhile, the lhs target must have all the qualifiers of the rhs. */ + if (TYPE_MAIN_VARIANT (ttl) == void_type_node + || TYPE_MAIN_VARIANT (ttr) == void_type_node + || comp_target_types (type, rhstype)) + { + if (pedantic + && ((TYPE_MAIN_VARIANT (ttl) == void_type_node + && TREE_CODE (ttr) == FUNCTION_TYPE) + || + (TYPE_MAIN_VARIANT (ttr) == void_type_node + && TREE_CODE (ttl) == FUNCTION_TYPE))) + warning ("%s between incompatible pointer types", errtype); + else + { + if (! TREE_READONLY (ttl) && TREE_READONLY (ttr)) + warning ("%s of non-const * pointer from const *", errtype); + if (! TREE_VOLATILE (ttl) && TREE_VOLATILE (ttr)) + warning ("%s of non-volatile * pointer from volatile *", errtype); + } + } + else + warning ("%s between incompatible pointer types", errtype); + return convert (type, rhs); + } + else if (codel == POINTER_TYPE && coder == INTEGER_TYPE) + { + if (! integer_zerop (rhs)) + { + warning ("%s of pointer from integer lacks a cast", errtype); + return convert (type, rhs); + } + return null_pointer_node; + } + else if (codel == INTEGER_TYPE && coder == POINTER_TYPE) + { + warning ("%s of integer from pointer lacks a cast", errtype); + return convert (type, rhs); + } + + error ("incompatible types in %s", errtype); + return error_mark_node; +} + +/* Return nonzero if VALUE is a valid constant-valued expression + for use in initializing a static variable; one that can be an + element of a "constant" initializer. + + Return 1 if the value is absolute; return 2 if it is relocatable. + We assume that VALUE has been folded as much as possible; + therefore, we do not need to check for such things as + arithmetic-combinations of integers. */ + +static int +initializer_constant_valid_p (value) + tree value; +{ + switch (TREE_CODE (value)) + { + case CONSTRUCTOR: + return TREE_STATIC (value); + + case INTEGER_CST: + case REAL_CST: + case STRING_CST: + return 1; + + case ADDR_EXPR: + return 2; + + case CONVERT_EXPR: + case NOP_EXPR: + /* Allow conversions between types of the same kind. */ + if (TREE_CODE (TREE_TYPE (value)) + == TREE_CODE (TREE_TYPE (TREE_OPERAND (value, 0)))) + return initializer_constant_valid_p (TREE_OPERAND (value, 0)); + /* Allow (int) &foo. */ + if (TREE_CODE (TREE_TYPE (value)) == INTEGER_TYPE + && TREE_CODE (TREE_TYPE (TREE_OPERAND (value, 0))) == POINTER_TYPE) + return initializer_constant_valid_p (TREE_OPERAND (value, 0)); + return 0; + + case PLUS_EXPR: + { + int valid0 = initializer_constant_valid_p (TREE_OPERAND (value, 0)); + int valid1 = initializer_constant_valid_p (TREE_OPERAND (value, 1)); + if (valid0 == 1 && valid1 == 2) + return 2; + if (valid0 == 2 && valid1 == 1) + return 2; + return 0; + } + + case MINUS_EXPR: + { + int valid0 = initializer_constant_valid_p (TREE_OPERAND (value, 0)); + int valid1 = initializer_constant_valid_p (TREE_OPERAND (value, 1)); + if (valid0 == 2 && valid1 == 1) + return 2; + return 0; + } + } + + return 0; +} + +/* Perform appropriate conversions on the initial value of a variable, + store it in the declaration DECL, + and print any error messages that are appropriate. + If the init is invalid, store an ERROR_MARK. */ + +void +store_init_value (decl, init) + tree decl, init; +{ + register tree value, type; + + /* If variable's type was invalidly declared, just ignore it. */ + + type = TREE_TYPE (decl); + if (TREE_CODE (type) == ERROR_MARK) + return; + + /* Digest the specified initializer into an expression. */ + + value = digest_init (type, init, 0); + + /* Store the expression if valid; else report error. */ + + if (value == error_mark_node) + ; + else if (TREE_STATIC (decl) && ! TREE_LITERAL (value)) + { + error ("initializer for static variable is not constant"); + value = error_mark_node; + } + else if (TREE_STATIC (decl) + && ! initializer_constant_valid_p (value)) + { + error ("initializer for static variable uses complicated arithmetic"); + value = error_mark_node; + } + else + { + if (pedantic && TREE_CODE (value) == CONSTRUCTOR) + { + if (! TREE_LITERAL (value)) + warning ("aggregate initializer is not constant"); + else if (! TREE_STATIC (value)) + warning ("aggregate initializer uses complicated arithmetic"); + } + } + DECL_INITIAL (decl) = value; +} + +/* Digest the parser output INIT as an initializer for type TYPE. + Return a C expression of type TYPE to represent the initial value. + + If TAIL is nonzero, it points to a variable holding a list of elements + of which INIT is the first. We update the list stored there by + removing from the head all the elements that we use. + Normally this is only one; we use more than one element only if + TYPE is an aggregate and INIT is not a constructor. */ + +tree +digest_init (type, init, tail) + tree type, init, *tail; +{ + enum tree_code code = TREE_CODE (type); + tree element = 0; + tree old_tail_contents; + /* Nonzero if INIT is a braced grouping, which comes in as a CONSTRUCTOR + tree node which has no TREE_TYPE. */ + int raw_constructor + = TREE_CODE (init) == CONSTRUCTOR && TREE_TYPE (init) == 0; + + /* By default, assume we use one element from a list. + We correct this later in the sole case where it is not true. */ + + if (tail) + { + old_tail_contents = *tail; + *tail = TREE_CHAIN (*tail); + } + + if (init == error_mark_node) + return init; + + if (init && raw_constructor + && CONSTRUCTOR_ELTS (init) != 0 + && TREE_CHAIN (CONSTRUCTOR_ELTS (init)) == 0) + element = TREE_VALUE (CONSTRUCTOR_ELTS (init)); + + /* 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)); + if ((typ1 == char_type_node + || typ1 == signed_char_type_node + || typ1 == unsigned_char_type_node + || typ1 == unsigned_type_node + || typ1 == integer_type_node) + && ((init && TREE_CODE (init) == STRING_CST) + || (element && TREE_CODE (element) == STRING_CST))) + { + tree string = element ? element : init; + + if ((TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (string))) + != char_type_node) + && TYPE_PRECISION (typ1) == TYPE_PRECISION (char_type_node)) + { + error ("char-array initialized from wide string"); + return error_mark_node; + } + if ((TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (string))) + == char_type_node) + && TYPE_PRECISION (typ1) == TYPE_PRECISION (integer_type_node)) + { + error ("int-array initialized from non-wide string"); + return error_mark_node; + } + + TREE_TYPE (string) = type; + if (TYPE_DOMAIN (type) != 0 + && TREE_LITERAL (TYPE_SIZE (type))) + { + register int size + = TREE_INT_CST_LOW (TYPE_SIZE (type)) * TYPE_SIZE_UNIT (type); + size = (size + BITS_PER_UNIT - 1) / BITS_PER_UNIT; + /* Subtract 1 because it's ok to ignore the terminating null char + that is counted in the length of the constant. */ + if (size < TREE_STRING_LENGTH (string) - 1) + warning ("initializer-string for array of chars is too long"); + } + return string; + } + } + + /* Any type can be initialized from an expression of the same type, + optionally with braces. */ + + if (init && (TREE_TYPE (init) == type + || (code == ARRAY_TYPE && TREE_TYPE (init) + && comptypes (TREE_TYPE (init), type)))) + { + if (code == ARRAY_TYPE && TREE_CODE (init) != STRING_CST) + { + error ("array initialized from non-constant array expression"); + return error_mark_node; + } + if (optimize && TREE_READONLY (init) && TREE_CODE (init) == VAR_DECL) + return decl_constant_value (init); + return init; + } + + if (element && (TREE_TYPE (element) == type + || (code == ARRAY_TYPE && TREE_TYPE (element) + && comptypes (TREE_TYPE (element), type)))) + { + if (code == ARRAY_TYPE) + { + error ("array initialized from non-constant array expression"); + return error_mark_node; + } + if (pedantic && (code == RECORD_TYPE || code == UNION_TYPE)) + warning ("single-expression nonscalar initializer has braces"); + if (optimize && TREE_READONLY (element) && TREE_CODE (element) == VAR_DECL) + return decl_constant_value (element); + return element; + } + + /* Check for initializing a union by its first field. + Such an initializer must use braces. */ + + if (code == UNION_TYPE) + { + tree result; + + if (TYPE_FIELDS (type) == 0) + { + error ("union with no members cannot be initialized"); + return error_mark_node; + } + + if (raw_constructor) + return process_init_constructor (type, init, 0); + else if (tail != 0) + { + *tail = old_tail_contents; + return process_init_constructor (type, 0, tail); + } + } + + /* Handle scalar types, including conversions. */ + + if (code == INTEGER_TYPE || code == REAL_TYPE || code == POINTER_TYPE + || code == ENUMERAL_TYPE) + { + if (raw_constructor) + { + if (element == 0) + { + error ("initializer for scalar variable requires one element"); + return error_mark_node; + } + init = element; + } + + if (TREE_CODE (init) == CONSTRUCTOR) + { + error ("initializer for scalar has extra braces"); + return error_mark_node; + } + + return convert_for_assignment (type, default_conversion (init), + "initialization"); + } + + /* Come here only for records and arrays. */ + + if (TYPE_SIZE (type) && ! TREE_LITERAL (TYPE_SIZE (type))) + { + error ("variable-sized object may not be initialized"); + return error_mark_node; + } + + if (code == ARRAY_TYPE || code == RECORD_TYPE) + { + if (raw_constructor) + return process_init_constructor (type, init, 0); + 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); + } + + error ("invalid initializer"); + return error_mark_node; +} + +/* Process a constructor for a variable of type TYPE. + The constructor elements may be specified either with INIT or with ELTS, + only one of which should be non-null. + + If INIT is specified, it is a CONSTRUCTOR node which is specifically + and solely for initializing this datum. + + If ELTS is specified, it is the address of a variable containing + a list of expressions. We take as many elements as we need + from the head of the list and update the list. + + In the resulting constructor, TREE_LITERAL is set if all elts are + constant, and TREE_STATIC is set if, in addition, all elts are simple enough + constants that the assembler and linker can compute them. */ + +static tree +process_init_constructor (type, init, elts) + tree type, init, *elts; +{ + register tree tail; + /* List of the elements of the result constructor, + in reverse order. */ + register tree members = NULL; + tree result; + int allconstant = 1; + int allsimple = 1; + int error_flag = 0; + + /* Make TAIL be the list of elements to use for the initialization, + no matter how the data was given to us. */ + + if (elts) + tail = *elts; + else + tail = CONSTRUCTOR_ELTS (init); + + /* Gobble as many elements as needed, and make a constructor or initial value + for each element of this aggregate. Chain them together in result. + If there are too few, use 0 for each scalar ultimate component. */ + + if (TREE_CODE (type) == ARRAY_TYPE) + { + tree domain = TYPE_DOMAIN (type); + register long len; + register int i; + + if (domain) + len = TREE_INT_CST_LOW (TYPE_MAX_VALUE (domain)) + - TREE_INT_CST_LOW (TYPE_MIN_VALUE (domain)) + + 1; + else + len = -1; /* Take as many as there are */ + + for (i = 0; (len < 0 || i < len) && tail != 0; i++) + { + register tree next1; + + if (TREE_VALUE (tail) != 0) + { + tree tail1 = tail; + next1 = digest_init (TYPE_MAIN_VARIANT (TREE_TYPE (type)), + TREE_VALUE (tail), &tail1); + if (tail1 != 0 && TREE_CODE (tail1) != TREE_LIST) + abort (); + if (tail == tail1 && len < 0) + { + error ("non-empty initializer for array of empty elements"); + /* Just ignore what we were supposed to use. */ + tail1 = 0; + } + tail = tail1; + } + else + { + next1 = error_mark_node; + tail = TREE_CHAIN (tail); + } + + if (next1 == error_mark_node) + error_flag = 1; + else if (!TREE_LITERAL (next1)) + allconstant = 0; + else if (! initializer_constant_valid_p (next1)) + allsimple = 0; + members = tree_cons (NULL_TREE, next1, members); + } + } + if (TREE_CODE (type) == RECORD_TYPE) + { + register tree field; + + for (field = TYPE_FIELDS (type); field && tail; + field = TREE_CHAIN (field)) + { + register tree next1; + + if (! DECL_NAME (field)) + { + members = tree_cons (field, integer_zero_node, members); + continue; + } + + if (TREE_VALUE (tail) != 0) + { + tree tail1 = tail; + next1 = digest_init (TREE_TYPE (field), + TREE_VALUE (tail), &tail1); + if (tail1 != 0 && TREE_CODE (tail1) != TREE_LIST) + abort (); + tail = tail1; + } + else + { + next1 = error_mark_node; + tail = TREE_CHAIN (tail); + } + + if (next1 == error_mark_node) + error_flag = 1; + else if (!TREE_LITERAL (next1)) + allconstant = 0; + else if (! initializer_constant_valid_p (next1)) + allsimple = 0; + members = tree_cons (field, next1, members); + } + } + + if (TREE_CODE (type) == UNION_TYPE) + { + register tree field = TYPE_FIELDS (type); + register tree next1; + + /* For a union, get the initializer for 1 fld. */ + + if (TREE_VALUE (tail) != 0) + { + tree tail1 = tail; + next1 = digest_init (TREE_TYPE (field), + TREE_VALUE (tail), &tail1); + if (tail1 != 0 && TREE_CODE (tail1) != TREE_LIST) + abort (); + tail = tail1; + } + else + { + next1 = error_mark_node; + tail = TREE_CHAIN (tail); + } + + if (next1 == error_mark_node) + error_flag = 1; + else if (!TREE_LITERAL (next1)) + allconstant = 0; + else if (! initializer_constant_valid_p (next1)) + allsimple = 0; + members = tree_cons (field, next1, members); + } + + /* If arguments were specified as a list, just remove the ones we used. */ + if (elts) + *elts = tail; + /* If arguments were specified as a constructor, + complain unless we used all the elements of the constructor. */ + else if (tail) + warning ("excess elements in aggregate initializer"); + + if (error_flag) + return error_mark_node; + + result = build (CONSTRUCTOR, type, NULL_TREE, nreverse (members)); + if (allconstant) TREE_LITERAL (result) = 1; + if (allconstant && allsimple) TREE_STATIC (result) = 1; + return result; +} + +/* Expand an ASM statement with operands, handling output operands + that are not variables or INDIRECT_REFS by transforming such + cases into cases that expand_asm_operands can handle. + + Arguments are same as for expand_asm_operands. */ + +void +c_expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line) + tree string, outputs, inputs, clobbers; + int vol; + char *filename; + int line; +{ + int noutputs = list_length (outputs); + register int i; + /* o[I] is the place that output number I should be written. */ + register tree *o = (tree *) alloca (noutputs * sizeof (tree)); + register tree tail; + + /* Record the contents of OUTPUTS before it is modifed. */ + for (i = 0, tail = outputs; tail; tail = TREE_CHAIN (tail), i++) + o[i] = TREE_VALUE (tail); + +#if 0 /* Don't do this--it screws up operands expected to be in memory. */ + /* Perform default conversions on all inputs. */ + for (i = 0, tail = inputs; tail; tail = TREE_CHAIN (tail), i++) + TREE_VALUE (tail) = default_conversion (TREE_VALUE (tail)); +#endif + + /* Generate the ASM_OPERANDS insn; + store into the TREE_VALUEs of OUTPUTS some trees for + where the values were actually stored. */ + expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line); + + /* Copy all the intermediate outputs into the specified outputs. */ + for (i = 0, tail = outputs; tail; tail = TREE_CHAIN (tail), i++) + { + if (o[i] != TREE_VALUE (tail)) + expand_expr (build_modify_expr (o[i], NOP_EXPR, TREE_VALUE (tail)), + 0, VOIDmode, 0); + /* Detect modification of read-only values. + (Otherwise done by build_modify_expr.) */ + else + { + tree type = TREE_TYPE (o[i]); + if (TREE_READONLY (o[i]) + || ((TREE_CODE (type) == RECORD_TYPE + || TREE_CODE (type) == UNION_TYPE) + && C_TYPE_FIELDS_READONLY (type))) + readonly_warning (o[i], "modification by `asm'"); + } + } + + /* Those MODIFY_EXPRs could do autoincrements. */ + emit_queue (); +} + +/* Expand a C `return' statement. + RETVAL is the expression for what to return, + or a null pointer for `return;' with no value. */ + +void +c_expand_return (retval) + tree retval; +{ + tree valtype = TREE_TYPE (TREE_TYPE (current_function_decl)); + + if (TREE_THIS_VOLATILE (current_function_decl)) + warning ("function declared `volatile' has a `return' statement"); + + if (!retval) + { + current_function_returns_null = 1; + if (warn_return_type && valtype != 0 && TREE_CODE (valtype) != VOID_TYPE) + warning ("`return' with no value, in function returning non-void"); + expand_null_return (); + } + else if (valtype == 0 || TREE_CODE (valtype) == VOID_TYPE) + { + current_function_returns_null = 1; + if (pedantic || TREE_CODE (TREE_TYPE (retval)) != VOID_TYPE) + warning ("`return' with a value, in function returning void"); + expand_return (retval); + } + else + { + tree t = convert_for_assignment (valtype, retval, "return"); + tree res = DECL_RESULT (current_function_decl); + t = build (MODIFY_EXPR, TREE_TYPE (res), + res, convert (TREE_TYPE (res), t)); + expand_return (t); + current_function_returns_value = 1; + } +} + +/* Start a C switch statement, testing expression EXP. + Return EXP if it is valid, an error node otherwise. */ + +tree +c_expand_start_case (exp) + tree exp; +{ + register enum tree_code code = TREE_CODE (TREE_TYPE (exp)); + tree type = TREE_TYPE (exp); + + if (code != INTEGER_TYPE && code != ENUMERAL_TYPE && code != ERROR_MARK) + { + error ("switch quantity not an integer"); + exp = error_mark_node; + } + else + { + tree index; + + exp = default_conversion (exp); + type = TREE_TYPE (exp); + index = 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; + } + + expand_start_case (1, exp, type); + + return exp; +} diff --git a/gcc-1.40/caller-save.c b/gcc-1.40/caller-save.c new file mode 100644 index 0000000..9a91a56 --- /dev/null +++ b/gcc-1.40/caller-save.c @@ -0,0 +1,666 @@ +/* Save and restore call-clobbered registers which are live across a call. + Copyright (C) 1989 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 1, 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 "rtl.h" +#include "insn-config.h" +#include "flags.h" +#include "regs.h" +#include "hard-reg-set.h" +#include "reload.h" +#include "recog.h" +#include "basic-block.h" + +/* Set of hard regs currently live (during scan of all insns). */ + +static HARD_REG_SET hard_regs_live; + +/* The block of storage on the stack where regs are saved */ + +static rtx save_block_addr; +static int save_block_size; + +/* A REG rtx for each hard register that has been saved. */ + +static rtx save_reg_rtx[FIRST_PSEUDO_REGISTER]; + +static void set_reg_live (); +static void clear_reg_live (); +static void insert_call_saves (); +static void emit_mult_save (); +static void emit_mult_restore (); +static rtx grow_save_block (); +static enum machine_mode choose_hard_reg_mode (); + +/* Find the places where hard regs are live across calls and save them. */ + +save_call_clobbered_regs () +{ + rtx insn; + int b; + + if (obey_regdecls) + return; + + save_block_size = 0; + save_block_addr = 0; + bzero (save_reg_rtx, sizeof save_reg_rtx); + + for (b = 0; b < n_basic_blocks; b++) + { + regset regs_live = basic_block_live_at_start[b]; + int offset, bit, i; + + /* Compute hard regs live at start of block -- this is the + real hard regs marked live, plus live pseudo regs that + have been renumbered to hard regs. */ + +#ifdef HARD_REG_SET + hard_regs_live = *regs_live; +#else + COPY_HARD_REG_SET (hard_regs_live, regs_live); +#endif + + for (offset = 0, i = 0; offset < regset_size; offset++) + { + if (regs_live[offset] == 0) + i += HOST_BITS_PER_INT; + else + for (bit = 1; bit && i < max_regno; bit <<= 1, i++) + if ((regs_live[offset] & bit) && reg_renumber[i] >= 0) + SET_HARD_REG_BIT (hard_regs_live, reg_renumber[i]); + } + + /* 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 + call-clobbered hard regs. */ + + for (insn = basic_block_head[b]; TRUE; insn = NEXT_INSN (insn)) + { + RTX_CODE code = GET_CODE (insn); + + if (code == CALL_INSN) + insert_call_saves (insn); + + if (code == INSN || code == CALL_INSN || code == JUMP_INSN) + { + rtx link; + + /* NB: the normal procedure is to first enliven any + registers set by insn, then deaden any registers that + had their last use at insn. This is incorrect now, + since multiple pseudos may have been mapped to the + same hard reg, and the death notes are ambiguous. So + it must be done in the other, safe, order. */ + + for (link = REG_NOTES (insn); link; link = XEXP (link, 1)) + if (REG_NOTE_KIND (link) == REG_DEAD) + clear_reg_live (XEXP (link, 0)); + + note_stores (PATTERN (insn), set_reg_live); + } + + if (insn == basic_block_end[b]) + break; + } + } +} + +/* Here from note_stores when an insn stores a value in a register. + Set the proper bit or bits in hard_regs_live. */ + +static void +set_reg_live (reg, setter) + rtx reg, setter; +{ + register int regno; + + /* WORD is which word of a multi-register group is being stored. + For the case where the store is actually into a SUBREG of REG. + Except we don't use it; I believe the entire REG needs to be + live. */ + int word = 0; + + if (GET_CODE (reg) == SUBREG) + { + word = SUBREG_WORD (reg); + reg = SUBREG_REG (reg); + } + + if (GET_CODE (reg) != REG) + return; + + regno = REGNO (reg); + + /* For pseudo reg, see if it has been assigned a hardware reg. */ + if (reg_renumber[regno] >= 0) + regno = reg_renumber[regno] /* + word */; + + /* Handle hardware regs (and pseudos allocated to hard regs). */ + if (regno < FIRST_PSEUDO_REGISTER && ! call_fixed_regs[regno]) + { + register int last = regno + HARD_REGNO_NREGS (regno, GET_MODE (reg)); + while (regno < last) + { + SET_HARD_REG_BIT (hard_regs_live, regno); + regno++; + } + } +} + +/* Here when a REG_DEAD note records the last use of a reg. Clear + the appropriate bit or bits in hard_regs_live. */ + +static void +clear_reg_live (reg) + rtx reg; +{ + register int regno = REGNO (reg); + + /* For pseudo reg, see if it has been assigned a hardware reg. */ + if (reg_renumber[regno] >= 0) + regno = reg_renumber[regno]; + + /* Handle hardware regs (and pseudos allocated to hard regs). */ + if (regno < FIRST_PSEUDO_REGISTER && ! call_fixed_regs[regno]) + { + /* Pseudo regs already assigned hardware regs are treated + almost the same as explicit hardware regs. */ + register int last = regno + HARD_REGNO_NREGS (regno, GET_MODE (reg)); + while (regno < last) + { + CLEAR_HARD_REG_BIT (hard_regs_live, regno); + regno++; + } + } +} + +/* Insert insns to save and restore live call-clobbered regs around + call insn INSN. */ + +static void +insert_call_saves (insn) + rtx insn; +{ + int regno; + int save_block_size_needed; + int save_block_offset[FIRST_PSEUDO_REGISTER]; + + save_block_size_needed = 0; + + for (regno = 0; regno < FIRST_PSEUDO_REGISTER; ++regno) + { + save_block_offset[regno] = -1; + if (call_used_regs[regno] && ! call_fixed_regs[regno] + && TEST_HARD_REG_BIT (hard_regs_live, regno)) + { + enum machine_mode mode = choose_hard_reg_mode (regno); + int align = GET_MODE_UNIT_SIZE (mode); + if (align > BIGGEST_ALIGNMENT / BITS_PER_UNIT) + align = BIGGEST_ALIGNMENT / BITS_PER_UNIT; + save_block_size_needed = + ((save_block_size_needed + align - 1) / align) * align; + save_block_offset[regno] = save_block_size_needed; + save_block_size_needed += GET_MODE_SIZE (mode); + if (! save_reg_rtx[regno]) + save_reg_rtx[regno] = gen_rtx (REG, mode, regno); + } + } + + if (save_block_size < save_block_size_needed) + save_block_addr = grow_save_block (save_block_addr, + save_block_size_needed); + emit_mult_save (insn, save_block_addr, save_block_offset); + emit_mult_restore (insn, save_block_addr, save_block_offset); +} + +/* Emit a string of stores to save the hard regs listed in + OFFSET[] at address ADDR. Emit them before INSN. + OFFSET[reg] is -1 if reg should not be saved, or a + suitably-aligned offset from ADDR. + The offsets actually used do not have to be those listed + in OFFSET, but should fit in a block of the same size. */ + +static void +emit_mult_save (insn, addr, offset) + rtx insn, addr; + int offset[]; +{ + int regno; + /* A register to use as a temporary for address calculations. */ + rtx tempreg; + /* A register that could be used as that temp if we save and restore it. */ + rtx can_push_reg; + /* Nonzero means we need to save a register to use it as TEMPREG. */ + int needpush; + /* The amount the stack is decremented to save that register (if we do). */ + int decrement; + /* Record which regs we save, in case we branch to retry. */ + char already_saved[FIRST_PSEUDO_REGISTER]; + + bzero (already_saved, sizeof already_saved); + + /* Hair is needed because sometimes the addresses to save in are + not valid (offsets too big). + So we need a reg, TEMPREG, to compute addresses in. + + We look first for an empty reg to use. + Sometimes no reg is empty. Then we push a reg, use it, and pop it. + + Sometimes the only reg to push and pop this way is one we want to save. + We can't save it while using it as a temporary. + So we save all the other registers, pop it, and go back to `retry'. + At that point, only this reg remains to be saved; + all the others already saved are empty. + So one of them can be the temporary for this one. */ + + /* Sometimes we can't save all the regs conveniently at once, just some. + If that happens, we branch back here to save the rest. */ + retry: + needpush = 0; + tempreg = 0; + can_push_reg = 0; + + /* Set NEEDPUSH if any save-addresses are not valid memory addresses. + If any register is available, record it in TEMPREG. + If any register doesn't need saving here, record it in CAN_PUSH_REG. */ + for (regno = 0; regno < FIRST_PSEUDO_REGISTER; ++regno) + { + if (offset[regno] >= 0 && ! already_saved[regno]) + { + rtx reg = save_reg_rtx[regno]; + rtx addr1 = plus_constant (addr, offset[regno]); + if (memory_address_p (GET_MODE (reg), addr1)) + needpush = 1; + } + + /* A call-clobbered reg that is dead, or already saved, + can be used as a temporary for sure, at no extra cost. */ + if (tempreg == 0 && call_used_regs[regno] && ! fixed_regs[regno] + && !(offset[regno] >= 0 && ! already_saved[regno]) + && HARD_REGNO_MODE_OK (regno, Pmode)) + { + tempreg = gen_rtx (REG, Pmode, regno); + /* Don't use it if not valid for addressing. */ + if (! strict_memory_address_p (QImode, tempreg)) + tempreg = 0; + } + + /* A call-saved reg can be a temporary if we push and pop it. */ + if (can_push_reg == 0 && ! call_used_regs[regno] + && HARD_REGNO_MODE_OK (regno, Pmode)) + { + can_push_reg = gen_rtx (REG, Pmode, regno); + /* Don't use it if not valid for addressing. */ + if (! strict_memory_address_p (QImode, can_push_reg)) + can_push_reg = 0; + } + } + + /* Clear NEEDPUSH if we already found an empty reg. */ + if (tempreg != 0) + needpush = 0; + + /* If we need a temp reg and none is free, make one free. */ + if (needpush) + { + /* Choose a reg, preferably not among those it is our job to save. */ + if (can_push_reg != 0) + tempreg = can_push_reg; + else + { + for (regno = 0; regno < FIRST_PSEUDO_REGISTER; ++regno) + if (offset[regno] >= 0 && !already_saved[regno] + && HARD_REGNO_MODE_OK (regno, Pmode)) + { + tempreg = gen_rtx (REG, Pmode, regno); + /* Don't use it if not valid for addressing. */ + if (! strict_memory_address_p (QImode, tempreg)) + tempreg = 0; + else + break; + } + } + + /* Push it on the stack. */ +#ifdef STACK_GROWS_DOWNWARD + decrement = UNITS_PER_WORD; +#else + decrement = - UNITS_PER_WORD; +#endif + + emit_insn_before (gen_add2_insn (stack_pointer_rtx, + gen_rtx (CONST_INT, VOIDmode, -decrement)), + insn); + emit_insn_before (gen_move_insn (gen_rtx (MEM, Pmode, stack_pointer_rtx), + tempreg), + insn); + } + + /* Save the regs we are supposed to save, aside from TEMPREG. + Use TEMPREG for address calculations when needed. */ + for (regno = 0; regno < FIRST_PSEUDO_REGISTER; ++regno) + if (offset[regno] >= 0 && ! already_saved[regno] + && tempreg != 0 && REGNO (tempreg) != regno) + { + rtx reg = save_reg_rtx[regno]; + rtx addr1 = plus_constant (addr, offset[regno]); + rtx temp; + if (! memory_address_p (GET_MODE (reg), addr1)) + { + if (GET_CODE (addr1) != PLUS) + abort (); + if (GET_CODE (XEXP (addr1, 1)) != CONST_INT + || GET_CODE (XEXP (addr1, 0)) != REG) + abort (); + emit_insn_before (gen_move_insn (tempreg, XEXP (addr1, 0)), insn); + emit_insn_before (gen_add2_insn (tempreg, XEXP (addr1, 1)), insn); + addr1 = tempreg; + } + temp = gen_rtx (MEM, GET_MODE (reg), addr1); + emit_insn_before (gen_move_insn (temp, reg), insn); + already_saved[regno] = 1; + } + + /* If we pushed TEMPREG to make it free, pop it. */ + if (needpush) + { + emit_insn_before (gen_move_insn (tempreg, + gen_rtx (MEM, Pmode, stack_pointer_rtx)), + insn); + emit_insn_before (gen_add2_insn (stack_pointer_rtx, + gen_rtx (CONST_INT, VOIDmode, decrement)), + insn); + } + + /* If TEMPREG itself needs saving, go back and save it. + There are plenty of free regs now, those already saved. */ + if (tempreg != 0 + && offset[REGNO (tempreg)] >= 0 && ! already_saved[REGNO (tempreg)]) + goto retry; +} + +/* Emit a string of loads to restore the hard regs listed in + OFFSET[] from address ADDR; insert the loads after INSN. + OFFSET[reg] is -1 if reg should not be loaded, or a + suitably-aligned offset from ADDR. + The offsets actually used do not need to be those provided in + OFFSET, but should agree with whatever emit_mult_save does. */ + +static void +emit_mult_restore (insn, addr, offset) + rtx insn, addr; + int offset[]; +{ + int regno; + + /* Number of regs now needing to be restored. */ + int restore_count; + /* A register to use as a temporary for address calculations. */ + rtx tempreg; + /* A register available for that purpose but less desirable. */ + rtx maybe_tempreg; + /* A register that could be used as that temp if we push and pop it. */ + rtx can_push_reg; + /* Nonzero means we need to push and pop a register to use it as TEMPREG. */ + int needpush; + /* The amount the stack is decremented to save that register (if we do). */ + int decrement; + /* Record which regs we restore, in case we branch to retry. */ + char already_restored[FIRST_PSEUDO_REGISTER]; + + bzero (already_restored, sizeof already_restored); + + /* Note: INSN can't be the last insn, since if it were, + no regs would live across it. */ + insn = NEXT_INSN (insn); + if (insn == 0) + abort (); + /* Now we can insert before INSN. + That is convenient because we can insert them in the order + that they should ultimately appear. */ + + /* Hair is needed because sometimes the addresses to restore from are + not valid (offsets too big). + So we need a reg, TEMPREG, to compute addresses in. + + We look first for an empty reg to use. + Sometimes no reg is empty. Then we push a reg, use it, and pop it. + + If all the suitable regs need to be restored, + that strategy won't work. So we restore all but one, using that one + as a temporary. Then we jump to `retry' to restore that one, + pushing and popping another (already restored) as a temporary. */ + + retry: + needpush = 0; + tempreg = 0; + can_push_reg = 0; + restore_count = 0; + + /* Set NEEDPUSH if any restore-addresses are not valid memory addresses. + If any register is available, record it in TEMPREG. + Otherwise, one register yet to be restored goes in MAYBE_TEMPREG, + and can be used as TEMPREG for any other regs to be restored. + If any register doesn't need restoring, record it in CAN_PUSH_REG. */ + for (regno = 0; regno < FIRST_PSEUDO_REGISTER; ++regno) + { + if (offset[regno] >= 0 && ! already_restored[regno]) + { + rtx reg = save_reg_rtx[regno]; + rtx addr1 = plus_constant (addr, offset[regno]); + + restore_count++; + + if (memory_address_p (GET_MODE (reg), addr1)) + needpush = 1; + + /* Find a call-clobbered reg that needs restoring. + We can use it as a temporary if we defer restoring it. */ + if (maybe_tempreg == 0) + { + maybe_tempreg = gen_rtx (REG, Pmode, regno); + /* Don't use it if not valid for addressing. */ + if (! strict_memory_address_p (QImode, maybe_tempreg)) + maybe_tempreg = 0; + } + } + + /* If any call-clobbered reg is dead, put it in TEMPREG. + It can be used as a temporary at no extra cost. */ + if (tempreg == 0 && call_used_regs[regno] && ! fixed_regs[regno] + && ! offset[regno] >= 0 + && HARD_REGNO_MODE_OK (regno, Pmode)) + { + tempreg = gen_rtx (REG, Pmode, regno); + /* Don't use it if not valid for addressing. */ + if (! strict_memory_address_p (QImode, tempreg)) + tempreg = 0; + } + + /* Any non-call-clobbered reg, put in CAN_PUSH_REG. + It can be used as a temporary if we push and pop it. */ + if (can_push_reg == 0 && ! call_used_regs[regno] + && HARD_REGNO_MODE_OK (regno, Pmode)) + { + can_push_reg = gen_rtx (REG, Pmode, regno); + /* Don't use it if not valid for addressing. */ + if (! strict_memory_address_p (QImode, can_push_reg)) + can_push_reg = 0; + } + /* Any reg we already restored can be a temporary + if we push and pop it. */ + if (can_push_reg == 0 && already_restored[regno] + && HARD_REGNO_MODE_OK (regno, Pmode)) + { + can_push_reg = gen_rtx (REG, Pmode, regno); + /* Don't use it if not valid for addressing. */ + if (! strict_memory_address_p (QImode, can_push_reg)) + can_push_reg = 0; + } + } + + /* If 2 or more regs need to be restored, use one as a temp reg + for the rest (if we need a tempreg). */ + if (tempreg == 0 && maybe_tempreg != 0 && restore_count > 1) + tempreg = maybe_tempreg; + + /* Clear NEEDPUSH if we already found an empty reg. */ + if (tempreg != 0) + needpush = 0; + + /* If we need a temp reg and none is free, make one free. */ + if (needpush) + { + tempreg = can_push_reg; + + /* Push it on the stack. */ +#ifdef STACK_GROWS_DOWNWARD + decrement = UNITS_PER_WORD; +#else + decrement = - UNITS_PER_WORD; +#endif + + emit_insn_before (gen_add2_insn (stack_pointer_rtx, + gen_rtx (CONST_INT, VOIDmode, -decrement)), + insn); + emit_insn_before (gen_move_insn (gen_rtx (MEM, Pmode, stack_pointer_rtx), + tempreg), + insn); + } + + /* Restore the regs we are supposed to restore, aside from TEMPREG. + Use TEMPREG for address calculations when needed. */ + for (regno = 0; regno < FIRST_PSEUDO_REGISTER; ++regno) + if (offset[regno] >= 0 && ! already_restored[regno] + && tempreg != 0 && REGNO (tempreg) != regno) + { + rtx reg = save_reg_rtx[regno]; + rtx addr1 = plus_constant (addr, offset[regno]); + rtx temp; + if (! memory_address_p (GET_MODE (reg), addr1)) + { + if (GET_CODE (addr1) != PLUS) + abort (); + if (GET_CODE (XEXP (addr1, 1)) != CONST_INT + || GET_CODE (XEXP (addr1, 0)) != REG) + abort (); + emit_insn_before (gen_move_insn (tempreg, XEXP (addr1, 0)), insn); + emit_insn_before (gen_add2_insn (tempreg, XEXP (addr1, 1)), insn); + addr1 = tempreg; + } + temp = gen_rtx (MEM, GET_MODE (reg), addr1); + emit_insn_before (gen_move_insn (reg, temp), insn); + already_restored[regno] = 1; + } + + /* If we pushed TEMPREG to make it free, pop it. */ + if (needpush) + { + emit_insn_before (gen_move_insn (tempreg, + gen_rtx (MEM, Pmode, stack_pointer_rtx)), + insn); + emit_insn_before (gen_add2_insn (stack_pointer_rtx, + gen_rtx (CONST_INT, VOIDmode, decrement)), + insn); + } + + /* If TEMPREG itself needs restoring, go back and restore it. + We can find a reg already restored to push and use as a temporary. */ + if (tempreg != 0 + && offset[REGNO (tempreg)] >= 0 && ! already_restored[REGNO (tempreg)]) + goto retry; +} + +/* Return the address of a new block of size SIZE on the stack. + The old save block is at ADDR; ADDR is 0 if no block exists yet. */ + +static rtx +grow_save_block (addr, size) + rtx addr; + int size; +{ + rtx newaddr; + + /* Keep the size a multiple of the main allocation unit. */ + size = (((size + (BIGGEST_ALIGNMENT / BITS_PER_UNIT) - 1) + / (BIGGEST_ALIGNMENT / BITS_PER_UNIT)) + * (BIGGEST_ALIGNMENT / BITS_PER_UNIT)); + + /* If no save block exists yet, create one and return it. */ + if (! addr) + { + save_block_size = size; + return XEXP (assign_stack_local (BLKmode, size), 0); + } + + /* Get a new block and coalesce it with the old one. */ + newaddr = XEXP (assign_stack_local (BLKmode, size - save_block_size), 0); + if (GET_CODE (newaddr) == PLUS + && XEXP (newaddr, 0) == frame_pointer_rtx + && GET_CODE (XEXP (newaddr, 1)) == CONST_INT + && GET_CODE (addr) == PLUS + && XEXP (addr, 0) == frame_pointer_rtx + && GET_CODE (XEXP (addr, 1)) == CONST_INT + && ((INTVAL (XEXP (newaddr, 1)) - INTVAL (XEXP (addr, 1)) + == size - save_block_size) + || (INTVAL (XEXP (addr, 1)) - INTVAL (XEXP (newaddr, 1)) + == size - save_block_size))) + { + save_block_size = size; + if (INTVAL (XEXP (newaddr, 1)) < INTVAL (XEXP (addr, 1))) + return newaddr; + else + return addr; + } + + /* They didn't coalesce, find out why */ + abort (); + + save_block_size = size; + return XEXP (assign_stack_local (BLKmode, size), 0); +} + +/* Return a machine mode that is legitimate for hard reg REGNO + and large enough to save the whole register. */ + +static enum machine_mode +choose_hard_reg_mode (regno) + int regno; +{ + enum reg_class class = REGNO_REG_CLASS (regno); + + if (CLASS_MAX_NREGS (class, DImode) == 1 + && HARD_REGNO_MODE_OK (regno, DImode)) + return DImode; + else if (CLASS_MAX_NREGS (class, DFmode) == 1 + && HARD_REGNO_MODE_OK (regno, DFmode)) + return DFmode; + else if (CLASS_MAX_NREGS (class, SImode) == 1 + && HARD_REGNO_MODE_OK (regno, SImode)) + return SImode; + else if (CLASS_MAX_NREGS (class, SFmode) == 1 + && HARD_REGNO_MODE_OK (regno, SFmode)) + return SFmode; + else if (CLASS_MAX_NREGS (class, HImode) == 1 + && HARD_REGNO_MODE_OK (regno, HImode)) + return HImode; + else + abort (); +} diff --git a/gcc-1.40/cccp.c b/gcc-1.40/cccp.c new file mode 100644 index 0000000..d57c9fb --- /dev/null +++ b/gcc-1.40/cccp.c @@ -0,0 +1,5795 @@ +/* C Compatible Compiler Preprocessor (CCCP) +Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc. + Written 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 +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. + +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, 675 Mass Ave, Cambridge, MA 02139, 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 */ + +#ifndef EMACS +#include "config.h" +#endif /* not EMACS */ + +#ifndef CC_INCLUDE_DIR +#define CC_INCLUDE_DIR "/usr/include" +#endif + +#ifndef STDC_VALUE +#define STDC_VALUE 1 +#endif + +/* In case config.h defines these. */ +#undef bcopy +#undef bzero +#undef bcmp + +#include +#include +#include +#include +#include + +#ifndef VMS +#include +#ifndef USG +#include /* for __DATE__ and __TIME__ */ +#include +#else +#define index strchr +#define rindex strrchr +#include +#include +#endif /* USG */ +#endif /* not VMS */ + +/* VMS-specific definitions */ +#ifdef VMS +#include +#include /* This defines "errno" properly */ +#include /* This defines sys_errlist/sys_nerr properly */ +#define O_RDONLY 0 /* Open arg for Read/Only */ +#define O_WRONLY 1 /* Open arg for Write/Only */ +#define read(fd,buf,size) VAX11_C_read(fd,buf,size) +#define write(fd,buf,size) VAX11_C_write(fd,buf,size) +#ifdef __GNUC__ +#define BSTRING /* VMS/GCC supplies the bstring routines */ +#endif /* __GNUC__ */ +#endif /* VMS */ + +#ifndef O_RDONLY +#define O_RDONLY 0 +#endif + +#define max(a,b) ((a) > (b) ? (a) : (b)) + +#ifndef S_ISREG +#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) +#endif + +/* External declarations. */ + +void bcopy (), bzero (); +int bcmp (); +extern char *getenv (); +extern char *version_string; + +/* Forward declarations. */ + +struct directive; +struct file_buf; +struct arglist; +struct argdata; + +int do_define (), do_line (), do_include (), do_undef (), do_error (), + do_pragma (), do_if (), do_xifdef (), do_else (), + do_elif (), do_endif (), do_sccs (), do_once (); + +struct hashnode *install (); +struct hashnode *lookup (); + +char *xmalloc (), *xrealloc (), *xcalloc (), *savestring (); +void fatal (), fancy_abort (), pfatal_with_name (), perror_with_name (); + +void macroexpand (); +void dump_all_macros (); +void conditional_skip (); +void skip_if_group (); +void output_line_command (); +/* Last arg to output_line_command. */ +enum file_change_code {same_file, enter_file, leave_file}; + +int grow_outbuf (); +int handle_directive (); +void memory_full (); + +U_CHAR *macarg1 (); +char *macarg (); + +U_CHAR *skip_to_end_of_comment (); +U_CHAR *skip_quoted_string (); + +#ifndef FATAL_EXIT_CODE +#define FATAL_EXIT_CODE 33 /* gnu cc command understands this */ +#endif + +#ifndef SUCCESS_EXIT_CODE +#define SUCCESS_EXIT_CODE 0 /* 0 means success on Unix. */ +#endif + +/* Name under which this program was invoked. */ + +char *progname; + +/* Nonzero means handle C++ comment syntax and use + extra default include directories for C++. */ + +int cplusplus; + +/* Current maximum length of directory names in the search path + for include files. (Altered as we get more of them.) */ + +int max_include_len; + +/* Nonzero means copy comments into the output file. */ + +int put_out_comments = 0; + +/* Nonzero means don't process the ANSI trigraph sequences. */ + +int no_trigraphs = 0; + +/* Nonzero means print the names of included files rather than + the preprocessed output. 1 means just the #include "...", + 2 means #include <...> as well. */ + +int print_deps = 0; + +/* Nonzero means don't output line number information. */ + +int no_line_commands; + +/* Nonzero means inhibit output of the preprocessed text + and instead output the definitions of all user-defined macros + in a form suitable for use as input to cccp. */ + +int dump_macros; + +/* Nonzero means give all the error messages the ANSI standard requires. */ + +int pedantic; + +/* Nonzero means don't print warning messages. -w. */ + +int inhibit_warnings = 0; + +/* Nonzero means warn if slash-star appears in a comment. */ + +int warn_comments; + +/* Nonzero means warn if there are any trigraphs. */ + +int warn_trigraphs; + +/* Nonzero means try to imitate old fashioned non-ANSI preprocessor. */ + +int traditional; + +/* Nonzero causes output not to be done, + but directives such as #define that have side effects + are still obeyed. */ + +int no_output; + +/* 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 200 +struct file_buf { + char *fname; + int lineno; + int length; + U_CHAR *buf; + U_CHAR *bufp; + /* Macro that this level is the expansion of. + Included so that we can reenable the macro + at the end of this level. */ + struct hashnode *macro; + /* Value of if_stack at start of this file. + Used to prohibit unmatched #endif (etc) in an include file. */ + struct if_stack *if_stack; + /* Object to be freed at end of input at this level. */ + U_CHAR *free_ptr; +} instack[INPUT_STACK_MAX]; + +/* Current nesting level of input sources. + `instack[indepth]' is the level currently being read. */ +int indepth = -1; +#define CHECK_DEPTH(code) \ + if (indepth >= (INPUT_STACK_MAX - 1)) \ + { \ + error_with_line (line_for_error (instack[indepth].lineno), \ + "macro or #include recursion too deep"); \ + code; \ + } + +/* Current depth in #include directives that use <...>. */ +int system_include_depth = 0; + +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. */ + +#define OUTBUF_SIZE 10 /* initial size of output buffer */ +FILE_BUF outbuf; + +/* Grow output buffer OBUF points at + so it can hold at least NEEDED more chars. */ + +#define check_expand(OBUF, NEEDED) \ + (((OBUF)->length - ((OBUF)->bufp - (OBUF)->buf) <= (NEEDED)) \ + ? grow_outbuf ((OBUF), (NEEDED)) : 0) + +struct file_name_list + { + struct file_name_list *next; + char *fname; + }; + +/* #include "file" looks in source file dir, then stack. */ +/* #include just looks in the stack. */ +/* -I directories are added to the end, then the defaults are added. */ +struct file_name_list include_defaults[] = + { +#ifndef VMS + { &include_defaults[1], GCC_INCLUDE_DIR }, + { &include_defaults[2], CC_INCLUDE_DIR }, + { 0, "/usr/local/include" } +#else + { &include_defaults[1], "GNU_CC_INCLUDE:" }, /* GNU includes */ + { &include_defaults[2], "SYS$SYSROOT:[SYSLIB.]" }, /* VAX-11 "C" includes */ + { 0, "." } /* This makes normal VMS filespecs work OK. The "." forces */ + /* the file through hack_vms_include_specification */ +#endif /* VMS */ + }; + +/* These are used instead of the above, for C++. */ +struct file_name_list cplusplus_include_defaults[] = + { +#ifndef VMS + /* Pick up GNU C++ specific include files. */ + { &cplusplus_include_defaults[1], GPLUSPLUS_INCLUDE_DIR }, + /* Use GNU CC specific header files. */ + { &cplusplus_include_defaults[2], GCC_INCLUDE_DIR }, + { 0, CC_INCLUDE_DIR } +#else + { &cplusplus_include_defaults[1], "GNU_GXX_INCLUDE:" }, + { &cplusplus_include_defaults[2], "GNU_CC_INCLUDE:" }, + /* VAX-11 C includes */ + { &cplusplus_include_defaults[3], "SYS$SYSROOT:[SYSLIB.]" }, + { 0, "." } /* This makes normal VMS filespecs work OK */ +#endif /* VMS */ + }; + +struct file_name_list *include = 0; /* First dir to search */ + /* First dir to search for */ +struct file_name_list *first_bracket_include = 0; +struct file_name_list *last_include = 0; /* Last in chain */ + +/* List of included files that contained #once. */ +struct file_name_list *dont_repeat_files = 0; + +/* List of other included files. */ +struct file_name_list *all_include_files = 0; + +/* Structure allocated for every #define. For a simple replacement + such as + #define foo bar , + nargs = -1, the `pattern' list is null, and the expansion is just + the replacement text. Nargs = 0 means a functionlike macro with no args, + e.g., + #define getchar() getc (stdin) . + When there are args, the expansion is the replacement text with the + args squashed out, and the reflist is a list describing how to + build the output from the input: e.g., "3 chars, then the 1st arg, + then 9 chars, then the 3rd arg, then 0 chars, then the 2nd arg". + The chars here come from the expansion. Whatever is left of the + expansion after the last arg-occurrence is copied after that arg. + Note that the reflist can be arbitrarily long--- + its length depends on the number of times the arguments appear in + the replacement text, not how many args there are. Example: + #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). */ + +typedef struct definition DEFINITION; +struct definition { + int nargs; + int length; /* length of expansion string */ + U_CHAR *expansion; + struct reflist { + struct reflist *next; + char stringify; /* nonzero if this arg was preceded by a + # operator. */ + char raw_before; /* Nonzero if a ## operator before arg. */ + char raw_after; /* Nonzero if a ## operator after arg. */ + int nchars; /* Number of literal chars to copy before + this arg occurrence. */ + int argno; /* Number of arg to substitute (origin-0) */ + } *pattern; + /* Names of macro args, concatenated in reverse order + 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; +}; + +/* different kinds of things that can appear in the value field + of a hash node. Actually, this may be useless now. */ +union hashval { + int ival; + char *cpval; + DEFINITION *defn; +}; + + +/* The structure of a node in the hash table. The hash table + has entries for all tokens defined by #define commands (type T_MACRO), + 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. */ + +/* different flavors of hash nodes --- also used in keyword table */ +enum node_type { + T_DEFINE = 1, /* the `#define' keyword */ + T_INCLUDE, /* the `#include' keyword */ + T_IFDEF, /* the `#ifdef' keyword */ + T_IFNDEF, /* the `#ifndef' keyword */ + T_IF, /* the `#if' keyword */ + T_ELSE, /* `#else' */ + T_PRAGMA, /* `#pragma' */ + T_ELIF, /* `#else' */ + T_UNDEF, /* `#undef' */ + T_LINE, /* `#line' */ + T_ERROR, /* `#error' */ + T_ENDIF, /* `#endif' */ + T_SCCS, /* `#sccs', used on system V. */ + T_IDENT, /* `#ident', used on system V. */ + T_SPECLINE, /* special symbol `__LINE__' */ + T_DATE, /* `__DATE__' */ + T_FILE, /* `__FILE__' */ + T_BASE_FILE, /* `__BASE_FILE__' */ + T_INCLUDE_LEVEL, /* `__INCLUDE_LEVEL__' */ + T_VERSION, /* `__VERSION__' */ + T_TIME, /* `__TIME__' */ + T_CONST, /* Constant value, used by `__STDC__' */ + T_MACRO, /* macro defined by `#define' */ + T_DISABLED, /* macro temporarily turned off for rescan */ + T_SPEC_DEFINED, /* special `defined' macro for use in #if statements */ + T_UNUSED /* Used for something not defined. */ + }; + +struct hashnode { + struct hashnode *next; /* double links for easy deletion */ + 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. */ + enum node_type type; /* type of special token */ + int length; /* length of token, for quick comparison */ + U_CHAR *name; /* the actual name */ + union hashval value; /* pointer to expansion, or whatever */ +}; + +typedef struct hashnode HASHNODE; + +/* Some definitions for the hash table. The hash function MUST be + computed as shown in hashf () below. That is because the rescan + 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. */ + +#define HASHSIZE 1403 +HASHNODE *hashtab[HASHSIZE]; +#define HASHSTEP(old, c) ((old << 2) + c) +#define MAKE_POS(v) (v & ~0x80000000) /* make number positive */ + +/* Symbols to predefine. */ + +#ifdef CPP_PREDEFINES +char *predefs = CPP_PREDEFINES; +#else +char *predefs = ""; +#endif + +/* `struct directive' defines one #-directive, including how to handle it. */ + +struct directive { + int length; /* Length of name */ + int (*func)(); /* 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. */ +}; + +/* Here is the actual list of #-directives, most-often-used first. */ + +struct directive directive_table[] = { + { 6, do_define, "define", T_DEFINE, 0, 1}, + { 2, do_if, "if", T_IF}, + { 5, do_xifdef, "ifdef", T_IFDEF}, + { 6, do_xifdef, "ifndef", T_IFNDEF}, + { 5, do_endif, "endif", T_ENDIF}, + { 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}, + { 5, do_undef, "undef", T_UNDEF}, + { 5, do_error, "error", T_ERROR}, +#ifdef SCCS_DIRECTIVE + { 4, do_sccs, "sccs", T_SCCS}, +#endif + { 6, do_pragma, "pragma", T_PRAGMA, 0, 0, 1}, + { -1, 0, "", T_UNUSED}, +}; + +/* 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. */ +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) + +int errors = 0; /* Error counter for exit code */ + +/* Zero means dollar signs are punctuation. + -$ stores 0; -traditional, stores 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) */ +#ifndef DOLLARS_IN_IDENTIFIERS +#define DOLLARS_IN_IDENTIFIERS 0 +#endif +int dollars_in_ident = DOLLARS_IN_IDENTIFIERS; + +FILE_BUF expand_to_temp_buffer (); + +DEFINITION *collect_expansion (); + +/* Stack of conditionals currently in progress + (including both successful and failing conditionals). */ + +struct if_stack { + struct if_stack *next; /* for chaining to the next stack frame */ + char *fname; /* copied from input when frame is made */ + int lineno; /* similarly */ + int if_succeeded; /* true if a leg of this if-group + has been passed through rescan */ + enum node_type type; /* type of last directive seen in this group */ +}; +typedef struct if_stack IF_STACK_FRAME; +IF_STACK_FRAME *if_stack = NULL; + +/* Buffer of -M output. */ + +char *deps_buffer; + +/* Number of bytes allocated in above. */ +int deps_allocated_size; + +/* Number of bytes used. */ +int deps_size; + +/* Number of bytes since the last newline. */ +int deps_column; + +/* Nonzero means -I- has been seen, + so don't look for #include "foo" the source-file directory. */ +int ignore_srcdir; + +/* Handler for SIGPIPE. */ + +static void +pipe_closed () +{ + fatal ("output pipe has been closed"); +} + +int +main (argc, argv) + int argc; + char **argv; +{ + int st_mode; + long st_size; + char *in_fname, *out_fname; + int f, i; + FILE_BUF *fp; + char **pend_files = (char **) xmalloc (argc * sizeof (char *)); + char **pend_defs = (char **) xmalloc (argc * sizeof (char *)); + char **pend_undefs = (char **) xmalloc (argc * sizeof (char *)); + int inhibit_predefs = 0; + int no_standard_includes = 0; + + /* Non-0 means don't output the preprocessed program. */ + int inhibit_output = 0; + + /* Stream on which to print the dependency information. */ + FILE *deps_stream = 0; + /* Target-name to write with the dependency information. */ + char *deps_target = 0; + +#ifdef RLIMIT_STACK + /* 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. */ + getrlimit (RLIMIT_STACK, &rlim); + rlim.rlim_cur = rlim.rlim_max; + setrlimit (RLIMIT_STACK, &rlim); + } +#endif /* RLIMIT_STACK defined */ + + progname = argv[0]; +#ifdef VMS + { + /* Remove directories from PROGNAME. */ + char *s; + extern char *rindex (); + + progname = savestring (argv[0]); + + if (!(s = rindex (progname, ']'))) + s = rindex (progname, ':'); + if (s) + strcpy (progname, s+1); + if (s = rindex (progname, '.')) + *s = '\0'; + } +#endif + + in_fname = NULL; + out_fname = NULL; + + /* Initialize is_idchar to allow $. */ + dollars_in_ident = 1; + initialize_char_syntax (); + dollars_in_ident = DOLLARS_IN_IDENTIFIERS; + + no_line_commands = 0; + no_trigraphs = 1; + dump_macros = 0; + no_output = 0; + cplusplus = 0; +#ifdef CPLUSPLUS + cplusplus = 1; +#endif + + signal (SIGPIPE, pipe_closed); + +#ifndef VMS + max_include_len + = max (max (sizeof (GCC_INCLUDE_DIR), + sizeof (GPLUSPLUS_INCLUDE_DIR)), + sizeof ("/usr/include/CC")); +#else /* VMS */ + max_include_len + = sizeof("SYS$SYSROOT:[SYSLIB.]"); +#endif /* VMS */ + + bzero (pend_files, argc * sizeof (char *)); + bzero (pend_defs, argc * sizeof (char *)); + bzero (pend_undefs, argc * sizeof (char *)); + + /* Process switches and find input file name. */ + + for (i = 1; i < argc; i++) { + if (argv[i][0] != '-') { + if (out_fname != NULL) + fatal ("Usage: %s [switches] input output", argv[0]); + else if (in_fname != NULL) + out_fname = argv[i]; + else + in_fname = argv[i]; + } else { + switch (argv[i][1]) { + + case 'i': + if (argv[i][2] != 0) + pend_files[i] = argv[i] + 2; + else if (i + 1 == argc) + fatal ("Filename missing after -i option"); + else + pend_files[i] = argv[i+1], i++; + break; + + case 'o': + if (out_fname != NULL) + fatal ("Output filename specified twice"); + if (i + 1 == argc) + fatal ("Filename missing after -o option"); + out_fname = argv[++i]; + if (!strcmp (out_fname, "-")) + out_fname = ""; + break; + + case 'p': + pedantic = 1; + break; + + case 't': + if (!strcmp (argv[i], "-traditional")) { + traditional = 1; + dollars_in_ident = 1; + } else if (!strcmp (argv[i], "-trigraphs")) { + no_trigraphs = 0; + } + break; + + case '+': + cplusplus = 1; + break; + + case 'w': + inhibit_warnings = 1; + break; + + case 'W': + if (!strcmp (argv[i], "-Wtrigraphs")) { + warn_trigraphs = 1; + } + if (!strcmp (argv[i], "-Wcomments")) + warn_comments = 1; + if (!strcmp (argv[i], "-Wcomment")) + warn_comments = 1; + if (!strcmp (argv[i], "-Wall")) { + warn_trigraphs = 1; + warn_comments = 1; + } + break; + + case 'M': + if (!strcmp (argv[i], "-M")) + print_deps = 2; + else if (!strcmp (argv[i], "-MM")) + print_deps = 1; + inhibit_output = 1; + break; + + case 'd': + dump_macros = 1; + no_output = 1; + break; + + case 'v': + fprintf (stderr, "GNU CPP version %s\n", version_string); + break; + + case 'D': + { + char *p, *p1; + + if (argv[i][2] != 0) + p = argv[i] + 2; + else if (i + 1 == argc) + fatal ("Macro name missing after -D option"); + else + p = argv[++i]; + + if ((p1 = (char *) index (p, '=')) != NULL) + *p1 = ' '; + pend_defs[i] = p; + } + break; + + case 'U': /* JF #undef something */ + if (argv[i][2] != 0) + pend_undefs[i] = argv[i] + 2; + else if (i + 1 == argc) + fatal ("Macro name missing after -U option"); + else + pend_undefs[i] = argv[i+1], i++; + break; + + case 'C': + put_out_comments = 1; + break; + + case 'E': /* -E comes from cc -E; ignore it. */ + break; + + case 'P': + no_line_commands = 1; + break; + + case '$': /* Don't include $ in identifiers. */ + dollars_in_ident = 0; + break; + + case 'I': /* Add directory to path for includes. */ + { + struct file_name_list *dirtmp; + + if (! ignore_srcdir && !strcmp (argv[i] + 2, "-")) + 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 (include == 0) + include = dirtmp; + else + last_include->next = dirtmp; + last_include = dirtmp; /* Tail follows the last one */ + 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]; + if (strlen (dirtmp->fname) > max_include_len) + max_include_len = strlen (dirtmp->fname); + if (ignore_srcdir && first_bracket_include == 0) + first_bracket_include = dirtmp; + } + } + break; + + case 'n': + /* -nostdinc causes no default include directories. + You must specify all include-file directories with -I. */ + no_standard_includes = 1; + break; + + case 'u': + /* Sun compiler passes undocumented switch "-undef". + Let's assume it means to inhibit the predefined symbols. */ + inhibit_predefs = 1; + break; + + case '\0': /* JF handle '-' as file name meaning stdin or stdout */ + if (in_fname == NULL) { + in_fname = ""; + break; + } else if (out_fname == NULL) { + out_fname = ""; + break; + } /* else fall through into error */ + + default: + fatal ("Invalid option `%s'", argv[i]); + } + } + } + + /* Now that dollars_in_ident is known, initialize is_idchar. */ + initialize_char_syntax (); + + /* Install __LINE__, etc. Must follow initialize_char_syntax + and option processing. */ + initialize_builtins (); + + /* Do standard #defines that identify processor type. */ + + if (!inhibit_predefs) { + char *p = (char *) alloca (strlen (predefs) + 1); + strcpy (p, predefs); + while (*p) { + char *q; + if (p[0] != '-' || p[1] != 'D') + abort (); + q = &p[2]; + while (*p && *p != ' ') p++; + if (*p != 0) + *p++= 0; + make_definition (q); + } + } + + /* Do defines specified with -D. */ + for (i = 1; i < argc; i++) + if (pend_defs[i]) + make_definition (pend_defs[i]); + + /* Do undefines specified with -U. */ + for (i = 1; i < argc; i++) + if (pend_undefs[i]) + make_undef (pend_undefs[i]); + + /* Unless -fnostdinc, + tack on the standard include file dirs to the specified list */ + if (!no_standard_includes) { + if (include == 0) + include = (cplusplus ? cplusplus_include_defaults : include_defaults); + else + last_include->next + = (cplusplus ? cplusplus_include_defaults : include_defaults); + /* Make sure the list for #include <...> also has the standard dirs. */ + if (ignore_srcdir && first_bracket_include == 0) + first_bracket_include + = (cplusplus ? cplusplus_include_defaults : include_defaults); + } + + /* Initialize output buffer */ + + outbuf.buf = (U_CHAR *) xmalloc (OUTBUF_SIZE); + outbuf.bufp = outbuf.buf; + outbuf.length = OUTBUF_SIZE; + + /* Scan the -i files before the main input. + Much like #including them, but with no_output set + so that only their macro definitions matter. */ + + no_output++; + 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); + } + no_output--; + + /* Create an input stack level for the main input file + and copy the entire contents of the file into it. */ + + fp = &instack[++indepth]; + + /* 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; + + /* Either of two environment variables can specify output of deps. + Its value is either "OUTPUT_FILE" or "OUTPUT_FILE DEPS_TARGET", + where OUTPUT_FILE is the file to write deps info to + and DEPS_TARGET is the target to mention in the deps. */ + + if (print_deps == 0 + && (getenv ("SUNPRO_DEPENDENCIES") != 0 + || getenv ("DEPENDENCIES_OUTPUT") != 0)) + { + char *spec = getenv ("DEPENDENCIES_OUTPUT"); + char *s; + char *output_file; + + if (spec == 0) + { + spec = getenv ("SUNPRO_DEPENDENCIES"); + print_deps = 2; + } + else + print_deps = 1; + + s = spec; + /* Find the space before the DEPS_TARGET, if there is one. */ + /* Don't use `index'; that causes trouble on USG. */ + while (*s != 0 && *s != ' ') s++; + if (*s != 0) + { + deps_target = s + 1; + output_file = (char *) xmalloc (s - spec + 1); + bcopy (spec, output_file, s - spec); + output_file[s - spec] = 0; + } + else + { + deps_target = 0; + output_file = spec; + } + + deps_stream = fopen (output_file, "a"); + if (deps_stream == 0) + pfatal_with_name (output_file); + } + /* If the -M option was used, output the deps to standard output. */ + else if (print_deps) + deps_stream = stdout; + + /* For -M, print the expected object file name + as the target of this Make-rule. */ + if (print_deps) { + deps_allocated_size = 200; + deps_buffer = (char *) xmalloc (deps_allocated_size); + deps_buffer[0] = 0; + deps_size = 0; + deps_column = 0; + + if (deps_target) { + deps_output (deps_target, 0); + deps_output (":", 0); + } else if (*in_fname == 0) + deps_output ("-: ", 0); + else { + int len; + char *p = in_fname; + char *p1 = p; + /* Discard all directory prefixes from P. */ + while (*p1) { + if (*p1 == '/') + p = p1 + 1; + p1++; + } + /* Output P, but remove known suffixes. */ + len = strlen (p); + if (p[len - 2] == '.' + && (p[len - 1] == 'c' || p[len - 1] == 'C' || p[len - 1] == 'S')) + deps_output (p, len - 2); + else if (p[len - 3] == '.' + && p[len - 2] == 'c' + && p[len - 1] == 'c') + deps_output (p, len - 3); + else + deps_output (p, 0); + /* Supply our own suffix. */ + deps_output (".o : ", 0); + deps_output (in_fname, 0); + deps_output (" ", 0); + } + } + + file_size_and_mode (f, &st_mode, &st_size); + fp->fname = in_fname; + fp->lineno = 1; + /* JF all this is mine about reading pipes and ttys */ + if (!S_ISREG (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. */ + int size; + int bsize; + int cnt; + U_CHAR *bufp; + + bsize = 2000; + size = 0; + fp->buf = (U_CHAR *) xmalloc (bsize + 2); + bufp = fp->buf; + for (;;) { + cnt = read (f, bufp, bsize - size); + if (cnt < 0) goto perror; /* error! */ + if (cnt == 0) break; /* End of file */ + size += cnt; + bufp += cnt; + if (bsize == size) { /* Buffer is full! */ + bsize *= 2; + fp->buf = (U_CHAR *) xrealloc (fp->buf, bsize + 2); + bufp = fp->buf + size; /* May have moved */ + } + } + 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. */ + long i; + fp->length = 0; + fp->buf = (U_CHAR *) xmalloc (st_size + 2); + + while (st_size > 0) { + i = read (f, fp->buf + fp->length, st_size); + if (i <= 0) { + if (i == 0) break; + goto perror; + } + fp->length += i; + st_size -= i; + } + } + fp->bufp = fp->buf; + fp->if_stack = if_stack; + + /* Unless inhibited, convert trigraphs in the input. */ + + if (!no_trigraphs) + trigraph_pcp (fp); + + /* Make sure data ends with a newline. And put a null after it. */ + + if (fp->length > 0 && fp->buf[fp->length-1] != '\n') + fp->buf[fp->length++] = '\n'; + fp->buf[fp->length] = '\0'; + + /* Now that we know the input file is valid, open the output. */ + + if (!out_fname || !strcmp (out_fname, "")) + out_fname = "stdout"; + else if (! freopen (out_fname, "w", stdout)) + pfatal_with_name (out_fname); + + output_line_command (fp, &outbuf, 0, same_file); + + /* Scan the input, processing macros and directives. */ + + rescan (&outbuf, 0); + + /* Now we have processed the entire input + Write whichever kind of output has been requested. */ + + + if (dump_macros) + dump_all_macros (); + else if (! inhibit_output && deps_stream != stdout) { + if (write (fileno (stdout), outbuf.buf, outbuf.bufp - outbuf.buf) < 0) + fatal ("I/O error on output"); + } + + if (print_deps) { + fputs (deps_buffer, deps_stream); + putc ('\n', deps_stream); + if (deps_stream != stdout) { + fclose (deps_stream); + if (ferror (deps_stream)) + fatal ("I/O error on output"); + } + } + + if (ferror (stdout)) + fatal ("I/O error on output"); + + if (errors) + exit (FATAL_EXIT_CODE); + exit (SUCCESS_EXIT_CODE); + + perror: + pfatal_with_name (in_fname); +} + +/* Pre-C-Preprocessor to translate ANSI trigraph idiocy in BUF + before main CCCP processing. Name `pcp' is also in honor of the + drugs the trigraph designers must have been on. + + Using an extra pass through the buffer takes a little extra time, + but is infinitely less hairy than trying to handle ??/" inside + strings, etc. everywhere, and also makes sure that trigraphs are + only translated in the top level of processing. */ + +trigraph_pcp (buf) + FILE_BUF *buf; +{ + register U_CHAR c, *fptr, *bptr, *sptr; + int len; + + fptr = bptr = sptr = buf->buf; + while ((sptr = (U_CHAR *) index (sptr, '?')) != NULL) { + if (*++sptr != '?') + continue; + switch (*++sptr) { + case '=': + c = '#'; + break; + case '(': + c = '['; + break; + case '/': + c = '\\'; + break; + case ')': + c = ']'; + break; + case '\'': + c = '^'; + break; + case '<': + c = '{'; + break; + case '!': + c = '|'; + break; + case '>': + c = '}'; + break; + case '-': + c = '~'; + break; + case '?': + sptr--; + continue; + default: + continue; + } + len = sptr - fptr - 2; + if (bptr != fptr && len > 0) + bcopy (fptr, bptr, len); /* BSD doc says bcopy () works right + for overlapping strings. In ANSI + C, this will be memmove (). */ + bptr += len; + *bptr++ = c; + fptr = ++sptr; + } + len = buf->length - (fptr - buf->buf); + if (bptr != fptr && len > 0) + bcopy (fptr, bptr, len); + buf->length -= fptr - bptr; + buf->buf[buf->length] = '\0'; + if (warn_trigraphs && fptr != bptr) + warning ("%d trigraph(s) encountered", (fptr - bptr) / 2); +} + +/* Move all backslash-newline pairs out of embarrassing places. + Exchange all such pairs following BP + with any potentially-embarrasing characters that follow them. + Potentially-embarrassing characters are / and * + (because a backslash-newline inside a comment delimiter + would cause it not to be recognized). */ + +newline_fix (bp) + U_CHAR *bp; +{ + register U_CHAR *p = bp; + register int count = 0; + + /* First count the backslash-newline pairs here. */ + + while (*p++ == '\\' && *p++ == '\n') + count++; + + p = bp + count * 2; + + /* Exit if what follows the backslash-newlines is not embarrassing. */ + + if (count == 0 || (*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 (count-- > 0) { + *bp++ = '\\'; + *bp++ = '\n'; + } +} + +/* Like newline_fix but for use within a directive-name. + Move any backslash-newlines up past any following symbol constituents. */ + +name_newline_fix (bp) + U_CHAR *bp; +{ + register U_CHAR *p = bp; + register int count = 0; + + /* First count the backslash-newline pairs here. */ + + while (*p++ == '\\' && *p++ == '\n') + count++; + + p = bp + count * 2; + + /* What follows the backslash-newlines is not embarrassing. */ + + if (count == 0 || !is_idchar[*p]) + return; + + /* Copy all potentially embarrassing characters + that follow the backslash-newline pairs + down to where the pairs originally started. */ + + while (is_idchar[*p]) + *bp++ = *p++; + + /* Now write the same number of pairs after the embarrassing chars. */ + while (count-- > 0) { + *bp++ = '\\'; + *bp++ = '\n'; + } +} + +/* + * The main loop of the program. + * + * Read characters from the input stack, transferring them to the + * output buffer OP. + * + * Macros are expanded and push levels on the input stack. + * At the end of such a level it is popped off and we keep reading. + * At the end of any other kind of level, we return. + * #-directives are handled, except within macros. + * + * If OUTPUT_MARKS is nonzero, keep Newline markers found in the input + * and insert them when appropriate. This is set while scanning macro + * arguments before substitution. It is zero when scanning for final output. + * There are three types of Newline markers: + * * Newline - follows a macro name that was not expanded + * because it appeared inside an expansion of the same macro. + * This marker prevents future expansion of that identifier. + * When the input is rescanned into the final output, these are deleted. + * These are also deleted by ## concatenation. + * * Newline Space (or Newline and any other whitespace character) + * stands for a place that tokens must be separated or whitespace + * is otherwise desirable, but where the ANSI standard specifies there + * is no whitespace. This marker turns into a Space (or whichever other + * whitespace char appears in the marker) in the final output, + * but it turns into nothing in an argument that is stringified with #. + * Such stringified arguments are the only place where the ANSI standard + * specifies with precision that whitespace may not appear. + * + * During this function, IP->bufp is kept cached in IBP for speed of access. + * Likewise, OP->bufp is kept in OBP. Before calling a subroutine + * IBP, IP and OBP must be copied back to memory. IP and IBP are + * copied back with the RECACHE macro. OBP must be copied back from OP->bufp + * explicitly, and before RECACHE, since RECACHE uses OBP. + */ + +rescan (op, output_marks) + FILE_BUF *op; + int output_marks; +{ + /* Character being scanned in main loop. */ + register U_CHAR c; + + /* Length of pending accumulated identifier. */ + register int ident_length = 0; + + /* Hash code of pending accumulated identifier. */ + register int hash = 0; + + /* Current input level (&instack[indepth]). */ + FILE_BUF *ip; + + /* Pointer for scanning input. */ + register U_CHAR *ibp; + + /* Pointer to end of input. End of scan is controlled by LIMIT. */ + register U_CHAR *limit; + + /* Pointer for storing output. */ + register U_CHAR *obp; + + /* REDO_CHAR is nonzero if we are processing an identifier + after backing up over the terminating character. + Sometimes we process an identifier without backing up over + the terminating character, if the terminating character + is not special. Backing up is done so that the terminating character + will be dispatched on again once the identifier is dealt with. */ + int redo_char = 0; + + /* 1 if within an identifier inside of which a concatenation + marker (Newline -) has been seen. */ + int concatenated = 0; + + /* While scanning a comment or a string constant, + this records the line it started on, for error messages. */ + int start_line; + + /* Record position of last `real' newline. */ + U_CHAR *beg_of_line; + +/* Pop the innermost input stack level, assuming it is a macro expansion. */ + +#define POPMACRO \ +do { ip->macro->type = T_MACRO; \ + if (ip->free_ptr) free (ip->free_ptr); \ + --indepth; } while (0) + +/* Reload `rescan's local variables that describe the current + level of the input stack. */ + +#define RECACHE \ +do { ip = &instack[indepth]; \ + ibp = ip->bufp; \ + limit = ip->buf + ip->length; \ + op->bufp = obp; \ + check_expand (op, limit - ibp); \ + beg_of_line = 0; \ + obp = op->bufp; } while (0) + + if (no_output && instack[indepth].fname != 0) + skip_if_group (&instack[indepth], 1); + + obp = op->bufp; + RECACHE; + beg_of_line = ibp; + + /* Our caller must always put a null after the end of + the input at each input stack level. */ + if (*limit != 0) + abort (); + + while (1) { + c = *ibp++; + *obp++ = c; + + switch (c) { + case '\\': + if (ibp >= limit) + break; + if (*ibp == '\n') { + /* Always merge lines ending with backslash-newline, + even in middle of identifier. */ + ++ibp; + ++ip->lineno; + --obp; /* remove backslash from obuf */ + break; + } + /* Otherwise, backslash suppresses specialness of following char, + so copy it here to prevent the switch from seeing it. + But first get any pending identifier processed. */ + if (ident_length > 0) + goto specialchar; + *obp++ = *ibp++; + break; + + case '#': + /* If this is expanding a macro definition, don't recognize + preprocessor directives. */ + if (ip->macro != 0) + goto randomchar; + if (ident_length) + goto specialchar; + + /* # keyword: a # must be first nonblank char on the line */ + if (beg_of_line == 0) + goto randomchar; + { + U_CHAR *bp; + + /* Scan from start of line, skipping whitespace, comments + and backslash-newlines, and see if we reach this #. + If not, this # is not special. */ + bp = beg_of_line; + while (1) { + if (is_hor_space[*bp]) + bp++; + else if (*bp == '\\' && bp[1] == '\n') + bp += 2; + else if (*bp == '/' && (newline_fix (bp + 1), bp[1]) == '*') { + bp += 2; + while (!(*bp == '*' && (newline_fix (bp + 1), bp[1]) == '/')) + bp++; + bp += 1; + } + else if (cplusplus && *bp == '/' && (newline_fix (bp + 1), bp[1]) == '/') { + bp += 2; + while (*bp++ != '\n') ; + } + else break; + } + if (bp + 1 != ibp) + goto randomchar; + } + + /* This # can start a directive. */ + + --obp; /* Don't copy the '#' */ + + ip->bufp = ibp; + op->bufp = obp; + if (! handle_directive (ip, op)) { +#ifdef USE_C_ALLOCA + alloca (0); +#endif + /* Not a known directive: treat it as ordinary text. + IP, OP, IBP, etc. have not been changed. */ + if (no_output && instack[indepth].fname) { + /* If not generating expanded output, + what we do with ordinary text is skip it. + Discard everything until next # directive. */ + skip_if_group (&instack[indepth], 1); + RECACHE; + beg_of_line = ibp; + break; + } + ++obp; /* Copy the '#' after all */ + goto randomchar; + } +#ifdef USE_C_ALLOCA + alloca (0); +#endif + /* A # directive has been successfully processed. */ + /* If not generating expanded output, ignore everything until + next # directive. */ + if (no_output && instack[indepth].fname) + skip_if_group (&instack[indepth], 1); + obp = op->bufp; + RECACHE; + beg_of_line = ibp; + break; + + case '\"': /* skip quoted string */ + case '\'': + /* A single quoted string is treated like a double -- some + programs (e.g., troff) are perverse this way */ + + if (ident_length) + goto specialchar; + + start_line = ip->lineno; + + /* Skip ahead to a matching quote. */ + + while (1) { + if (ibp >= limit) { + if (traditional) { + if (ip->macro != 0) { + /* try harder: this string crosses a macro expansion boundary */ + POPMACRO; + RECACHE; + continue; + } + } else + error_with_line (line_for_error (start_line), + "unterminated string or character constant"); + break; + } + *obp++ = *ibp; + switch (*ibp++) { + case '\n': + ++ip->lineno; + ++op->lineno; + /* Traditionally, end of line ends a string constant with no error. + So exit the loop and record the new line. */ + if (traditional) { + beg_of_line = ibp; + goto while2end; + } + if (pedantic || c == '\'') { + error_with_line (line_for_error (start_line), + "unterminated string or character constant"); + goto while2end; + } + break; + + case '\\': + if (ibp >= limit) + break; + if (*ibp == '\n') { + /* Backslash newline is replaced by nothing at all, + but keep the line counts correct. */ + --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; + } + *obp++ = *ibp++; + } + break; + + case '\"': + case '\'': + if (ibp[-1] == c) + goto while2end; + break; + } + } + while2end: + break; + + case '/': + if (*ibp == '\\' && ibp[1] == '\n') + newline_fix (ibp); + /* Don't look for comments inside a macro definition. */ + if (ip->macro != 0) + goto randomchar; + /* A comment constitutes white space, so it can terminate an identifier. + Process the identifier, if any. */ + if (ident_length) + goto specialchar; + if (cplusplus && *ibp == '/') { + /* C++ style comment... */ + start_line = ip->lineno; + + --ibp; /* Back over the slash */ + --obp; + + /* Comments are equivalent to spaces. */ + if (! put_out_comments) + *obp++ = ' '; + else { + /* must fake up a comment here */ + *obp++ = '/'; + *obp++ = '/'; + } + { + U_CHAR *before_bp = ibp+2; + + while (ibp < limit) { + if (*ibp == '\\' && ibp[1] == '\n') { + ip->lineno++; + ibp += 2; + } else if (*ibp++ == '\n') { + ibp--; + if (put_out_comments) { + bcopy (before_bp, obp, ibp - before_bp); + obp += ibp - before_bp; + } + break; + } + } + break; + } + } + if (*ibp != '*') + goto randomchar; + + /* We have a comment. Skip it, optionally copying it to output. */ + + start_line = ip->lineno; + + ++ibp; /* Skip the star. */ + + /* Comments are equivalent to spaces. + Note that we already output the slash; we might not want it. + For -traditional, a comment is equivalent to nothing. */ + if (! put_out_comments) { + if (traditional) + obp--; + else + obp[-1] = ' '; + } + else + *obp++ = '*'; + + { + U_CHAR *before_bp = ibp; + + while (ibp < limit) { + switch (*ibp++) { + case '/': + if (warn_comments && ibp < limit && *ibp == '*') + warning("`/*' within comment"); + break; + case '*': + if (*ibp == '\\' && ibp[1] == '\n') + newline_fix (ibp); + if (ibp >= limit || *ibp == '/') + goto comment_end; + break; + case '\n': + ++ip->lineno; + /* Copy the newline into the output buffer, in order to + avoid the pain of a #line every time a multiline comment + is seen. */ + if (!put_out_comments) + *obp++ = '\n'; + ++op->lineno; + } + } + comment_end: + + if (ibp >= limit) + error_with_line (line_for_error (start_line), + "unterminated comment"); + else { + ibp++; + if (put_out_comments) { + bcopy (before_bp, obp, ibp - before_bp); + obp += ibp - before_bp; + } + } + } + break; + + case '$': + if (!dollars_in_ident) + goto randomchar; + goto letter; + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + /* If digit is not part of identifier, it starts a number, + which means that following letters are not an identifier. + "0x5" does not refer to an identifier "x5". + So copy all alphanumerics that follow without accumulating + as an identifier. Periods also, for sake of "3.e7". */ + + if (ident_length == 0) { + while (ibp < limit) { + while (ibp < limit && ibp[0] == '\\' && ibp[1] == '\n') { + ++ip->lineno; + ibp += 2; + } + c = *ibp++; + if (!isalnum (c) && c != '.' && c != '_') { + --ibp; + break; + } + *obp++ = c; + /* A sign can be part of a preprocessing number + if it follows an e. */ + if (c == 'e' || c == 'E') { + while (ibp < limit && ibp[0] == '\\' && ibp[1] == '\n') { + ++ip->lineno; + ibp += 2; + } + if (ibp < limit && (*ibp == '+' || *ibp == '-')) { + *obp++ = *ibp++; + /* But traditional C does not let the token go past the sign. */ + if (traditional) + break; + } + } + } + break; + } + /* fall through */ + + case '_': + 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': + letter: + ident_length++; + /* Compute step of hash function, to avoid a proc call on every token */ + hash = HASHSTEP (hash, c); + break; + + case '\n': + /* If reprocessing a macro expansion, newline is a special marker. */ + if (ip->macro != 0) { + /* Newline White is a "funny space" to separate tokens that are + supposed to be separate but without space between. + Here White means any horizontal whitespace character. + Newline - marks a recursive macro use that is not + supposed to be expandable. */ + + if (*ibp == '-') { + /* Newline - inhibits expansion of preceding token. + If expanding a macro arg, we keep the newline -. + In final output, it is deleted. */ + if (! concatenated) { + ident_length = 0; + hash = 0; + } + ibp++; + if (!output_marks) { + obp--; + } else { + /* If expanding a macro arg, keep the newline -. */ + *obp++ = '-'; + } + } else if (is_space[*ibp]) { + /* Newline Space does not prevent expansion of preceding token + so expand the preceding token and then come back. */ + if (ident_length > 0) + goto specialchar; + + /* If generating final output, newline space makes a space. */ + if (!output_marks) { + obp[-1] = *ibp++; + /* And Newline Newline makes a newline, so count it. */ + if (obp[-1] == '\n') + op->lineno++; + } else { + /* If expanding a macro arg, keep the newline space. + If the arg gets stringified, newline space makes nothing. */ + *obp++ = *ibp++; + } + } else abort (); /* Newline followed by something random? */ + break; + } + + /* If there is a pending identifier, handle it and come back here. */ + if (ident_length > 0) + goto specialchar; + + beg_of_line = ibp; + + /* Update the line counts and output a #line if necessary. */ + ++ip->lineno; + ++op->lineno; + if (ip->lineno != op->lineno) { + op->bufp = obp; + output_line_command (ip, op, 1, same_file); + check_expand (op, ip->length - (ip->bufp - ip->buf)); + obp = op->bufp; + } + break; + + /* Come here either after (1) a null character that is part of the input + or (2) at the end of the input, because there is a null there. */ + case 0: + if (ibp <= limit) + /* Our input really contains a null character. */ + goto randomchar; + + /* At end of a macro-expansion level, pop it and read next level. */ + if (ip->macro != 0) { + obp--; + ibp--; + /* If traditional, and we have an identifier that ends here, + process it now, so we get the right error for recursion. */ + if (traditional && ident_length + && ! is_idchar[*instack[indepth - 1].bufp]) { + redo_char = 1; + goto randomchar; + } + POPMACRO; + RECACHE; + break; + } + + /* If we don't have a pending identifier, + return at end of input. */ + if (ident_length == 0) { + obp--; + ibp--; + op->bufp = obp; + ip->bufp = ibp; + goto ending; + } + + /* If we do have a pending identifier, just consider this null + a special character and arrange to dispatch on it again. + The second time, IDENT_LENGTH will be zero so we will return. */ + + /* Fall through */ + +specialchar: + + /* Handle the case of a character such as /, ', " or null + seen following an identifier. Back over it so that + after the identifier is processed the special char + will be dispatched on again. */ + + ibp--; + obp--; + redo_char = 1; + + default: + +randomchar: + + if (ident_length > 0) { + register HASHNODE *hp; + + /* We have just seen an identifier end. If it's a macro, expand it. + + IDENT_LENGTH is the length of the identifier + and HASH is its hash code. + + The identifier has already been copied to the output, + so if it is a macro we must remove it. + + If REDO_CHAR is 0, the char that terminated the identifier + has been skipped in the output and the input. + OBP-IDENT_LENGTH-1 points to the identifier. + If the identifier is a macro, we must back over the terminator. + + If REDO_CHAR is 1, the terminating char has already been + backed over. OBP-IDENT_LENGTH points to the identifier. */ + + for (hp = hashtab[MAKE_POS (hash) % HASHSIZE]; hp != NULL; + hp = hp->next) { + + if (hp->length == ident_length) { + U_CHAR *obufp_before_macroname; + int op_lineno_before_macroname; + register int i = ident_length; + register U_CHAR *p = hp->name; + register U_CHAR *q = obp - i; + int disabled; + + if (! redo_char) + q--; + + do { /* All this to avoid a strncmp () */ + if (*p++ != *q++) + goto hashcollision; + } while (--i); + + /* We found a use of a macro name. + see if the context shows it is a macro call. */ + + /* Back up over terminating character if not already done. */ + if (! redo_char) { + ibp--; + obp--; + } + + obufp_before_macroname = obp - ident_length; + op_lineno_before_macroname = op->lineno; + + /* Record whether the macro is disabled. */ + disabled = hp->type == T_DISABLED; + + /* This looks like a macro ref, but if the macro was disabled, + just copy its name and put in a marker if requested. */ + + if (disabled) { +#if 0 + /* This error check caught useful cases such as + #define foo(x,y) bar(x(y,0), y) + foo(foo, baz) */ + if (traditional) + error ("recursive use of macro `%s'", hp->name); +#endif + + if (output_marks) { + check_expand (op, limit - ibp + 2); + *obp++ = '\n'; + *obp++ = '-'; + } + break; + } + + /* If macro wants an arglist, verify that a '(' follows. + first skip all whitespace, copying it to the output + after the macro name. Then, if there is no '(', + decide this is not a macro call and leave things that way. */ + if ((hp->type == T_MACRO || hp->type == T_DISABLED) + && hp->value.defn->nargs >= 0) + { + while (1) { + /* Scan forward over whitespace, copying it to the output. */ + if (ibp == limit && ip->macro != 0) { + POPMACRO; + RECACHE; + } + /* A comment: copy it unchanged or discard it. */ + else if (*ibp == '/' && ibp+1 != limit && 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') { + if (ip->macro == 0) { + /* Newline in a file. Count it. */ + ++ip->lineno; + ++op->lineno; + } else if (!output_marks) { + /* A newline mark, and we don't want marks + in the output. If it is newline-hyphen, + discard it entirely. Otherwise, it is + newline-whitechar, so keep the whitechar. */ + obp--; + if (*ibp == '-') + ibp++; + else { + if (*ibp == '\n') + ++op->lineno; + *obp++ = *ibp++; + } + } else { + /* A newline mark; copy both chars to the output. */ + *obp++ = *ibp++; + } + } + } + else break; + } + if (*ibp != '(') + break; + } + + /* This is now known to be a macro call. + Discard the macro name from the output, + along with any following whitespace just copied. */ + obp = obufp_before_macroname; + op->lineno = op_lineno_before_macroname; + + /* Expand the macro, reading arguments as needed, + and push the expansion on the input stack. */ + ip->bufp = ibp; + op->bufp = obp; + macroexpand (hp, op); + + /* Reexamine input stack, since macroexpand has pushed + a new level on it. */ + obp = op->bufp; + RECACHE; + break; + } +hashcollision: + ; + } /* End hash-table-search loop */ + ident_length = hash = 0; /* Stop collecting identifier */ + redo_char = 0; + concatenated = 0; + } /* End if (ident_length > 0) */ + } /* End switch */ + } /* End per-char loop */ + + /* Come here to return -- but first give an error message + if there was an unterminated successful conditional. */ + ending: + if (if_stack != ip->if_stack) { + char *str; + switch (if_stack->type) { + case T_IF: + str = "if"; + break; + case T_IFDEF: + str = "ifdef"; + break; + case T_IFNDEF: + str = "ifndef"; + break; + case T_ELSE: + str = "else"; + break; + case T_ELIF: + str = "elif"; + break; + } + error_with_line (line_for_error (if_stack->lineno), + "unterminated #%s conditional", str); + } + if_stack = ip->if_stack; +} + +/* + * Rescan a string into a temporary buffer and return the result + * as a FILE_BUF. Note this function returns a struct, not a pointer. + * + * OUTPUT_MARKS nonzero means keep Newline markers found in the input + * and insert such markers when appropriate. See `rescan' for details. + * OUTPUT_MARKS is 1 for macroexpanding a macro argument separately + * before substitution; it is 0 for other uses. + */ +FILE_BUF +expand_to_temp_buffer (buf, limit, output_marks) + U_CHAR *buf, *limit; + int output_marks; +{ + register FILE_BUF *ip; + FILE_BUF obuf; + int length = limit - buf; + U_CHAR *buf1; + int odepth = indepth; + + if (length < 0) + abort (); + + /* Set up the input on the input stack. */ + + buf1 = (U_CHAR *) alloca (length + 1); + { + register U_CHAR *p1 = buf; + register U_CHAR *p2 = buf1; + + while (p1 != limit) + *p2++ = *p1++; + } + buf1[length] = 0; + + /* Set up to receive the output. */ + + obuf.length = length * 2 + 100; /* Usually enough. Why be stingy? */ + obuf.bufp = obuf.buf = (U_CHAR *) xmalloc (obuf.length); + obuf.fname = 0; + obuf.macro = 0; + obuf.free_ptr = 0; + + CHECK_DEPTH ({return obuf;}); + + ++indepth; + + ip = &instack[indepth]; + ip->fname = 0; + ip->macro = 0; + ip->free_ptr = 0; + ip->length = length; + ip->buf = ip->bufp = buf1; + ip->if_stack = if_stack; + + ip->lineno = obuf.lineno = 1; + + /* Scan the input, create the output. */ + + rescan (&obuf, output_marks); + + /* Pop input stack to original state. */ + --indepth; + + if (indepth != odepth) + abort (); + + /* Record the output. */ + obuf.length = obuf.bufp - obuf.buf; + + return obuf; +} + +/* + * Process a # directive. Expects IP->bufp to point to the '#', as in + * `#define foo bar'. Passes to the command handler + * (do_define, do_include, etc.): the addresses of the 1st and + * last chars of the command (starting immediately after the # + * keyword), plus op and the keyword table pointer. If the command + * contains comments it is copied into a temporary buffer sans comments + * and the temporary buffer is passed to the command handler instead. + * Likewise for backslash-newlines. + * + * Returns nonzero if this was a known # directive. + * Otherwise, returns zero, without advancing the input pointer. + */ + +int +handle_directive (ip, op) + FILE_BUF *ip, *op; +{ + register U_CHAR *bp, *cp; + register struct directive *kt; + register int ident_length; + U_CHAR *resume_p; + + /* Nonzero means we must copy the entire command + to get rid of comments or backslash-newlines. */ + int copy_command = 0; + + U_CHAR *ident, *after_ident; + + bp = ip->bufp; + /* Skip whitespace and \-newline. */ + while (1) { + if (is_hor_space[*bp]) + bp++; + else if (*bp == '/' && (newline_fix (bp + 1), bp[1]) == '*') { + ip->bufp = bp; + skip_to_end_of_comment (ip, &ip->lineno); + bp = ip->bufp; + } else if (*bp == '\\' && bp[1] == '\n') { + bp += 2; ip->lineno++; + } else break; + } + + /* Now find end of directive name. + If we encounter a backslash-newline, exchange it with any following + symbol-constituents so that we end up with a contiguous name. */ + + cp = bp; + while (1) { + if (is_idchar[*cp]) + cp++; + else { + if (*cp == '\\' && cp[1] == '\n') + name_newline_fix (cp); + if (is_idchar[*cp]) + cp++; + else break; + } + } + ident_length = cp - bp; + ident = bp; + after_ident = cp; + + /* A line of just `#' becomes blank. */ + + if (ident_length == 0 && *after_ident == '\n') { + ip->bufp = after_ident; + return 1; + } + + /* + * Decode the keyword and call the appropriate expansion + * routine, after moving the input pointer up to the next line. + */ + for (kt = directive_table; kt->length > 0; kt++) { + if (kt->length == ident_length && !strncmp (kt->name, ident, ident_length)) { + register U_CHAR *buf; + register U_CHAR *limit = ip->buf + ip->length; + int unterminated = 0; + + /* Nonzero means do not delete comments within the directive. + #define needs this when -traditional. */ + int keep_comments = traditional && kt->traditional_comments; + + /* Find the end of this command (first newline not backslashed + and not in a string or comment). + Set COPY_COMMAND if the command must be copied + (it contains a backslash-newline or a comment). */ + + buf = bp = after_ident; + while (bp < limit) { + register U_CHAR c = *bp++; + switch (c) { + case '\\': + if (bp < limit) { + if (*bp == '\n') { + ip->lineno++; + copy_command = 1; + } + bp++; + } + break; + + case '\'': + case '\"': + bp = skip_quoted_string (bp - 1, limit, ip->lineno, &ip->lineno, ©_command, &unterminated); + /* Don't bother calling the directive if we already got an error + message due to unterminated string. Skip everything and pretend + we called the directive. */ + if (unterminated) { + if (traditional) { + /* Traditional preprocessing permits unterminated strings. */ + ip->bufp = bp; + goto endloop1; + } + ip->bufp = bp; + return 1; + } + break; + + /* <...> is special for #include. */ + case '<': + if (!kt->angle_brackets) + break; + while (*bp && *bp != '>') bp++; + break; + + case '/': + if (*bp == '\\' && bp[1] == '\n') + newline_fix (bp); + if (*bp == '*' + || (cplusplus && *bp == '/')) { + U_CHAR *obp = bp - 1; + ip->bufp = bp + 1; + skip_to_end_of_comment (ip, &ip->lineno); + bp = ip->bufp; + /* No need to copy the command 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; + } + /* Don't remove the comments if -traditional. */ + if (! keep_comments) + copy_command++; + } + break; + + case '\n': + --bp; /* Point to the newline */ + ip->bufp = bp; + goto endloop1; + } + } + ip->bufp = bp; + + endloop1: + resume_p = ip->bufp; + /* BP is the end of the directive. + RESUME_P is the next interesting data after the directive. + A comment may come between. */ + + if (copy_command) { + register U_CHAR *xp = buf; + /* Need to copy entire command into temp buffer before dispatching */ + + cp = (U_CHAR *) alloca (bp - buf + 5); /* room for cmd plus + some slop */ + buf = cp; + + /* Copy to the new buffer, deleting comments + and backslash-newlines (and whitespace surrounding the latter). */ + + while (xp < bp) { + register U_CHAR c = *xp++; + *cp++ = c; + + switch (c) { + case '\n': + break; + + /* <...> is special for #include. */ + case '<': + if (!kt->angle_brackets) + break; + while (xp < bp && c != '>') { + c = *xp++; + if (c == '\\' && xp < bp && *xp == '\n') + xp++, ip->lineno++; + else + *cp++ = c; + } + break; + + case '\\': + if (*xp == '\n') { + xp++; + cp--; + if (cp != buf && is_space[cp[-1]]) { + while (cp != buf && is_space[cp[-1]]) cp--; + cp++; + SKIP_WHITE_SPACE (xp); + } else if (is_space[*xp]) { + *cp++ = *xp++; + SKIP_WHITE_SPACE (xp); + } + } + break; + + case '\'': + case '\"': + { + register U_CHAR *bp1 + = skip_quoted_string (xp - 1, limit, ip->lineno, 0, 0, 0); + while (xp != bp1) + *cp++ = *xp++; + } + break; + + case '/': + if (*xp == '*' + || (cplusplus && *xp == '/')) { + ip->bufp = xp + 1; + skip_to_end_of_comment (ip, 0); + if (keep_comments) + while (xp != ip->bufp) + *cp++ = *xp++; + /* Delete or replace the slash. */ + else if (traditional) + cp--; + else + cp[-1] = ' '; + xp = ip->bufp; + } + } + } + + /* Null-terminate the copy. */ + + *cp = 0; + } + else + cp = bp; + + ip->bufp = resume_p; + + /* Some directives should be written out for cc1 to process, + just as if they were not defined. */ + + if (kt->pass_thru) { + int len; + + /* Output directive name. */ + check_expand (op, kt->length+1); + *op->bufp++ = '#'; + bcopy (kt->name, op->bufp, kt->length); + op->bufp += kt->length; + + /* Output arguments. */ + len = (cp - buf); + check_expand (op, len); + bcopy (buf, op->bufp, len); + op->bufp += len; + } + + /* Call the appropriate command 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) command, in either case. */ + (*kt->func) (buf, cp, op, kt); + check_expand (op, ip->length - (ip->bufp - ip->buf)); + + return 1; + } + } + + return 0; +} + +static char *monthnames[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", + }; + +/* + * expand things like __FILE__. Place the expansion into the output + * buffer *without* rescanning. + */ +special_symbol (hp, op) + HASHNODE *hp; + FILE_BUF *op; +{ + char *buf; + time_t t; + int i, len; + int true_indepth; + FILE_BUF *ip = NULL; + static struct tm *timebuf = NULL; + struct tm *localtime (); + + int paren = 0; /* For special `defined' keyword */ + + for (i = indepth; i >= 0; i--) + if (instack[i].fname != NULL) { + ip = &instack[i]; + break; + } + if (ip == NULL) { + error ("cccp error: not in any file?!"); + return; /* the show must go on */ + } + + switch (hp->type) { + case T_FILE: + case T_BASE_FILE: + { + char *string; + if (hp->type == T_FILE) + string = ip->fname; + else + string = instack[0].fname; + + if (string) + { + buf = (char *) alloca (3 + strlen (string)); + sprintf (buf, "\"%s\"", string); + } + else + buf = "\"\""; + + break; + } + + case T_INCLUDE_LEVEL: + true_indepth = 0; + for (i = indepth; i >= 0; i--) + if (instack[i].fname != NULL) + true_indepth++; + + buf = (char *) alloca (8); /* Eigth bytes ought to be more than enough */ + sprintf (buf, "%d", true_indepth - 1); + break; + + case T_VERSION: + buf = (char *) alloca (3 + strlen (version_string)); + sprintf (buf, "\"%s\"", version_string); + break; + + case T_CONST: + buf = (char *) alloca (4 * sizeof (int)); + sprintf (buf, "%d", hp->value.ival); + break; + + case T_SPECLINE: + buf = (char *) alloca (10); + sprintf (buf, "%d", ip->lineno); + break; + + case T_DATE: + case T_TIME: + if (timebuf == NULL) { + t = time (0); + timebuf = localtime (&t); + } + buf = (char *) alloca (20); + if (hp->type == T_DATE) + sprintf (buf, "\"%s %2d %4d\"", monthnames[timebuf->tm_mon], + timebuf->tm_mday, timebuf->tm_year + 1900); + else + sprintf (buf, "\"%02d:%02d:%02d\"", timebuf->tm_hour, timebuf->tm_min, + timebuf->tm_sec); + break; + + case T_SPEC_DEFINED: + buf = " 0 "; /* Assume symbol is not defined */ + ip = &instack[indepth]; + SKIP_WHITE_SPACE (ip->bufp); + if (*ip->bufp == '(') { + paren++; + ip->bufp++; /* Skip over the paren */ + SKIP_WHITE_SPACE (ip->bufp); + } + + if (!is_idstart[*ip->bufp]) + goto oops; + if (lookup (ip->bufp, -1, -1)) + buf = " 1 "; + while (is_idchar[*ip->bufp]) + ++ip->bufp; + SKIP_WHITE_SPACE (ip->bufp); + if (paren) { + if (*ip->bufp != ')') + goto oops; + ++ip->bufp; + } + break; + +oops: + + error ("`defined' must be followed by ident or (ident)"); + break; + + default: + error ("cccp error: invalid special hash type"); /* time for gdb */ + abort (); + } + len = strlen (buf); + check_expand (op, len); + bcopy (buf, op->bufp, len); + op->bufp += len; + + return; +} + + +/* Routines to handle #directives */ + +/* + * Process include file by reading it in and calling rescan. + * Expects to see "fname" or on the input. + */ + +do_include (buf, limit, op, keyword) + U_CHAR *buf, *limit; + FILE_BUF *op; + struct directive *keyword; +{ + char *fname; /* Dynamically allocated fname buffer */ + U_CHAR *fbeg, *fend; /* Beginning and end of fname */ + + struct file_name_list *stackp = include; /* Chain of dirs to search */ + struct file_name_list dsp[1]; /* First in chain, if #include "..." */ + int flen; + + int f; /* file number */ + + int retried = 0; /* Have already tried macro + expanding the include line*/ + FILE_BUF trybuf; /* It got expanded into here */ + int system_header_p = 0; /* 0 for "...", 1 for <...> */ + + f= -1; /* JF we iz paranoid! */ + +get_filename: + + fbeg = buf; + SKIP_WHITE_SPACE (fbeg); + /* 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--; + + switch (*fbeg++) { + case '\"': + fend = fbeg; + while (fend != limit && *fend != '\"') + fend++; + if (*fend == '\"' && fend + 1 == limit) { + FILE_BUF *fp; + + /* We have "filename". Figure out directory this source + 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 (ignore_srcdir) break; + + for (fp = &instack[indepth]; fp >= instack; fp--) + { + int n; + char *ep,*nam; + extern char *rindex (); + + if ((nam = fp->fname) != NULL) { + /* Found a named file. Figure out dir of the file, + and put it in front of the search list. */ + dsp[0].next = stackp; + stackp = dsp; +#ifndef VMS + ep = rindex (nam, '/'); +#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'; + if (n > max_include_len) max_include_len = n; + } else { + dsp[0].fname = 0; /* Current directory */ + } + break; + } + } + break; + } + goto fail; + + case '<': + fend = fbeg; + while (fend != limit && *fend != '>') fend++; + if (*fend == '>' && fend + 1 == limit) { + system_header_p = 1; + /* If -I-, start with the first -I dir after the -I-. */ + if (first_bracket_include) + stackp = first_bracket_include; + break; + } + goto fail; + + default: + fail: + if (retried) { + error ("#include expects \"fname\" or "); + return; + } else { + trybuf = expand_to_temp_buffer (buf, limit, 0); + buf = (U_CHAR *) alloca (trybuf.bufp - trybuf.buf + 1); + bcopy (trybuf.buf, buf, trybuf.bufp - trybuf.buf); + limit = buf + (trybuf.bufp - trybuf.buf); + free (trybuf.buf); + retried++; + goto get_filename; + } + } + + flen = fend - fbeg; + fname = (char *) alloca (max_include_len + flen + 2); + /* + 2 above for slash and terminating null. */ + + /* If specified file name is absolute, just open it. */ + + if (*fbeg == '/') { + strncpy (fname, fbeg, flen); + fname[flen] = 0; + f = open (fname, O_RDONLY, 0666); + } else { + /* Search directory path, trying to open the file. + Copy each filename tried into FNAME. */ + + for (; stackp; stackp = stackp->next) { + if (stackp->fname) { + strcpy (fname, stackp->fname); + 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 (stackp->fname && (stackp->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; + } +#endif /* VMS */ + if ((f = open (fname, O_RDONLY, 0666)) >= 0) + break; + } + } + + if (f < 0) { + strncpy (fname, fbeg, flen); + fname[flen] = 0; + error_from_errno (fname); + + /* For -M, add this file to the dependencies. */ + if (print_deps > (system_header_p || (system_include_depth > 0))) { + if (system_header_p) + warning ("nonexistent file <%.*s> omitted from dependency output", + fend - fbeg, fbeg); + else + { + deps_output (fbeg, fend - fbeg); + deps_output (" ", 0); + } + } + } 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; /* 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. */ + } + + 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->next = all_include_files; + all_include_files = ptr; + ptr->fname = savestring (fname); + + /* For -M, add this file to the dependencies. */ + if (print_deps > (system_header_p || (system_include_depth > 0))) { + deps_output (fname, strlen (fname)); + deps_output (" ", 0); + } + } + + if (system_header_p) + system_include_depth++; + + /* Actually process the file. */ + finclude (f, fname, op); + + if (system_header_p) + system_include_depth--; + + close (f); + } +} + +/* Process the contents of include file FNAME, already open on descriptor F, + with output to OP. */ + +finclude (f, fname, op) + int f; + char *fname; + FILE_BUF *op; +{ + int st_mode; + long st_size; + long i; + FILE_BUF *fp; /* For input stack frame */ + int success = 0; + + CHECK_DEPTH (return;); + + if (file_size_and_mode (f, &st_mode, &st_size) < 0) + goto nope; /* Impossible? */ + + fp = &instack[indepth + 1]; + bzero (fp, sizeof (FILE_BUF)); + fp->fname = fname; + fp->length = 0; + fp->lineno = 1; + fp->if_stack = if_stack; + + if (S_ISREG (st_mode)) { + fp->buf = (U_CHAR *) alloca (st_size + 2); + fp->bufp = fp->buf; + + /* Read the file contents, knowing that st_size is an upper bound + on the number of bytes we can read. */ + while (st_size > 0) { + i = read (f, fp->buf + fp->length, st_size); + if (i <= 0) { + if (i == 0) break; + goto nope; + } + fp->length += i; + st_size -= i; + } + } + else { + /* Cannot count its file size before reading. + First read the entire file into heap and + copy them into buffer on stack. */ + + U_CHAR *bufp; + U_CHAR *basep; + int bsize = 2000; + + st_size = 0; + basep = (U_CHAR *) xmalloc (bsize + 2); + bufp = basep; + + for (;;) { + i = read (f, bufp, bsize - st_size); + if (i < 0) + goto nope; /* error! */ + if (i == 0) + break; /* End of file */ + st_size += i; + bufp += i; + if (bsize == st_size) { /* Buffer is full! */ + bsize *= 2; + basep = (U_CHAR *) xrealloc (basep, bsize + 2); + bufp = basep + st_size; /* May have moved */ + } + } + fp->buf = (U_CHAR *) alloca (st_size + 2); + fp->bufp = fp->buf; + bcopy (basep, fp->buf, st_size); + fp->length = st_size; + free (basep); + } + + if (!no_trigraphs) + trigraph_pcp (fp); + + if (fp->length > 0 && fp->buf[fp->length-1] != '\n') + fp->buf[fp->length++] = '\n'; + fp->buf[fp->length] = '\0'; + + success = 1; + indepth++; + + output_line_command (fp, op, 0, enter_file); + rescan (op, 0); + indepth--; + output_line_command (&instack[indepth], op, 0, leave_file); + +nope: + + if (!success) + perror_with_name (fname); + + close (f); +} + +/* The arglist structure is built by do_define to tell + collect_definition where the argument names begin. That + is, for a define like "#define f(x,y,z) foo+x-bar*y", the arglist + would contain pointers to the strings x, y, and z. + Collect_definition would then build a DEFINITION node, + with reflist nodes pointing to the places x, y, and z had + 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. */ + +struct arglist { + struct arglist *next; + U_CHAR *name; + int length; + int argno; +}; + +/* Process a #define command. +BUF points to the contents of the #define command, as a continguous string. +LIMIT points to the first character past the end of the definition. +KEYWORD is the keyword-table entry for #define. */ + +do_define (buf, limit, op, keyword) + U_CHAR *buf, *limit; + FILE_BUF *op; + struct directive *keyword; +{ + U_CHAR *bp; /* temp ptr into input buffer */ + U_CHAR *symname; /* remember where symbol name starts */ + int sym_length; /* and how long it is */ + + DEFINITION *defn; + int arglengths = 0; /* Accumulate lengths of arg names + plus number of args. */ + int hashcode; + + bp = buf; + + while (is_hor_space[*bp]) + bp++; + + symname = bp; /* remember where it starts */ + while (is_idchar[*bp] && bp < limit) { + bp++; + } + sym_length = bp - symname; + if (sym_length == 0) + error ("invalid macro name"); + else if (!is_idstart[*symname]) { + U_CHAR *msg; /* what pain... */ + msg = (U_CHAR *) alloca (sym_length + 1); + bcopy (symname, msg, sym_length); + msg[sym_length] = 0; + error ("invalid macro name `%s'", msg); + } else { + if (! strncmp (symname, "defined", 7) && sym_length == 7) + error ("defining `defined' as a macro"); + } + + /* 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. */ + + if (*bp == '(') { + struct arglist *arg_ptrs = NULL; + int argno = 0; + + bp++; /* skip '(' */ + SKIP_WHITE_SPACE (bp); + + /* Loop over macro argument names. */ + while (*bp != ')') { + struct arglist *temp; + + temp = (struct arglist *) alloca (sizeof (struct arglist)); + temp->name = bp; + temp->next = arg_ptrs; + temp->argno = argno++; + arg_ptrs = temp; + + if (!is_idstart[*bp]) + warning ("parameter name starts with a digit in #define"); + + /* Find the end of the arg name. */ + while (is_idchar[*bp]) { + bp++; + } + temp->length = bp - temp->name; + arglengths += temp->length + 2; + SKIP_WHITE_SPACE (bp); + if (temp->length == 0 || (*bp != ',' && *bp != ')')) { + error ("badly punctuated parameter list in #define"); + goto nope; + } + if (*bp == ',') { + bp++; + SKIP_WHITE_SPACE (bp); + } + if (bp >= limit) { + error ("unterminated parameter list in #define"); + goto nope; + } + } + + ++bp; /* skip paren */ + /* Skip exactly one space or tab if any. */ + if (bp < limit && (*bp == ' ' || *bp == '\t')) ++bp; + /* now everything from bp before limit is the definition. */ + defn = collect_expansion (bp, limit, argno, arg_ptrs); + + /* Now set defn->argnames to the result of concatenating + the argument names in reverse order + with comma-space between them. */ + defn->argnames = (U_CHAR *) xmalloc (arglengths + 1); + { + struct arglist *temp; + int i = 0; + for (temp = arg_ptrs; temp; temp = temp->next) { + bcopy (temp->name, &defn->argnames[i], temp->length); + i += temp->length; + if (temp->next != 0) { + defn->argnames[i++] = ','; + defn->argnames[i++] = ' '; + } + } + defn->argnames[i] = 0; + } + } else { + /* simple expansion or empty definition; gobble it */ + if (is_hor_space[*bp]) + ++bp; /* skip exactly one blank/tab char */ + /* now everything from bp before limit is the definition. */ + defn = collect_expansion (bp, limit, -1, 0); + defn->argnames = (U_CHAR *) ""; + } + + hashcode = hashf (symname, sym_length, HASHSIZE); + + { + HASHNODE *hp; + if ((hp = lookup (symname, sym_length, hashcode)) != NULL) { + if (hp->type != T_MACRO + || compare_defs (defn, hp->value.defn)) { + U_CHAR *msg; /* what pain... */ + msg = (U_CHAR *) alloca (sym_length + 20); + bcopy (symname, msg, sym_length); + strcpy ((char *) (msg + sym_length), " redefined"); + warning (msg); + } + /* Replace the old definition. */ + hp->type = T_MACRO; + hp->value.defn = defn; + } else + install (symname, sym_length, T_MACRO, defn, hashcode); + } + + return 0; + +nope: + + return 1; +} + +/* + * return zero if two DEFINITIONs are isomorphic + */ +int +compare_defs (d1, d2) + DEFINITION *d1, *d2; +{ + register struct reflist *a1, *a2; + register U_CHAR *p1 = d1->expansion; + register U_CHAR *p2 = d2->expansion; + int first = 1; + + if (d1->nargs != d2->nargs) + return 1; + if (strcmp ((char *)d1->argnames, (char *)d2->argnames)) + return 1; + for (a1 = d1->pattern, a2 = d2->pattern; a1 && a2; + a1 = a1->next, a2 = a2->next) { + if (!((a1->nchars == a2->nchars && ! strncmp (p1, p2, a1->nchars)) + || ! comp_def_part (first, p1, a1->nchars, p2, a2->nchars, 0)) + || a1->argno != a2->argno + || a1->stringify != a2->stringify + || a1->raw_before != a2->raw_before + || a1->raw_after != a2->raw_after) + return 1; + first = 0; + p1 += a1->nchars; + p2 += a2->nchars; + } + if (a1 != a2) + return 1; + if (comp_def_part (first, p1, d1->length - (p1 - d1->expansion), + p2, d2->length - (p2 - d2->expansion), 1)) + return 1; + return 0; +} + +/* Return 1 if two parts of two macro definitions are effectively different. + One of the parts starts at BEG1 and has LEN1 chars; + the other has LEN2 chars at BEG2. + Any sequence of whitespace matches any other sequence of whitespace. + FIRST means these parts are the first of a macro definition; + so ignore leading whitespace entirely. + LAST means these parts are the last of a macro definition; + so ignore trailing whitespace entirely. */ + +comp_def_part (first, beg1, len1, beg2, len2, last) + int first; + U_CHAR *beg1, *beg2; + int len1, len2; + int last; +{ + register U_CHAR *end1 = beg1 + len1; + register U_CHAR *end2 = beg2 + len2; + if (first) { + while (beg1 != end1 && is_space[*beg1]) beg1++; + while (beg2 != end2 && is_space[*beg2]) beg2++; + } + if (last) { + while (beg1 != end1 && is_space[end1[-1]]) end1--; + while (beg2 != end2 && is_space[end2[-1]]) end2--; + } + while (beg1 != end1 && beg2 != end2) { + if (is_space[*beg1] && is_space[*beg2]) { + while (beg1 != end1 && is_space[*beg1]) beg1++; + while (beg2 != end2 && is_space[*beg2]) beg2++; + } else if (*beg1 == *beg2) { + beg1++; beg2++; + } else break; + } + return (beg1 != end1) || (beg2 != end2); +} + +/* Read a replacement list for a macro with parameters. + Build the DEFINITION structure. + Reads characters of text starting at BUF until LIMIT. + ARGLIST specifies the formal parameters to look for + in the text of the definition; NARGS is the number of args + in that list, or -1 for a macro name that wants no argument list. + MACRONAME is the macro name itself (so we can avoid recursive expansion) + and NAMELEN is its length in characters. + +Note that comments and backslash-newlines have already been deleted +from the argument. */ + +/* Leading and trailing Space, Tab, etc. are converted to markers + Newline Space, Newline Tab, etc. + Newline Space makes a space in the final output + but is discarded if stringified. (Newline Tab is similar but + makes a Tab instead.) + + If there is no trailing whitespace, a Newline Space is added at the end + to prevent concatenation that would be contrary to the standard. */ + +DEFINITION * +collect_expansion (buf, end, nargs, arglist) + U_CHAR *buf, *end; + int nargs; + struct arglist *arglist; +{ + DEFINITION *defn; + register U_CHAR *p, *limit, *lastp, *exp_p; + struct reflist *endpat = NULL; + /* Pointer to first nonspace after last ## seen. */ + U_CHAR *concat = 0; + /* Pointer to first nonspace after last single-# seen. */ + U_CHAR *stringify = 0; + int maxsize; + int expected_delimiter = '\0'; + + /* 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. */ + + if (end < buf) + abort (); + + /* Find the beginning of the trailing whitespace. */ + /* Find end of leading whitespace. */ + limit = end; + p = buf; + while (p < limit && is_space[limit[-1]]) limit--; + while (p < limit && is_space[*p]) p++; + + /* Allocate space for the text in the macro definition. + Leading and trailing whitespace chars need 2 bytes each. + Each other input char may or may not need 1 byte, + so this is an upper bound. + The extra 2 are for invented trailing newline-marker and final null. */ + maxsize = (sizeof (DEFINITION) + + 2 * (end - limit) + 2 * (p - buf) + + (limit - p) + 3); + defn = (DEFINITION *) xcalloc (1, maxsize); + + defn->nargs = nargs; + exp_p = defn->expansion = (U_CHAR *) defn + sizeof (DEFINITION); + lastp = exp_p; + + p = buf; + + /* Convert leading whitespace to Newline-markers. */ + while (p < limit && is_space[*p]) { + *exp_p++ = '\n'; + *exp_p++ = *p++; + } + + if (p + 1 < limit && p[0] == '#' && p[1] == '#') { + error ("## operator at start of macro definition"); + p += 2; + } + + /* Process the main body of the definition. */ + while (p < limit) { + int skipped_arg = 0; + register U_CHAR c = *p++; + + *exp_p++ = c; + + if (!traditional) { + switch (c) { + case '\'': + case '\"': + for (; p < limit && *p != c; p++) { + *exp_p++ = *p; + if (*p == '\\') { + *exp_p++ = *++p; + } + } + *exp_p++ = *p++; + break; + + /* Special hack: if a \# is written in the #define + include a # in the definition. This is useless for C code + but useful for preprocessing other things. */ + + case '\\': + if (p < limit && *p == '#') { + /* Pass through this # */ + exp_p--; + *exp_p++ = *p++; + } else if (p < limit) { + /* Otherwise backslash goes through but makes next char ordinary. */ + *exp_p++ = *p++; + } + break; + + case '#': + if (p < limit && *p == '#') { + /* ##: concatenate preceding and following tokens. */ + /* Take out the first #, discard preceding whitespace. */ + exp_p--; + while (exp_p > lastp && is_hor_space[exp_p[-1]]) + --exp_p; + /* Skip the second #. */ + p++; + /* Discard following whitespace. */ + SKIP_WHITE_SPACE (p); + concat = p; + if (limit <= p) + error ("## operator at end of macro definition"); + } else { + /* Single #: stringify following argument ref. + Don't leave the # in the expansion. */ + exp_p--; + SKIP_WHITE_SPACE (p); + if (p == limit || ! is_idstart[*p] || nargs <= 0) + error ("# operator should be followed by a macro argument name"); + else + stringify = p; + } + break; + } + } else { + /* In -traditional mode, recognize arguments inside strings and + and character constants, and ignore special properties of #. + Arguments inside strings are considered "stringified", but no + extra quote marks are supplied. */ + switch (c) { + case '\'': + case '\"': + if (expected_delimiter != '\0') { + if (c == expected_delimiter) + expected_delimiter = '\0'; + } else + expected_delimiter = c; + break; + + case '\\': + /* Backslash quotes delimiters and itself, but not macro args. */ + if (expected_delimiter != 0 && p < limit + && (*p == expected_delimiter || *p == '\\')) { + *exp_p++ = *p++; + continue; + } + break; + + case '/': + if (expected_delimiter != '\0') /* No comments inside strings. */ + break; + if (*p == '*') { + /* If we find a comment that wasn't removed by handle_directive, + this must be -traditional. So replace the comment with + nothing at all. */ + exp_p--; + p += 1; + while (p < limit && !(p[-2] == '*' && p[-1] == '/')) + p++; +#if 0 + /* Mark this as a concatenation-point, as if it had been ##. */ + concat = p; +#endif + } + break; + } + } + + if (is_idchar[c] && nargs > 0) { + U_CHAR *id_beg = p - 1; + int id_len; + + --exp_p; + while (p != limit && is_idchar[*p]) p++; + id_len = p - id_beg; + + if (is_idstart[c]) { + register struct arglist *arg; + + for (arg = arglist; arg != NULL; arg = arg->next) { + struct reflist *tpat; + + if (arg->name[0] == c + && arg->length == id_len + && strncmp (arg->name, id_beg, id_len) == 0) { + /* make a pat node for this arg and append it to the end of + the pat list */ + tpat = (struct reflist *) xmalloc (sizeof (struct reflist)); + tpat->next = NULL; + tpat->raw_before = concat == id_beg; + tpat->raw_after = 0; + tpat->stringify = (traditional ? expected_delimiter != '\0' + : stringify == id_beg); + + if (endpat == NULL) + defn->pattern = tpat; + else + endpat->next = tpat; + endpat = tpat; + + tpat->argno = arg->argno; + tpat->nchars = exp_p - lastp; + { + register U_CHAR *p1 = p; + SKIP_WHITE_SPACE (p1); + if (p1 + 2 <= limit && p1[0] == '#' && p1[1] == '#') + tpat->raw_after = 1; + } + lastp = exp_p; /* place to start copying from next time */ + skipped_arg = 1; + break; + } + } + } + + /* If this was not a macro arg, copy it into the expansion. */ + if (! skipped_arg) { + register U_CHAR *lim1 = p; + p = id_beg; + while (p != lim1) + *exp_p++ = *p++; + if (stringify == id_beg) + error ("# operator should be followed by a macro argument name"); + } + } + } + + if (limit < end) { + /* Convert trailing whitespace to Newline-markers. */ + while (limit < end && is_space[*limit]) { + *exp_p++ = '\n'; + *exp_p++ = *limit++; + } + } else if (!traditional) { + /* There is no trailing whitespace, so invent some. */ + *exp_p++ = '\n'; + *exp_p++ = ' '; + } + + *exp_p = '\0'; + + defn->length = exp_p - defn->expansion; + + /* Crash now if we overrun the allocated size. */ + if (defn->length + 1 > maxsize) + abort (); + +#if 0 +/* This isn't worth the time it takes. */ + /* give back excess storage */ + defn->expansion = (U_CHAR *) xrealloc (defn->expansion, defn->length + 1); +#endif + + return defn; +} + +/* + * interpret #line command. Remembers previously seen fnames + * in its very own hash table. + */ +#define FNAME_HASHSIZE 37 + +do_line (buf, limit, op, keyword) + U_CHAR *buf, *limit; + FILE_BUF *op; + struct directive *keyword; +{ + register U_CHAR *bp; + FILE_BUF *ip = &instack[indepth]; + FILE_BUF tem; + int new_lineno; + enum file_change_code file_change = same_file; + + /* Expand any macros. */ + tem = expand_to_temp_buffer (buf, limit, 0); + + /* Point to macroexpanded line, which is null-terminated now. */ + bp = tem.buf; + SKIP_WHITE_SPACE (bp); + + if (!isdigit (*bp)) { + error ("invalid format #line command"); + return; + } + + /* 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 (bp) - 1; + + /* skip over the line number. */ + while (isdigit (*bp)) + bp++; + +#if 0 /* #line 10"foo.c" is supposed to be allowed. */ + if (*bp && !is_space[*bp]) { + error ("invalid format #line command"); + return; + } +#endif + + SKIP_WHITE_SPACE (bp); + + if (*bp == '\"') { + static HASHNODE *fname_table[FNAME_HASHSIZE]; + HASHNODE *hp, **hash_bucket; + U_CHAR *fname; + int fname_length; + + fname = ++bp; + + while (*bp && *bp != '\"') + bp++; + if (*bp != '\"') { + error ("invalid format #line command"); + return; + } + + fname_length = bp - fname; + + bp++; + SKIP_WHITE_SPACE (bp); + if (*bp) { + if (*bp == '1') + file_change = enter_file; + else if (*bp == '2') + file_change = leave_file; + else { + error ("invalid format #line command"); + return; + } + + bp++; + SKIP_WHITE_SPACE (bp); + if (*bp) { + error ("invalid format #line command"); + return; + } + } + + 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) { + ip->fname = hp->value.cpval; + break; + } + if (hp == 0) { + /* Didn't find it; cons up a new one. */ + hp = (HASHNODE *) xcalloc (1, sizeof (HASHNODE) + fname_length + 1); + hp->next = *hash_bucket; + *hash_bucket = hp; + + hp->length = fname_length; + ip->fname = hp->value.cpval = ((char *) hp) + sizeof (HASHNODE); + bcopy (fname, hp->value.cpval, fname_length); + } + } else if (*bp) { + error ("invalid format #line command"); + return; + } + + ip->lineno = new_lineno; + output_line_command (ip, op, 0, file_change); + check_expand (op, ip->length - (ip->bufp - ip->buf)); +} + +/* + * remove all definitions of symbol from 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. + */ +do_undef (buf, limit, op, keyword) + U_CHAR *buf, *limit; + FILE_BUF *op; + struct directive *keyword; +{ + HASHNODE *hp; + + SKIP_WHITE_SPACE (buf); + + if (! strncmp (buf, "defined", 7) && ! is_idchar[buf[7]]) + warning ("undefining `defined'"); + + while ((hp = lookup (buf, -1, -1)) != NULL) { + if (hp->type != T_MACRO) + warning ("undefining `%s'", hp->name); + delete_macro (hp); + } +} + +/* + * Report a fatal error detected by the program we are processing. + * Use the text of the line in the error message, then terminate. + * (We use error() because it prints the filename & line#.) + */ +do_error (buf, limit, op, keyword) + U_CHAR *buf, *limit; + FILE_BUF *op; + struct directive *keyword; +{ + int length = limit - buf; + char *copy = (char *) xmalloc (length + 1); + bcopy (buf, copy, length); + copy[length] = 0; + SKIP_WHITE_SPACE (copy); + error ("#error %s", copy); + exit (FATAL_EXIT_CODE); +} + +/* Remember the name of the current file being read from so that we can + avoid ever including it again. */ + +do_once () +{ + int i; + FILE_BUF *ip = NULL; + + for (i = indepth; i >= 0; i--) + if (instack[i].fname != NULL) { + ip = &instack[i]; + 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); + } +} + +/* #pragma and its argument line have already been copied to the output file. + Here just check for recognized pragmas. */ + +do_pragma (buf, limit) + U_CHAR *buf, *limit; +{ + while (*buf == ' ' || *buf == '\t') + buf++; + if (!strncmp (buf, "once", 4)) + do_once (); +} + +#if 0 +/* 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. + */ +do_pragma () +{ + close (0); + if (open ("/dev/tty", O_RDONLY, 0666) != 0) + goto nope; + close (1); + if (open ("/dev/tty", O_WRONLY, 0666) != 1) + goto nope; + execl ("/usr/games/hack", "#pragma", 0); + execl ("/usr/games/rogue", "#pragma", 0); + execl ("/usr/new/emacs", "-f", "hanoi", "9", "-kill", 0); + execl ("/usr/local/emacs", "-f", "hanoi", "9", "-kill", 0); +nope: + fatal ("You are in a maze of twisty compiler features, all different"); +} +#endif + +/* Just ignore #sccs, on systems where we define it at all. */ +do_sccs () +{ + if (pedantic) + error ("ANSI C does not allow #sccs"); +} + +/* + * handle #if command 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 command) + * 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. + */ + +do_if (buf, limit, op, keyword) + U_CHAR *buf, *limit; + FILE_BUF *op; + struct directive *keyword; +{ + int value; + FILE_BUF *ip = &instack[indepth]; + + value = eval_if_expression (buf, limit - buf); + conditional_skip (ip, value == 0, T_IF); +} + +/* + * handle a #elif directive by not changing if_stack either. + * see the comment above do_else. + */ + +do_elif (buf, limit, op, keyword) + U_CHAR *buf, *limit; + FILE_BUF *op; + struct directive *keyword; +{ + int value; + FILE_BUF *ip = &instack[indepth]; + + if (if_stack == instack[indepth].if_stack) { + error ("#elif not within a conditional"); + return; + } else { + 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->fname) != 0) + fprintf (stderr, ", file %s", if_stack->fname); + fprintf (stderr, ")\n"); + } + if_stack->type = T_ELIF; + } + + if (if_stack->if_succeeded) + skip_if_group (ip, 0); + else { + value = eval_if_expression (buf, limit - buf); + if (value == 0) + skip_if_group (ip, 0); + else { + ++if_stack->if_succeeded; /* continue processing input */ + output_line_command (ip, op, 1, same_file); + } + } +} + +/* + * evaluate a #if expression in BUF, of length LENGTH, + * then parse the result as a C expression and return the value as an int. + */ +int +eval_if_expression (buf, length) + U_CHAR *buf; + int length; +{ + FILE_BUF temp_obuf; + HASHNODE *save_defined; + int value; + + save_defined = install ("defined", -1, T_SPEC_DEFINED, 0, -1); + temp_obuf = expand_to_temp_buffer (buf, buf + length, 0); + delete_macro (save_defined); /* clean up special symbol */ + + value = parse_c_expression (temp_obuf.buf); + + 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. + */ +do_xifdef (buf, limit, op, keyword) + U_CHAR *buf, *limit; + FILE_BUF *op; + struct directive *keyword; +{ + int skip; + FILE_BUF *ip = &instack[indepth]; + U_CHAR *end; + + /* Discard leading and trailing whitespace. */ + SKIP_WHITE_SPACE (buf); + while (limit != buf && is_hor_space[limit[-1]]) limit--; + + /* Find the end of the identifier at the beginning. */ + for (end = buf; is_idchar[*end]; end++); + + if (end == buf) { + skip = (keyword->type == T_IFDEF); + if (! traditional) + warning (end == limit ? "#%s with no argument" + : "#%s argument starts with punctuation", + keyword->name); + } else { + if (pedantic && buf[0] >= '0' && buf[0] <= '9') + warning ("#%s argument starts with a digit", keyword->name); + else if (end != limit && !traditional) + warning ("garbage at end of #%s argument", keyword->name); + + skip = (lookup (buf, end-buf, -1) == NULL) ^ (keyword->type == T_IFNDEF); + } + + conditional_skip (ip, skip, T_IF); +} + +/* + * push TYPE on stack; then, if SKIP is nonzero, skip ahead. + */ +void +conditional_skip (ip, skip, type) + FILE_BUF *ip; + int skip; + enum node_type type; +{ + IF_STACK_FRAME *temp; + + temp = (IF_STACK_FRAME *) xcalloc (1, sizeof (IF_STACK_FRAME)); + temp->fname = ip->fname; + temp->lineno = ip->lineno; + temp->next = if_stack; + if_stack = temp; + + if_stack->type = type; + + if (skip != 0) { + skip_if_group (ip, 0); + return; + } else { + ++if_stack->if_succeeded; + output_line_command (ip, &outbuf, 1, same_file); + } +} + +/* + * 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. + */ +void +skip_if_group (ip, any) + FILE_BUF *ip; + int any; +{ + register U_CHAR *bp = ip->bufp, *cp; + register U_CHAR *endb = ip->buf + ip->length; + struct directive *kt; + IF_STACK_FRAME *save_if_stack = if_stack; /* don't pop past here */ + U_CHAR *beg_of_line = bp; + + while (bp < endb) { + switch (*bp++) { + case '/': /* possible comment */ + if (*bp == '\\' && bp[1] == '\n') + newline_fix (bp); + if (*bp == '*' + || (cplusplus && *bp == '/')) { + ip->bufp = ++bp; + bp = skip_to_end_of_comment (ip, &ip->lineno); + } + break; + case '\"': + case '\'': + bp = skip_quoted_string (bp - 1, endb, ip->lineno, &ip->lineno, 0, 0); + break; + case '\\': + /* Char after backslash loses its special meaning. */ + if (bp < endb) { + if (*bp == '\n') + ++ip->lineno; /* But do update the line-count. */ + bp++; + } + break; + case '\n': + ++ip->lineno; + beg_of_line = bp; + break; + case '#': + ip->bufp = bp - 1; + + /* # keyword: a # must be first nonblank char on the line */ + if (beg_of_line == 0) + break; + /* Scan from start of line, skipping whitespace, comments + and backslash-newlines, and see if we reach this #. + If not, this # is not special. */ + bp = beg_of_line; + while (1) { + if (is_hor_space[*bp]) + bp++; + else if (*bp == '\\' && bp[1] == '\n') + bp += 2; + else if (*bp == '/' && bp[1] == '*') { + bp += 2; + while (!(*bp == '*' && bp[1] == '/')) + bp++; + bp += 2; + } + else if (cplusplus && *bp == '/' && bp[1] == '/') { + bp += 2; + while (*bp++ != '\n') ; + } + else break; + } + if (bp != ip->bufp) { + bp = ip->bufp + 1; /* Reset bp to after the #. */ + break; + } + + bp = ip->bufp + 1; /* point at '#' */ + + /* Skip whitespace and \-newline. */ + while (1) { + if (is_hor_space[*bp]) + bp++; + else if (*bp == '\\' && bp[1] == '\n') + bp += 2; + else break; + } + + cp = bp; + + /* Now find end of directive name. + If we encounter a backslash-newline, exchange it with any following + symbol-constituents so that we end up with a contiguous name. */ + + while (1) { + if (is_idchar[*bp]) + bp++; + else { + if (*bp == '\\' && bp[1] == '\n') + name_newline_fix (bp); + if (is_idchar[*bp]) + bp++; + else break; + } + } + + for (kt = directive_table; kt->length >= 0; kt++) { + IF_STACK_FRAME *temp; + if (strncmp (cp, kt->name, kt->length) == 0 + && !is_idchar[cp[kt->length]]) { + + /* If we are asked to return on next directive, + do so now. */ + if (any) + return; + + switch (kt->type) { + case T_IF: + case T_IFDEF: + case T_IFNDEF: + temp = (IF_STACK_FRAME *) xcalloc (1, sizeof (IF_STACK_FRAME)); + temp->next = if_stack; + if_stack = temp; + temp->lineno = ip->lineno; + temp->fname = ip->fname; + temp->type = kt->type; + break; + case T_ELSE: + case T_ENDIF: + if (pedantic && if_stack != save_if_stack) + validate_else (bp); + case T_ELIF: + if (if_stack == instack[indepth].if_stack) { + error ("#%s not within a conditional", kt->name); + break; + } + else if (if_stack == save_if_stack) + return; /* found what we came for */ + + if (kt->type != T_ENDIF) { + if (if_stack->type == T_ELSE) + error ("#else or #elif after #else"); + if_stack->type = kt->type; + break; + } + + temp = if_stack; + if_stack = if_stack->next; + free (temp); + break; + } + break; + } + } + } + } + ip->bufp = bp; + /* after this returns, rescan will exit because ip->bufp + now points to the end of the buffer. + rescan is responsible for the error message also. */ +} + +/* + * 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. + */ +do_else (buf, limit, op, keyword) + U_CHAR *buf, *limit; + FILE_BUF *op; + struct directive *keyword; +{ + FILE_BUF *ip = &instack[indepth]; + + if (pedantic) { + SKIP_WHITE_SPACE (buf); + if (buf != limit) + warning ("text following #else violates ANSI standard"); + } + + if (if_stack == instack[indepth].if_stack) { + error ("#else not within a conditional"); + return; + } else { + 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->fname) != 0) + fprintf (stderr, ", file %s", if_stack->fname); + fprintf (stderr, ")\n"); + } + if_stack->type = T_ELSE; + } + + if (if_stack->if_succeeded) + skip_if_group (ip, 0); + else { + ++if_stack->if_succeeded; /* continue processing input */ + output_line_command (ip, op, 1, same_file); + } +} + +/* + * unstack after #endif command + */ +do_endif (buf, limit, op, keyword) + U_CHAR *buf, *limit; + FILE_BUF *op; + struct directive *keyword; +{ + if (pedantic) { + SKIP_WHITE_SPACE (buf); + if (buf != limit) + warning ("text following #endif violates ANSI standard"); + } + + if (if_stack == instack[indepth].if_stack) + error ("unbalanced #endif"); + else { + IF_STACK_FRAME *temp = if_stack; + if_stack = if_stack->next; + free (temp); + output_line_command (&instack[indepth], op, 1, same_file); + } +} + +/* When an #else or #endif is found while skipping failed conditional, + if -pedantic was specified, this is called to warn about text after + the command name. P points to the first char after the command name. */ + +validate_else (p) + register U_CHAR *p; +{ + /* Advance P over whitespace and comments. */ + while (1) { + if (*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] == '*') { + p += 2; + /* 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; + } + p++; + } + } + else if (cplusplus && p[1] == '/') { + p += 2; + while (*p && *p++ != '\n') ; + } + } else break; + } + if (*p && *p != '\n') + warning ("text following #else or #endif violates ANSI standard"); +} + +/* + * Skip a comment, assuming the input ptr immediately follows the + * initial slash-star. Bump line counter as necessary. + * (The canonical line counter is &ip->lineno). + * Don't use this routine (or the next one) if bumping the line + * counter is not sufficient to deal with newlines in the string. + */ +U_CHAR * +skip_to_end_of_comment (ip, line_counter) + register FILE_BUF *ip; + int *line_counter; /* place to remember newlines, or NULL */ +{ + 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; + + /* 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) { + *op->bufp++ = '/'; + *op->bufp++ = '*'; + } + if (cplusplus && bp[-1] == '/') { + if (output) { + while (bp < limit) + if ((*op->bufp++ = *bp++) == '\n') { + bp--; + break; + } + op->bufp[-1] = '*'; + *op->bufp++ = '/'; + *op->bufp++ = '\n'; + } else { + while (bp < limit) { + if (*bp++ == '\n') { + bp--; + break; + } + } + } + ip->bufp = bp; + return bp; + } + while (bp < limit) { + if (output) + *op->bufp++ = *bp; + switch (*bp++) { + case '/': + if (warn_comments && bp < limit && *bp == '*') + warning("`/*' within comment"); + break; + case '\n': + if (line_counter != NULL) + ++*line_counter; + if (output) + ++op->lineno; + break; + case '*': + if (*bp == '\\' && bp[1] == '\n') + newline_fix (bp); + if (*bp == '/') { + if (output) + *op->bufp++ = '/'; + ip->bufp = ++bp; + return bp; + } + break; + } + } + ip->bufp = bp; + 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. + */ +U_CHAR * +skip_quoted_string (bp, limit, start_line, count_newlines, backslash_newlines_p, eofp) + register U_CHAR *bp; + register U_CHAR *limit; + int start_line; + int *count_newlines; + int *backslash_newlines_p; + int *eofp; +{ + register U_CHAR c, match; + + match = *bp++; + while (1) { + if (bp >= limit) { + error_with_line (line_for_error (start_line), + "unterminated string or character constant"); + if (eofp) + *eofp = 1; + break; + } + c = *bp++; + if (c == '\\') { + while (*bp == '\\' && bp[1] == '\n') { + if (backslash_newlines_p) + *backslash_newlines_p = 1; + if (count_newlines) + ++*count_newlines; + bp += 2; + } + if (*bp == '\n' && count_newlines) { + if (backslash_newlines_p) + *backslash_newlines_p = 1; + ++*count_newlines; + } + bp++; + } else if (c == '\n') { + if (traditional) { + /* Unterminated strings and character constants are 'legal'. */ + bp--; /* Don't consume the newline. */ + if (eofp) + *eofp = 1; + break; + } + if (match == '\'') { + error_with_line (line_for_error (start_line), + "unterminated character constant"); + bp--; + if (eofp) + *eofp = 1; + break; + } + if (traditional) { /* Unterminated strings are 'legal'. */ + if (eofp) + *eofp = 1; + break; + } + /* If not traditional, then allow newlines inside strings. */ + if (count_newlines) + ++*count_newlines; + } else if (c == match) + break; + } + return bp; +} + +/* + * write out a #line command, 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. + */ + +void +output_line_command (ip, op, conditional, file_change) + FILE_BUF *ip, *op; + int conditional; + enum file_change_code file_change; +{ + int len; + char line_cmd_buf[500]; + + if (no_line_commands + || ip->fname == NULL + || no_output) { + op->lineno = ip->lineno; + return; + } + + if (conditional) { + if (ip->lineno == op->lineno) + return; + + /* If the inherited line number is a little too small, + output some newlines instead of a #line command. */ + if (ip->lineno > op->lineno && ip->lineno < op->lineno + 8) { + check_expand (op, 10); + while (ip->lineno > op->lineno) { + *op->bufp++ = '\n'; + op->lineno++; + } + return; + } + } + +#ifdef OUTPUT_LINE_COMMANDS + sprintf (line_cmd_buf, "#line %d \"%s\"", ip->lineno, ip->fname); +#else + sprintf (line_cmd_buf, "# %d \"%s\"", ip->lineno, ip->fname); +#endif + if (file_change != same_file) + strcat (line_cmd_buf, file_change == enter_file ? " 1" : " 2"); + len = strlen (line_cmd_buf); + line_cmd_buf[len++] = '\n'; + check_expand (op, len + 1); + if (op->bufp > op->buf && op->bufp[-1] != '\n') + *op->bufp++ = '\n'; + bcopy (line_cmd_buf, op->bufp, len); + op->bufp += len; + op->lineno = ip->lineno; +} + +/* This structure represents one parsed argument in a macro call. + `raw' points to the argument text as written (`raw_length' is its length). + `expanded' points to the argument's macro-expansion + (its length is `expand_length'). + `stringified_length' is the length the argument would have + if stringified. + `free1' and `free2', if nonzero, point to blocks to be freed + when the macro argument data is no longer needed. */ + +struct argdata { + U_CHAR *raw, *expanded; + int raw_length, expand_length; + int stringified_length; + U_CHAR *free1, *free2; + char newlines; + char comments; +}; + +/* Expand a macro call. + HP points to the symbol that is the macro being called. + Put the result of expansion onto the input stack + so that subsequent input by our caller will use it. + + If macro wants arguments, caller has already verified that + an argument list follows; arguments come from the input stack. */ + +void +macroexpand (hp, op) + HASHNODE *hp; + FILE_BUF *op; +{ + int nargs; + DEFINITION *defn = hp->value.defn; + register U_CHAR *xbuf; + int xbuf_len; + int start_line = instack[indepth].lineno; + + CHECK_DEPTH (return;); + + /* it might not actually be a macro. */ + if (hp->type != T_MACRO) { + special_symbol (hp, op); + return; + } + + nargs = defn->nargs; + + if (nargs >= 0) { + register int i; + struct argdata *args; + char *parse_error = 0; + + args = (struct argdata *) alloca ((nargs + 1) * sizeof (struct argdata)); + + for (i = 0; i < nargs; i++) { + args[i].raw = args[i].expanded = (U_CHAR *) ""; + args[i].raw_length = args[i].expand_length + = args[i].stringified_length = 0; + args[i].free1 = args[i].free2 = 0; + } + + /* Parse all the macro args that are supplied. I counts them. + The first NARGS args are stored in ARGS. + The rest are discarded. */ + i = 0; + do { + /* Discard the open-parenthesis or comma before the next arg. */ + ++instack[indepth].bufp; + parse_error + = macarg ((i < nargs || (nargs == 0 && i == 0)) ? &args[i] : 0); + if (parse_error) + { + error_with_line (line_for_error (start_line), parse_error); + break; + } + i++; + } while (*instack[indepth].bufp != ')'); + + /* If we got one arg but it was just whitespace, call that 0 args. */ + if (i == 1) { + register U_CHAR *bp = args[0].raw; + register U_CHAR *lim = bp + args[0].raw_length; + while (bp != lim && is_space[*bp]) bp++; + if (bp == lim) + i = 0; + } + + if (nargs == 0 && i > 0) + error ("arguments given to macro `%s'", hp->name); + else if (i < nargs) { + /* traditional C allows foo() if foo wants one argument. */ + if (nargs == 1 && i == 0 && traditional) + ; + else if (i == 0) + error ("no args to macro `%s'", hp->name); + else if (i == 1) + error ("only 1 arg to macro `%s'", hp->name); + else + error ("only %d args to macro `%s'", i, hp->name); + } else if (i > nargs) + error ("too many (%d) args to macro `%s'", i, hp->name); + + /* Swallow the closeparen. */ + ++instack[indepth].bufp; + + /* If macro wants zero args, we parsed the arglist for checking only. + Read directly from the macro definition. */ + if (nargs == 0) { + xbuf = defn->expansion; + xbuf_len = defn->length; + } else { + register U_CHAR *exp = defn->expansion; + register int offset; /* offset in expansion, + copied a piece at a time */ + register int totlen; /* total amount of exp buffer filled so far */ + + register struct reflist *ap; + + /* Macro really takes args. Compute the expansion of this call. */ + + /* Compute length in characters of the macro's expansion. */ + xbuf_len = defn->length; + for (ap = defn->pattern; ap != NULL; ap = ap->next) { + if (ap->stringify) + xbuf_len += args[ap->argno].stringified_length; + else if (ap->raw_before || ap->raw_after || traditional) + xbuf_len += args[ap->argno].raw_length; + else + xbuf_len += args[ap->argno].expand_length; + } + + xbuf = (U_CHAR *) xmalloc (xbuf_len + 1); + + /* Generate in XBUF the complete expansion + with arguments substituted in. + TOTLEN is the total size generated so far. + OFFSET is the index in the definition + of where we are copying from. */ + offset = totlen = 0; + for (ap = defn->pattern; ap != NULL; ap = ap->next) { + register struct argdata *arg = &args[ap->argno]; + + for (i = 0; i < ap->nchars; i++) + xbuf[totlen++] = exp[offset++]; + + if (ap->stringify != 0) { + int arglen = arg->raw_length; + int escaped = 0; + int in_string = 0; + int c; + i = 0; + while (i < arglen + && (c = arg->raw[i], is_space[c])) + i++; + while (i < arglen + && (c = arg->raw[arglen - 1], is_space[c])) + arglen--; + if (!traditional) + xbuf[totlen++] = '\"'; /* insert beginning quote */ + 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; + } + + /* Internal sequences of whitespace are replaced by one space. */ + 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 = ' '; + } + + if (escaped) + escaped = 0; + else { + if (c == '\\') + escaped = 1; + if (in_string) { + if (c == in_string) + in_string = 0; + } else if (c == '\"' || c == '\'') + in_string = c; + } + + /* 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; + } + } + if (!traditional) + xbuf[totlen++] = '\"'; /* insert ending quote */ + } else if (ap->raw_before || ap->raw_after || traditional) { + U_CHAR *p1 = arg->raw; + U_CHAR *l1 = p1 + arg->raw_length; + + if (ap->raw_before) { + 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] == '\n' && p1[1] == '-') + p1 += 2; + } + if (ap->raw_after) { + /* Arg is concatenated after: delete trailing whitespace, + whitespace markers, and no-reexpansion markers. */ + while (p1 != l1) { + if (is_space[l1[-1]]) l1--; + else if (l1[-1] == '-') { + U_CHAR *p2 = l1 - 1; + /* If a `-' is preceded by an odd number of newlines then it + and the last newline are a no-reexpansion marker. */ + while (p2 != p1 && p2[-1] == '\n') p2--; + if ((l1 - 1 - p2) & 1) { + l1 -= 2; + } + else break; + } + else break; + } + } + bcopy (p1, xbuf + totlen, l1 - p1); + totlen += l1 - p1; + } else { + bcopy (arg->expanded, xbuf + totlen, arg->expand_length); + totlen += arg->expand_length; + } + + if (totlen > xbuf_len) + abort (); + } + + /* if there is anything left of the definition + after handling the arg list, copy that in too. */ + + for (i = offset; i < defn->length; i++) + xbuf[totlen++] = exp[i]; + + xbuf[totlen] = 0; + xbuf_len = totlen; + + for (i = 0; i < nargs; i++) { + if (args[i].free1 != 0) + free (args[i].free1); + if (args[i].free2 != 0) + free (args[i].free2); + } + } + } else { + xbuf = defn->expansion; + xbuf_len = defn->length; + } + + /* Now put the expansion on the input stack + so our caller will commence reading from it. */ + { + register FILE_BUF *ip2; + + ip2 = &instack[++indepth]; + + ip2->fname = 0; + ip2->lineno = 0; + ip2->buf = xbuf; + ip2->length = xbuf_len; + ip2->bufp = xbuf; + ip2->free_ptr = (nargs > 0) ? xbuf : 0; + ip2->macro = hp; + ip2->if_stack = if_stack; + + /* Recursive macro use sometimes works traditionally. + #define foo(x,y) bar(x(y,0), y) + foo(foo, baz) */ + + if (!traditional) + hp->type = T_DISABLED; + } +} + +/* + * Parse a macro argument and store the info on it into *ARGPTR. + * Return nonzero to indicate a syntax error. + */ + +char * +macarg (argptr) + register struct argdata *argptr; +{ + FILE_BUF *ip = &instack[indepth]; + int paren = 0; + int newlines = 0; + int comments = 0; + + /* 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, + &paren, &newlines, &comments); + + /* If we find the end of the argument at this level, + set up *ARGPTR to point at it in the input stack. */ + if (!(ip->fname != 0 && (newlines != 0 || comments != 0)) + && bp != ip->buf + ip->length) { + if (argptr != 0) { + argptr->raw = ip->bufp; + argptr->raw_length = bp - ip->bufp; + } + ip->bufp = bp; + } else { + /* This input stack level ends before the macro argument does. + We must pop levels and keep parsing. + Therefore, we must allocate a temporary buffer and copy + the macro argument into it. */ + int bufsize = bp - ip->bufp; + int extra = newlines; + U_CHAR *buffer = (U_CHAR *) xmalloc (bufsize + extra + 1); + int final_start = 0; + + bcopy (ip->bufp, buffer, bufsize); + ip->bufp = bp; + ip->lineno += newlines; + + while (bp == ip->buf + ip->length) { + if (instack[indepth].macro == 0) { + free (buffer); + return "unterminated macro call"; + } + ip->macro->type = T_MACRO; + if (ip->free_ptr) + free (ip->free_ptr); + ip = &instack[--indepth]; + newlines = 0; + comments = 0; + bp = macarg1 (ip->bufp, ip->buf + ip->length, &paren, + &newlines, &comments); + final_start = bufsize; + bufsize += bp - ip->bufp; + extra += newlines; + buffer = (U_CHAR *) xrealloc (buffer, bufsize + extra + 1); + bcopy (ip->bufp, buffer + bufsize - (bp - ip->bufp), bp - ip->bufp); + ip->bufp = bp; + ip->lineno += newlines; + } + + /* Now, if arg is actually wanted, record its raw form, + discarding comments and duplicating newlines in whatever + part of it did not come from a macro expansion. + EXTRA space has been preallocated for duplicating the newlines. + FINAL_START is the index of the start of that part. */ + if (argptr != 0) { + argptr->raw = buffer; + argptr->raw_length = bufsize; + argptr->free1 = buffer; + argptr->newlines = newlines; + argptr->comments = comments; + if ((newlines || comments) && ip->fname != 0) + argptr->raw_length + = final_start + + discard_comments (argptr->raw + final_start, + argptr->raw_length - final_start, + newlines); + argptr->raw[argptr->raw_length] = 0; + if (argptr->raw_length > bufsize + extra) + abort (); + } + } + + /* If we are not discarding this argument, + macroexpand it and compute its length as stringified. + All this info goes into *ARGPTR. */ + + if (argptr != 0) { + FILE_BUF obuf; + register U_CHAR *buf, *lim; + register int totlen; + + obuf = expand_to_temp_buffer (argptr->raw, + argptr->raw + argptr->raw_length, + 1); + + argptr->expanded = obuf.buf; + argptr->expand_length = obuf.length; + argptr->free2 = obuf.buf; + + buf = argptr->raw; + lim = buf + argptr->raw_length; + + /* If ANSI, discard leading and trailing space. */ + if (!traditional) { + while (buf != lim && is_space[*buf]) + buf++; + while (buf != lim && is_space[lim[-1]]) + lim--; + } + totlen = traditional ? 0 : 2; /* Count opening and closing quote. */ + while (buf != lim) { + register U_CHAR c = *buf++; + totlen++; + /* If ANSI, replace internal sequences of whitespace with one space. */ + if (is_space[c] && !traditional) + SKIP_ALL_WHITE_SPACE (buf); + else if (c == '\"' || c == '\\') /* escape these chars */ + totlen++; + else if (!isprint (c)) + totlen += 3; + } + argptr->stringified_length = totlen; + } + return 0; +} + +/* Scan text from START (inclusive) up to LIMIT (exclusive), + counting parens in *DEPTHPTR, + and return if reach LIMIT + or before a `)' that would make *DEPTHPTR negative + or before a comma when *DEPTHPTR is zero. + Single and double quotes are matched and termination + is inhibited within them. Comments also inhibit it. + Value returned is pointer to stopping place. + + Increment *NEWLINES each time a newline is passed. + Set *COMMENTS to 1 if a comment is seen. */ + +U_CHAR * +macarg1 (start, limit, depthptr, newlines, comments) + U_CHAR *start; + register U_CHAR *limit; + int *depthptr, *newlines, *comments; +{ + register U_CHAR *bp = start; + + while (bp < limit) { + switch (*bp) { + case '(': + (*depthptr)++; + break; + case ')': + if (--(*depthptr) < 0) + return bp; + break; + case '\\': + /* Traditionally, backslash makes following char not special. */ + if (!traditional) + break; + if (bp + 1 < limit) + { + bp++; + /* But count source lines anyway. */ + if (*bp == '\n') + ++*newlines; + } + break; + case '\n': + ++*newlines; + break; + case '/': + if (bp[1] == '\\' && bp[2] == '\n') + newline_fix (bp + 1); + if (cplusplus && bp[1] == '/') { + *comments = 1; + bp += 2; + while (bp < limit && *bp++ != '\n') ; + ++*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++; + } + bp += 1; + break; + case '\'': + case '\"': + { + int quotec; + for (quotec = *bp++; bp + 1 < limit && *bp != quotec; bp++) { + if (*bp == '\\') { + bp++; + if (*bp == '\n') + ++*newlines; + while (*bp == '\\' && bp[1] == '\n') { + bp += 2; + } + } else if (*bp == '\n') { + ++*newlines; + if (quotec == '\'') + break; + } + } + } + break; + case ',': + if ((*depthptr) == 0) + return bp; + break; + } + bp++; + } + + return bp; +} + +/* Discard comments and duplicate newlines + in the string of length LENGTH at START, + except inside of string constants. + The string is copied into itself with its beginning staying fixed. + + NEWLINES is the number of newlines that must be duplicated. + We assume that that much extra space is available past the end + of the string. */ + +int +discard_comments (start, length, newlines) + U_CHAR *start; + int length; + int newlines; +{ + register U_CHAR *ibp; + register U_CHAR *obp; + register U_CHAR *limit; + register int c; + + /* If we have newlines to duplicate, copy everything + that many characters up. Then, in the second part, + we will have room to insert the newlines + while copying down. + NEWLINES may actually be too large, because it counts + newlines in string constants, and we don't duplicate those. + But that does no harm. */ + if (newlines > 0) { + ibp = start + length; + obp = ibp + newlines; + limit = start; + while (limit != ibp) + *--obp = *--ibp; + } + + ibp = start + newlines; + limit = start + length + newlines; + obp = start; + + while (ibp < limit) { + *obp++ = c = *ibp++; + switch (c) { + case '\n': + /* Duplicate the newline. */ + *obp++ = '\n'; + break; + + case '\\': + if (*ibp == '\n') { + obp--; + ibp++; + } + break; + + case '/': + if (*ibp == '\\' && ibp[1] == '\n') + newline_fix (ibp); + /* Delete any comment. */ + if (cplusplus && ibp[0] == '/') { + obp--; + ibp++; + while (ibp < limit && *ibp++ != '\n') ; + break; + } + if (ibp[0] != '*' || ibp + 1 >= limit) + break; + obp--; + ibp++; + while (ibp + 1 < limit) { + if (ibp[0] == '*' + && ibp[1] == '\\' && ibp[2] == '\n') + newline_fix (ibp + 1); + if (ibp[0] == '*' && ibp[1] == '/') + break; + ibp++; + } + ibp += 2; + break; + + case '\'': + case '\"': + /* Notice and skip strings, so that we don't + think that comments start inside them, + and so we don't duplicate newlines in them. */ + { + int quotec = c; + while (ibp < limit) { + *obp++ = c = *ibp++; + if (c == quotec) + break; + if (c == '\n' && quotec == '\'') + break; + if (c == '\\' && ibp < limit) { + while (*ibp == '\\' && ibp[1] == '\n') + ibp += 2; + *obp++ = *ibp++; + } + } + } + break; + } + } + + return obp - start; +} + +/* + * error - print error message and increment count of errors. + */ +error (msg, arg1, arg2, arg3) + char *msg; +{ + int i; + FILE_BUF *ip = NULL; + + for (i = indepth; i >= 0; i--) + if (instack[i].fname != NULL) { + ip = &instack[i]; + break; + } + + if (ip != NULL) + fprintf (stderr, "%s:%d: ", ip->fname, ip->lineno); + fprintf (stderr, msg, arg1, arg2, arg3); + fprintf (stderr, "\n"); + errors++; + return 0; +} + +/* Error including a message from `errno'. */ + +error_from_errno (name) + char *name; +{ + int i; + FILE_BUF *ip = NULL; + extern int errno, sys_nerr; + extern char *sys_errlist[]; + + for (i = indepth; i >= 0; i--) + if (instack[i].fname != NULL) { + ip = &instack[i]; + break; + } + + if (ip != NULL) + fprintf (stderr, "%s:%d: ", ip->fname, ip->lineno); + + if (errno < sys_nerr) + fprintf (stderr, "%s: %s\n", name, sys_errlist[errno]); + else + fprintf (stderr, "%s: undocumented I/O error\n", name); + + errors++; + return 0; +} + +/* Print error message but don't count it. */ + +warning (msg, arg1, arg2, arg3) + char *msg; +{ + int i; + FILE_BUF *ip = NULL; + + if (inhibit_warnings) + return 0; + + for (i = indepth; i >= 0; i--) + if (instack[i].fname != NULL) { + ip = &instack[i]; + break; + } + + if (ip != NULL) + fprintf (stderr, "%s:%d: ", ip->fname, ip->lineno); + fprintf (stderr, "warning: "); + fprintf (stderr, msg, arg1, arg2, arg3); + fprintf (stderr, "\n"); + return 0; +} + +error_with_line (line, msg, arg1, arg2, arg3) + int line; + char *msg; +{ + int i; + FILE_BUF *ip = NULL; + + for (i = indepth; i >= 0; i--) + if (instack[i].fname != NULL) { + ip = &instack[i]; + break; + } + + if (ip != NULL) + fprintf (stderr, "%s:%d: ", ip->fname, line); + fprintf (stderr, msg, arg1, arg2, arg3); + fprintf (stderr, "\n"); + errors++; + return 0; +} + +/* Return the line at which an error occurred. + The error is not necessarily associated with the current spot + in the input stack, so LINE says where. LINE will have been + copied from ip->lineno for the current input level. + If the current level is for a file, we return LINE. + But if the current level is not for a file, LINE is meaningless. + In that case, we return the lineno of the innermost file. */ +int +line_for_error (line) + int line; +{ + int i; + int line1 = line; + + for (i = indepth; i >= 0; ) { + if (instack[i].fname != 0) + return line1; + i--; + if (i < 0) + return 0; + line1 = instack[i].lineno; + } +} + +/* + * If OBUF doesn't have NEEDED bytes after OPTR, make it bigger. + * + * As things stand, nothing is ever placed in the output buffer to be + * removed again except when it's KNOWN to be part of an identifier, + * so flushing and moving down everything left, instead of expanding, + * should work ok. + */ + +int +grow_outbuf (obuf, needed) + register FILE_BUF *obuf; + register int needed; +{ + register U_CHAR *p; + int minsize; + + if (obuf->length - (obuf->bufp - obuf->buf) > needed) + return; + + /* Make it at least twice as big as it is now. */ + obuf->length *= 2; + /* Make it have at least 150% of the free space we will need. */ + minsize = (3 * needed) / 2 + (obuf->bufp - obuf->buf); + if (minsize > obuf->length) + obuf->length = minsize; + + if ((p = (U_CHAR *) xrealloc (obuf->buf, obuf->length)) == NULL) + memory_full (); + + obuf->bufp = p + (obuf->bufp - obuf->buf); + obuf->buf = p; +} + +/* Symbol table for macro names and special symbols */ + +/* + * 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, value, hash) + U_CHAR *name; + int len; + enum node_type type; + int value; + int hash; + /* watch out here if sizeof (U_CHAR *) != sizeof (int) */ +{ + register HASHNODE *hp; + register int i, bucket; + register U_CHAR *p, *q; + + if (len < 0) { + p = name; + while (is_idchar[*p]) + p++; + len = p - name; + } + + if (hash < 0) + hash = hashf (name, len, HASHSIZE); + + i = sizeof (HASHNODE) + len + 1; + hp = (HASHNODE *) xmalloc (i); + bucket = hash; + hp->bucket_hdr = &hashtab[bucket]; + hp->next = hashtab[bucket]; + hashtab[bucket] = hp; + hp->prev = NULL; + if (hp->next != NULL) + hp->next->prev = hp; + hp->type = type; + hp->length = len; + hp->value.ival = value; + hp->name = ((U_CHAR *) hp) + sizeof (HASHNODE); + p = hp->name; + q = name; + for (i = 0; i < len; i++) + *p++ = *q++; + hp->name[len] = 0; + 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. + */ +HASHNODE * +lookup (name, len, hash) + U_CHAR *name; + int len; + int hash; +{ + register U_CHAR *bp; + register HASHNODE *bucket; + + if (len < 0) { + for (bp = name; is_idchar[*bp]; bp++) ; + len = bp - name; + } + + if (hash < 0) + hash = hashf (name, len, HASHSIZE); + + bucket = hashtab[hash]; + while (bucket) { + if (bucket->length == len && strncmp (bucket->name, name, len) == 0) + return bucket; + bucket = bucket->next; + } + return NULL; +} + +/* + * Delete a hash node. Some weirdness to free junk from macros. + * More such weirdness will have to be added if you define more hash + * types that need it. + */ + +/* Note that the DEFINITION of a macro is removed from the hash table + but its storage is not freed. This would be a storage leak + except that it is not reasonable to keep undefining and redefining + large numbers of macros many times. + In any case, this is necessary, because a macro can be #undef'd + in the middle of reading the arguments to a call to it. + If #undef freed the DEFINITION, that would crash. */ + +delete_macro (hp) + HASHNODE *hp; +{ + + if (hp->prev != NULL) + hp->prev->next = hp->next; + 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. */ + if (hp == *hp->bucket_hdr) + *hp->bucket_hdr = hp->next; + +#if 0 + if (hp->type == T_MACRO) { + DEFINITION *d = hp->value.defn; + struct reflist *ap, *nextap; + + for (ap = d->pattern; ap != NULL; ap = nextap) { + nextap = ap->next; + free (ap); + } + free (d); + } +#endif + free (hp); +} + +/* + * return hash function on name. must be compatible with the one + * computed a step at a time, elsewhere + */ +int +hashf (name, len, hashsize) + register U_CHAR *name; + register int len; + int hashsize; +{ + register int r = 0; + + while (len--) + r = HASHSTEP (r, *name++); + + return MAKE_POS (r) % hashsize; +} + +/* Dump all macro definitions as #defines to stdout. */ + +void +dump_all_macros () +{ + int bucket; + + for (bucket = 0; bucket < HASHSIZE; bucket++) { + register HASHNODE *hp; + + for (hp = hashtab[bucket]; hp; hp= hp->next) { + if (hp->type == T_MACRO) { + register DEFINITION *defn = hp->value.defn; + struct reflist *ap; + int offset; + int concat; + + + /* Print the definition of the macro HP. */ + + printf ("#define %s", hp->name); + if (defn->nargs >= 0) { + int i; + + printf ("("); + for (i = 0; i < defn->nargs; i++) { + dump_arg_n (defn, i); + if (i + 1 < defn->nargs) + printf (", "); + } + printf (")"); + } + + printf (" "); + + offset = 0; + concat = 0; + for (ap = defn->pattern; ap != NULL; ap = ap->next) { + dump_defn_1 (defn->expansion, offset, ap->nchars); + if (ap->nchars != 0) + concat = 0; + offset += ap->nchars; + if (ap->stringify) + printf (" #"); + if (ap->raw_before && !concat) + printf (" ## "); + concat = 0; + dump_arg_n (defn, ap->argno); + if (ap->raw_after) { + printf (" ## "); + concat = 1; + } + } + dump_defn_1 (defn->expansion, offset, defn->length - offset); + printf ("\n"); + } + } + } +} + +/* Output to stdout a substring of a macro definition. + BASE is the beginning of the definition. + Output characters START thru LENGTH. + Discard newlines outside of strings, thus + converting funny-space markers to ordinary spaces. */ + +dump_defn_1 (base, start, length) + U_CHAR *base; + int start; + int length; +{ + U_CHAR *p = base + start; + U_CHAR *limit = base + start + length; + + while (p < limit) { + if (*p != '\n') + putchar (*p); + else if (*p == '\"' || *p =='\'') { + U_CHAR *p1 = skip_quoted_string (p, limit, 0, 0, 0, 0); + fwrite (p, p1 - p, 1, stdout); + p = p1 - 1; + } + p++; + } +} + +/* Print the name of argument number ARGNUM of macro definition DEFN. + Recall that DEFN->argnames contains all the arg names + concatenated in reverse order with comma-space in between. */ + +dump_arg_n (defn, argnum) + DEFINITION *defn; + int argnum; +{ + register U_CHAR *p = defn->argnames; + while (argnum + 1 < defn->nargs) { + p = (U_CHAR *) index (p, ' ') + 1; + argnum++; + } + + while (*p && *p != ',') { + putchar (*p); + p++; + } +} + +/* Initialize syntactic classifications of characters. */ + +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. + * Must do 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; + is_idchar['$'] = dollars_in_ident; + is_idstart['$'] = dollars_in_ident; + + /* 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; +} + +/* Initialize the built-in macros. */ + +initialize_builtins () +{ + install ("__LINE__", -1, T_SPECLINE, 0, -1); + install ("__DATE__", -1, T_DATE, 0, -1); + install ("__FILE__", -1, T_FILE, 0, -1); + install ("__BASE_FILE__", -1, T_BASE_FILE, 0, -1); + install ("__INCLUDE_LEVEL__", -1, T_INCLUDE_LEVEL, 0, -1); + install ("__VERSION__", -1, T_VERSION, 0, -1); + install ("__TIME__", -1, T_TIME, 0, -1); + if (!traditional) + install ("__STDC__", -1, T_CONST, STDC_VALUE, -1); +/* install ("__GNU__", -1, T_CONST, 1, -1); */ +/* This is supplied using a -D by the compiler driver + so that it is present only when truly compiling with GNU C. */ +} + +/* + * process a given definition string, for initialization + * If STR is just an identifier, define it with value 1. + * If STR has anything after the identifier, then it should + * be identifier-space-definition. + */ +make_definition (str) + U_CHAR *str; +{ + FILE_BUF *ip; + struct directive *kt; + U_CHAR *buf, *p; + + buf = str; + p = str; + while (is_idchar[*p]) p++; + if (p == str) { + error ("malformed option `-D %s'", str); + return; + } + if (*p == 0) { + buf = (U_CHAR *) alloca (p - buf + 4); + strcpy ((char *)buf, str); + strcat ((char *)buf, " 1"); + } else if (*p != ' ') { + error ("malformed option `-D %s'", str); + return; + } else { + U_CHAR *q; + /* Copy the entire option so we can modify it. */ + buf = (U_CHAR *) alloca (2 * strlen (str) + 1); + strncpy (buf, str, p - str); + /* Change the = to a space. */ + buf[p - str] = ' '; + /* Scan for any backslash-newline and remove it. */ + p++; + q = &buf[p - str]; + while (*p) { + if (*p == '\\' && p[1] == '\n') + p += 2; + /* Change newline chars into newline-markers. */ + else if (*p == '\n') + { + *q++ = '\n'; + *q++ = '\n'; + p++; + } + else + *q++ = *p++; + } + *q = 0; + } + + ip = &instack[++indepth]; + ip->fname = "*Initialization*"; + + ip->buf = ip->bufp = buf; + ip->length = strlen (buf); + ip->lineno = 1; + ip->macro = 0; + ip->free_ptr = 0; + ip->if_stack = if_stack; + + for (kt = directive_table; kt->type != T_DEFINE; kt++) + ; + + /* pass NULL as output ptr to do_define since we KNOW it never + does any output.... */ + do_define (buf, buf + strlen (buf) , NULL, kt); + --indepth; +} + +/* JF, this does the work for the -U option */ +make_undef (str) + U_CHAR *str; +{ + FILE_BUF *ip; + struct directive *kt; + + ip = &instack[++indepth]; + ip->fname = "*undef*"; + + ip->buf = ip->bufp = str; + ip->length = strlen (str); + ip->lineno = 1; + ip->macro = 0; + ip->free_ptr = 0; + ip->if_stack = if_stack; + + for (kt = directive_table; kt->type != T_UNDEF; kt++) + ; + + do_undef (str,str + strlen (str) - 1, NULL, kt); + --indepth; +} + +/* Add output to `deps_buffer' for the -M switch. + STRING points to the text to be output. + SIZE is the number of bytes, or 0 meaning output until a null. + If SIZE is nonzero, we break the line first, if it is long enough. */ + +deps_output (string, size) + char *string; + int size; +{ +#ifndef MAX_OUTPUT_COLUMNS +#define MAX_OUTPUT_COLUMNS 75 +#endif + if (size != 0 && deps_column != 0 + && size + deps_column > MAX_OUTPUT_COLUMNS) { + deps_output ("\\\n ", 0); + deps_column = 0; + } + + if (size == 0) + size = strlen (string); + + if (deps_size + size + 1 > deps_allocated_size) { + deps_allocated_size = deps_size + size + 50; + deps_allocated_size *= 2; + deps_buffer = (char *) xrealloc (deps_buffer, deps_allocated_size); + } + bcopy (string, &deps_buffer[deps_size], size); + deps_size += size; + deps_column += size; + deps_buffer[deps_size] = 0; +} + +#ifndef BSTRING + +void +bzero (b, length) + register char *b; + register int length; +{ +#ifdef VMS + short zero = 0; + long max_str = 65535; + + while (length > max_str) { + (void) LIB$MOVC5 (&zero, &zero, &zero, &max_str, b); + length -= max_str; + b += max_str; + } + (void) LIB$MOVC5 (&zero, &zero, &zero, &length, b); +#else + while (length-- > 0) + *b++ = 0; +#endif /* not VMS */ +} + +void +bcopy (b1, b2, length) + register char *b1; + register char *b2; + register int length; +{ +#ifdef VMS + long max_str = 65535; + + while (length > max_str) { + (void) LIB$MOVC3 (&max_str, b1, b2); + length -= max_str; + b1 += max_str; + b2 += max_str; + } + (void) LIB$MOVC3 (&length, b1, b2); +#else + while (length-- > 0) + *b2++ = *b1++; +#endif /* not VMS */ +} + +int +bcmp (b1, b2, length) /* This could be a macro! */ + register char *b1; + register char *b2; + register int length; +{ +#ifdef VMS + struct dsc$descriptor_s src1 = {length, DSC$K_DTYPE_T, DSC$K_CLASS_S, b1}; + struct dsc$descriptor_s src2 = {length, DSC$K_DTYPE_T, DSC$K_CLASS_S, b2}; + + return STR$COMPARE (&src1, &src2); +#else + while (length-- > 0) + if (*b1++ != *b2++) + return 1; + + return 0; +#endif /* not VMS */ +} +#endif /* not BSTRING */ + +void +fatal (str, arg) + char *str, *arg; +{ + fprintf (stderr, "%s: ", progname); + fprintf (stderr, str, arg); + fprintf (stderr, "\n"); + exit (FATAL_EXIT_CODE); +} + +/* 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."); +} + +void +perror_with_name (name) + char *name; +{ + extern int errno, sys_nerr; + extern char *sys_errlist[]; + + fprintf (stderr, "%s: ", progname); + if (errno < sys_nerr) + fprintf (stderr, "%s: %s\n", name, sys_errlist[errno]); + else + fprintf (stderr, "%s: undocumented I/O error\n", name); + errors++; +} + +void +pfatal_with_name (name) + char *name; +{ + perror_with_name (name); +#ifdef VMS + exit (vaxc$errno); +#else + exit (FATAL_EXIT_CODE); +#endif +} + + +void +memory_full () +{ + fatal ("Memory exhausted."); +} + + +char * +xmalloc (size) + int size; +{ + extern char *malloc (); + register char *ptr = malloc (size); + if (ptr != 0) return (ptr); + memory_full (); + /*NOTREACHED*/ +} + +char * +xrealloc (old, size) + char *old; + int size; +{ + extern char *realloc (); + register char *ptr = realloc (old, size); + if (ptr != 0) return (ptr); + memory_full (); + /*NOTREACHED*/ +} + +char * +xcalloc (number, size) + int number, size; +{ + extern char *malloc (); + register int total = number * size; + register char *ptr = malloc (total); + if (ptr != 0) { + if (total > 100) + bzero (ptr, total); + else { + /* It's not too long, so loop, zeroing by longs. + It must be safe because malloc values are always well aligned. */ + register long *zp = (long *) ptr; + register long *zl = (long *) (ptr + total - 4); + register int i = total - 4; + while (zp < zl) + *zp++ = 0; + if (i < 0) + i = 0; + while (i < total) + ptr[i++] = 0; + } + return ptr; + } + memory_full (); + /*NOTREACHED*/ +} + +char * +savestring (input) + char *input; +{ + int size = strlen (input); + char *output = xmalloc (size + 1); + strcpy (output, 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. */ + +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; +} + +#ifdef VMS + +/* 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. */ + +hack_vms_include_specification (fname) + char *fname; +{ + register char *cp, *cp1, *cp2; + char Local[512]; + extern char *index (), *rindex (); + + /* Ignore leading "./"s */ + while (fname[0] == '.' && fname[1] == '/') + strcpy (fname, fname+2); + /* 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 "/" */ + } + + cp2 = 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 + processing can handle them. + + If the file name contains something like [dir.], then it recognizes this + as a root, and strips the ".]". Later processing will add whatever is + 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). */ + + /* 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) > 2) && ((cp[-1] == ']') || (cp[-1] == '>'))) { + if (cp[-2] != '.') { +/* + * The VMS part ends in a "]", where the preceeding character is not a ".". + * We assume that the rest of the specification is correct, and we splice + * the two parts together, and go back. Actually, given the default + * locations for include files listed in cccp.c, we will never get here. + * Things could change, so we leave it in... + */ + strcpy (cp, cp1); /* Non-rooted */ + return; /* trailing "]/", and not ".]/" */ + } 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 { + +/* 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] != ':') /* dev not in spec. take first dir */ + *cp2++ = ':'; + *cp2++ = '['; /* Open the directory specification */ + } + + /* 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 */ + + /* 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); + } 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 "/" */ + } + /* 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); + return; +} +#endif /* VMS */ + +#ifdef VMS + +/* 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 */ + +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); +} + +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); +} + +#endif /* VMS */ diff --git a/gcc-1.40/cexp.c b/gcc-1.40/cexp.c new file mode 100644 index 0000000..9698d9e --- /dev/null +++ b/gcc-1.40/cexp.c @@ -0,0 +1,1468 @@ + +/* A Bison parser, made from ./cexp.y */ + +#define INT 258 +#define CHAR 259 +#define NAME 260 +#define ERROR 261 +#define OR 262 +#define AND 263 +#define EQUAL 264 +#define NOTEQUAL 265 +#define LEQ 266 +#define GEQ 267 +#define LSH 268 +#define RSH 269 +#define UNARY 270 + +#line 26 "./cexp.y" + +#include "config.h" +#include +/* #define YYDEBUG 1 */ + + int yylex (); + void yyerror (); + int expression_value; + + static jmp_buf parse_return_error; + + /* some external tables of character types */ + extern unsigned char is_idstart[], is_idchar[]; + +#ifndef CHAR_TYPE_SIZE +#define CHAR_TYPE_SIZE BITS_PER_UNIT +#endif + +#line 45 "./cexp.y" +typedef union { + struct constant {long value; int unsignedp;} integer; + int voidval; + char *sval; +} YYSTYPE; + +#ifndef YYLTYPE +typedef + struct yyltype + { + int timestamp; + int first_line; + int first_column; + int last_line; + int last_column; + char *text; + } + yyltype; + +#define YYLTYPE yyltype +#endif + +#include + +#ifndef __STDC__ +#define const +#endif + + + +#define YYFINAL 61 +#define YYFLAG -32768 +#define YYNTBASE 33 + +#define YYTRANSLATE(x) ((unsigned)(x) <= 270 ? yytranslate[x] : 36) + +static const char yytranslate[] = { 0, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 29, 2, 2, 2, 27, 14, 2, 31, + 32, 25, 23, 9, 24, 2, 26, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 8, 2, 17, + 2, 18, 7, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 13, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 12, 2, 30, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 1, 2, 3, 4, 5, + 6, 10, 11, 15, 16, 19, 20, 21, 22, 28 +}; + +static const short yyprhs[] = { 0, + 0, 2, 4, 8, 11, 14, 17, 20, 24, 28, + 32, 36, 40, 44, 48, 52, 56, 60, 64, 68, + 72, 76, 80, 84, 88, 92, 96, 102, 104, 106 +}; + +static const short yyrhs[] = { 34, + 0, 35, 0, 34, 9, 35, 0, 24, 35, 0, + 29, 35, 0, 23, 35, 0, 30, 35, 0, 31, + 34, 32, 0, 35, 25, 35, 0, 35, 26, 35, + 0, 35, 27, 35, 0, 35, 23, 35, 0, 35, + 24, 35, 0, 35, 21, 35, 0, 35, 22, 35, + 0, 35, 15, 35, 0, 35, 16, 35, 0, 35, + 19, 35, 0, 35, 20, 35, 0, 35, 17, 35, + 0, 35, 18, 35, 0, 35, 14, 35, 0, 35, + 13, 35, 0, 35, 12, 35, 0, 35, 11, 35, + 0, 35, 10, 35, 0, 35, 7, 35, 8, 35, + 0, 3, 0, 4, 0, 5, 0 +}; + +#if YYDEBUG != 0 +static const short yyrline[] = { 0, + 74, 79, 80, 85, 88, 91, 93, 96, 101, 107, + 118, 129, 132, 135, 141, 147, 150, 153, 159, 165, + 171, 177, 180, 183, 186, 189, 192, 195, 197, 199 +}; + +static const char * const yytname[] = { "$", +"error","$illegal.","INT","CHAR","NAME","ERROR","'?'","':'","','","OR", +"AND","'|'","'^'","'&'","EQUAL","NOTEQUAL","'<'","'>'","LEQ","GEQ", +"LSH","RSH","'+'","'-'","'*'","'/'","'%'","UNARY","'!'","'~'", +"'('","')'","start","exp1","exp","" +}; +#endif + +static const short yyr1[] = { 0, + 33, 34, 34, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35 +}; + +static const short yyr2[] = { 0, + 1, 1, 3, 2, 2, 2, 2, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 5, 1, 1, 1 +}; + +static const short yydefact[] = { 0, + 28, 29, 30, 0, 0, 0, 0, 0, 1, 2, + 6, 4, 5, 7, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 8, 3, 0, 26, 25, + 24, 23, 22, 16, 17, 20, 21, 18, 19, 14, + 15, 12, 13, 9, 10, 11, 0, 27, 0, 0, + 0 +}; + +static const short yydefgoto[] = { 59, + 9, 10 +}; + +static const short yypact[] = { 31, +-32768,-32768,-32768, 31, 31, 31, 31, 31, 1, 77, +-32768,-32768,-32768,-32768, 0, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31,-32768, 77, 56, 94, 25, + 109, 123, 136, 147, 147, 154, 154, 154, 154, -19, + -19, 32, 32,-32768,-32768,-32768, 31, 77, 11, 33, +-32768 +}; + +static const short yypgoto[] = {-32768, + 48, -4 +}; + + +#define YYLAST 181 + + +static const short yytable[] = { 11, + 12, 13, 14, 31, 32, 33, 34, 35, 16, 16, + 60, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, + 56, 36, 61, 1, 2, 3, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 58, 4, 5, 15, 33, 34, 35, 6, + 7, 8, 17, 57, 0, 18, 19, 20, 21, 22, + 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 17, 0, 0, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, + 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 29, 30, 31, 32, 33, 34, + 35 +}; + +static const short yycheck[] = { 4, + 5, 6, 7, 23, 24, 25, 26, 27, 9, 9, + 0, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 32, 0, 3, 4, 5, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 26, 27, 57, 23, 24, 8, 25, 26, 27, 29, + 30, 31, 7, 8, -1, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 7, -1, -1, 10, 11, 12, 13, + 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 21, 22, 23, 24, 25, 26, + 27 +}; +/* -*-C-*- Note some compilers choke on comments on `#line' lines. */ +#line 3 "bison.simple" + +/* Skeleton output parser for bison, + Copyright (C) 1984, 1989, 1990 Bob Corbett and Richard Stallman + + 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. + + 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. */ + + +#ifndef alloca +#ifdef __GNUC__ +#define alloca __builtin_alloca +#else /* Not GNU C. */ +#if (!defined (__STDC__) && defined (sparc)) || defined (__sparc__) +#include +#else /* Not sparc */ +#ifdef MSDOS +#include +#endif /* MSDOS */ +#endif /* Not sparc. */ +#endif /* Not GNU C. */ +#endif /* alloca not defined. */ + +/* This is the parser code that is written into each bison parser + when the %semantic_parser declaration is not specified in the grammar. + It was written by Richard Stallman by simplifying the hairy parser + used when %semantic_parser is specified. */ + +/* Note: there must be only one dollar sign in this file. + It is replaced by the list of actions, each action + as one case of the switch. */ + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY -2 +#define YYEOF 0 +#define YYACCEPT return(0) +#define YYABORT return(1) +#define YYERROR goto yyerrlab1 +/* Like YYERROR except do call yyerror. + This remains here temporarily to ease the + transition to the new meaning of YYERROR, for GCC. + Once GCC version 2 has supplanted version 1, this can go. */ +#define YYFAIL goto yyerrlab +#define YYRECOVERING() (!!yyerrstatus) +#define YYBACKUP(token, value) \ +do \ + if (yychar == YYEMPTY && yylen == 1) \ + { yychar = (token), yylval = (value); \ + yychar1 = YYTRANSLATE (yychar); \ + YYPOPSTACK; \ + goto yybackup; \ + } \ + else \ + { yyerror ("syntax error: cannot back up"); YYERROR; } \ +while (0) + +#define YYTERROR 1 +#define YYERRCODE 256 + +#ifndef YYPURE +#define YYLEX yylex() +#endif + +#ifdef YYPURE +#ifdef YYLSP_NEEDED +#define YYLEX yylex(&yylval, &yylloc) +#else +#define YYLEX yylex(&yylval) +#endif +#endif + +/* If nonreentrant, generate the variables here */ + +#ifndef YYPURE + +int yychar; /* the lookahead symbol */ +YYSTYPE yylval; /* the semantic value of the */ + /* lookahead symbol */ + +#ifdef YYLSP_NEEDED +YYLTYPE yylloc; /* location data for the lookahead */ + /* symbol */ +#endif + +int yynerrs; /* number of parse errors so far */ +#endif /* not YYPURE */ + +#if YYDEBUG != 0 +int yydebug; /* nonzero means print parse trace */ +/* Since this is uninitialized, it does not stop multiple parsers + from coexisting. */ +#endif + +/* YYINITDEPTH indicates the initial size of the parser's stacks */ + +#ifndef YYINITDEPTH +#define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH is the maximum size the stacks can grow to + (effective only if the built-in stack extension method is used). */ + +#if YYMAXDEPTH == 0 +#undef YYMAXDEPTH +#endif + +#ifndef YYMAXDEPTH +#define YYMAXDEPTH 10000 +#endif + +#ifndef __cplusplus + +/* This is the most reliable way to avoid incompatibilities + in available built-in functions on various systems. */ +static void +__yy_bcopy (from, to, count) + char *from; + char *to; + int count; +{ + register char *f = from; + register char *t = to; + register int i = count; + + while (i-- > 0) + *t++ = *f++; +} + +#else /* __cplusplus */ + +/* This is the most reliable way to avoid incompatibilities + in available built-in functions on various systems. */ +static void +__yy_bcopy (char *from, char *to, int count) +{ + register char *f = from; + register char *t = to; + register int i = count; + + while (i-- > 0) + *t++ = *f++; +} + +#endif + +#line 160 "bison.simple" +int +yyparse() +{ + register int yystate; + register int yyn; + register short *yyssp; + register YYSTYPE *yyvsp; + int yyerrstatus; /* number of tokens to shift before error messages enabled */ + int yychar1; /* lookahead token as an internal (translated) token number */ + + short yyssa[YYINITDEPTH]; /* the state stack */ + YYSTYPE yyvsa[YYINITDEPTH]; /* the semantic value stack */ + + short *yyss = yyssa; /* refer to the stacks thru separate pointers */ + YYSTYPE *yyvs = yyvsa; /* to allow yyoverflow to reallocate them elsewhere */ + +#ifdef YYLSP_NEEDED + YYLTYPE *yyls = yylsa; + YYLTYPE *yylsp; + YYLTYPE yylsa[YYINITDEPTH]; /* the location stack */ + +#define YYPOPSTACK (yyvsp--, yysp--, yylsp--) +#else +#define YYPOPSTACK (yyvsp--, yysp--) +#endif + + int yystacksize = YYINITDEPTH; + +#ifdef YYPURE + int yychar; + YYSTYPE yylval; + int yynerrs; +#ifdef YYLSP_NEEDED + YYLTYPE yylloc; +#endif +#endif + + YYSTYPE yyval; /* the variable used to return */ + /* semantic values from the action */ + /* routines */ + + int yylen; + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Starting parse\n"); +#endif + + yystate = 0; + yyerrstatus = 0; + yynerrs = 0; + yychar = YYEMPTY; /* Cause a token to be read. */ + + /* Initialize stack pointers. + Waste one element of value and location stack + so that they stay on the same level as the state stack. */ + + yyssp = yyss - 1; + yyvsp = yyvs; +#ifdef YYLSP_NEEDED + yylsp = yyls; +#endif + +/* Push a new state, which is found in yystate . */ +/* In all cases, when you get here, the value and location stacks + have just been pushed. so pushing a state here evens the stacks. */ +yynewstate: + + *++yyssp = yystate; + + if (yyssp >= yyss + yystacksize - 1) + { + /* Give user a chance to reallocate the stack */ + /* Use copies of these so that the &'s don't force the real ones into memory. */ + YYSTYPE *yyvs1 = yyvs; + short *yyss1 = yyss; +#ifdef YYLSP_NEEDED + YYLTYPE *yyls1 = yyls; +#endif + + /* Get the current used size of the three stacks, in elements. */ + int size = yyssp - yyss + 1; + +#ifdef yyoverflow + /* Each stack pointer address is followed by the size of + the data in use in that stack, in bytes. */ + yyoverflow("parser stack overflow", + &yyss1, size * sizeof (*yyssp), + &yyvs1, size * sizeof (*yyvsp), +#ifdef YYLSP_NEEDED + &yyls1, size * sizeof (*yylsp), +#endif + &yystacksize); + + yyss = yyss1; yyvs = yyvs1; +#ifdef YYLSP_NEEDED + yyls = yyls1; +#endif +#else /* no yyoverflow */ + /* Extend the stack our own way. */ + if (yystacksize >= YYMAXDEPTH) + { + yyerror("parser stack overflow"); + return 2; + } + yystacksize *= 2; + if (yystacksize > YYMAXDEPTH) + yystacksize = YYMAXDEPTH; + yyss = (short *) alloca (yystacksize * sizeof (*yyssp)); + __yy_bcopy ((char *)yyss1, (char *)yyss, size * sizeof (*yyssp)); + yyvs = (YYSTYPE *) alloca (yystacksize * sizeof (*yyvsp)); + __yy_bcopy ((char *)yyvs1, (char *)yyvs, size * sizeof (*yyvsp)); +#ifdef YYLSP_NEEDED + yyls = (YYLTYPE *) alloca (yystacksize * sizeof (*yylsp)); + __yy_bcopy ((char *)yyls1, (char *)yyls, size * sizeof (*yylsp)); +#endif +#endif /* no yyoverflow */ + + yyssp = yyss + size - 1; + yyvsp = yyvs + size - 1; +#ifdef YYLSP_NEEDED + yylsp = yyls + size - 1; +#endif + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Stack size increased to %d\n", yystacksize); +#endif + + if (yyssp >= yyss + yystacksize - 1) + YYABORT; + } + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Entering state %d\n", yystate); +#endif + + yybackup: + +/* Do appropriate processing given the current state. */ +/* Read a lookahead token if we need one and don't already have one. */ +/* yyresume: */ + + /* First try to decide what to do without reference to lookahead token. */ + + yyn = yypact[yystate]; + if (yyn == YYFLAG) + goto yydefault; + + /* Not known => get a lookahead token if don't already have one. */ + + /* yychar is either YYEMPTY or YYEOF + or a valid token in external form. */ + + if (yychar == YYEMPTY) + { +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Reading a token: "); +#endif + yychar = YYLEX; + } + + /* Convert token to internal form (in yychar1) for indexing tables with */ + + if (yychar <= 0) /* This means end of input. */ + { + yychar1 = 0; + yychar = YYEOF; /* Don't call YYLEX any more */ + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Now at end of input.\n"); +#endif + } + else + { + yychar1 = YYTRANSLATE(yychar); + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Next token is %d (%s)\n", yychar, yytname[yychar1]); +#endif + } + + yyn += yychar1; + if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != yychar1) + goto yydefault; + + yyn = yytable[yyn]; + + /* yyn is what to do for this token type in this state. + Negative => reduce, -yyn is rule number. + Positive => shift, yyn is new state. + New state is final state => don't bother to shift, + just return success. + 0, or most negative number => error. */ + + if (yyn < 0) + { + if (yyn == YYFLAG) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + else if (yyn == 0) + goto yyerrlab; + + if (yyn == YYFINAL) + YYACCEPT; + + /* Shift the lookahead token. */ + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Shifting token %d (%s), ", yychar, yytname[yychar1]); +#endif + + /* Discard the token being shifted unless it is eof. */ + if (yychar != YYEOF) + yychar = YYEMPTY; + + *++yyvsp = yylval; +#ifdef YYLSP_NEEDED + *++yylsp = yylloc; +#endif + + /* count tokens shifted since error; after three, turn off error status. */ + if (yyerrstatus) yyerrstatus--; + + yystate = yyn; + goto yynewstate; + +/* Do the default action for the current state. */ +yydefault: + + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + +/* Do a reduction. yyn is the number of a rule to reduce with. */ +yyreduce: + yylen = yyr2[yyn]; + yyval = yyvsp[1-yylen]; /* implement default value of the action */ + +#if YYDEBUG != 0 + if (yydebug) + { + int i; + + fprintf (stderr, "Reducing via rule %d (line %d), ", + yyn, yyrline[yyn]); + + /* Print the symboles being reduced, and their result. */ + for (i = yyprhs[yyn]; yyrhs[i] > 0; i++) + fprintf (stderr, "%s ", yytname[yyrhs[i]]); + fprintf (stderr, " -> %s\n", yytname[yyr1[yyn]]); + } +#endif + + + switch (yyn) { + +case 1: +#line 75 "./cexp.y" +{ expression_value = yyvsp[0].integer.value; ; + break;} +case 3: +#line 81 "./cexp.y" +{ yyval.integer = yyvsp[0].integer; ; + break;} +case 4: +#line 86 "./cexp.y" +{ yyval.integer.value = - yyvsp[0].integer.value; + yyval.integer.unsignedp = yyvsp[0].integer.unsignedp; ; + break;} +case 5: +#line 89 "./cexp.y" +{ yyval.integer.value = ! yyvsp[0].integer.value; + yyval.integer.unsignedp = 0; ; + break;} +case 6: +#line 92 "./cexp.y" +{ yyval.integer = yyvsp[0].integer; ; + break;} +case 7: +#line 94 "./cexp.y" +{ yyval.integer.value = ~ yyvsp[0].integer.value; + yyval.integer.unsignedp = yyvsp[0].integer.unsignedp; ; + break;} +case 8: +#line 97 "./cexp.y" +{ yyval.integer = yyvsp[-1].integer; ; + break;} +case 9: +#line 102 "./cexp.y" +{ yyval.integer.unsignedp = yyvsp[-2].integer.unsignedp || yyvsp[0].integer.unsignedp; + if (yyval.integer.unsignedp) + yyval.integer.value = (unsigned) yyvsp[-2].integer.value * yyvsp[0].integer.value; + else + yyval.integer.value = yyvsp[-2].integer.value * yyvsp[0].integer.value; ; + break;} +case 10: +#line 108 "./cexp.y" +{ if (yyvsp[0].integer.value == 0) + { + error ("division by zero in #if"); + yyvsp[0].integer.value = 1; + } + yyval.integer.unsignedp = yyvsp[-2].integer.unsignedp || yyvsp[0].integer.unsignedp; + if (yyval.integer.unsignedp) + yyval.integer.value = (unsigned) yyvsp[-2].integer.value / yyvsp[0].integer.value; + else + yyval.integer.value = yyvsp[-2].integer.value / yyvsp[0].integer.value; ; + break;} +case 11: +#line 119 "./cexp.y" +{ if (yyvsp[0].integer.value == 0) + { + error ("division by zero in #if"); + yyvsp[0].integer.value = 1; + } + yyval.integer.unsignedp = yyvsp[-2].integer.unsignedp || yyvsp[0].integer.unsignedp; + if (yyval.integer.unsignedp) + yyval.integer.value = (unsigned) yyvsp[-2].integer.value % yyvsp[0].integer.value; + else + yyval.integer.value = yyvsp[-2].integer.value % yyvsp[0].integer.value; ; + break;} +case 12: +#line 130 "./cexp.y" +{ yyval.integer.value = yyvsp[-2].integer.value + yyvsp[0].integer.value; + yyval.integer.unsignedp = yyvsp[-2].integer.unsignedp || yyvsp[0].integer.unsignedp; ; + break;} +case 13: +#line 133 "./cexp.y" +{ yyval.integer.value = yyvsp[-2].integer.value - yyvsp[0].integer.value; + yyval.integer.unsignedp = yyvsp[-2].integer.unsignedp || yyvsp[0].integer.unsignedp; ; + break;} +case 14: +#line 136 "./cexp.y" +{ yyval.integer.unsignedp = yyvsp[-2].integer.unsignedp; + if (yyval.integer.unsignedp) + yyval.integer.value = (unsigned) yyvsp[-2].integer.value << yyvsp[0].integer.value; + else + yyval.integer.value = yyvsp[-2].integer.value << yyvsp[0].integer.value; ; + break;} +case 15: +#line 142 "./cexp.y" +{ yyval.integer.unsignedp = yyvsp[-2].integer.unsignedp; + if (yyval.integer.unsignedp) + yyval.integer.value = (unsigned) yyvsp[-2].integer.value >> yyvsp[0].integer.value; + else + yyval.integer.value = yyvsp[-2].integer.value >> yyvsp[0].integer.value; ; + break;} +case 16: +#line 148 "./cexp.y" +{ yyval.integer.value = (yyvsp[-2].integer.value == yyvsp[0].integer.value); + yyval.integer.unsignedp = 0; ; + break;} +case 17: +#line 151 "./cexp.y" +{ yyval.integer.value = (yyvsp[-2].integer.value != yyvsp[0].integer.value); + yyval.integer.unsignedp = 0; ; + break;} +case 18: +#line 154 "./cexp.y" +{ yyval.integer.unsignedp = 0; + if (yyvsp[-2].integer.unsignedp || yyvsp[0].integer.unsignedp) + yyval.integer.value = (unsigned) yyvsp[-2].integer.value <= yyvsp[0].integer.value; + else + yyval.integer.value = yyvsp[-2].integer.value <= yyvsp[0].integer.value; ; + break;} +case 19: +#line 160 "./cexp.y" +{ yyval.integer.unsignedp = 0; + if (yyvsp[-2].integer.unsignedp || yyvsp[0].integer.unsignedp) + yyval.integer.value = (unsigned) yyvsp[-2].integer.value >= yyvsp[0].integer.value; + else + yyval.integer.value = yyvsp[-2].integer.value >= yyvsp[0].integer.value; ; + break;} +case 20: +#line 166 "./cexp.y" +{ yyval.integer.unsignedp = 0; + if (yyvsp[-2].integer.unsignedp || yyvsp[0].integer.unsignedp) + yyval.integer.value = (unsigned) yyvsp[-2].integer.value < yyvsp[0].integer.value; + else + yyval.integer.value = yyvsp[-2].integer.value < yyvsp[0].integer.value; ; + break;} +case 21: +#line 172 "./cexp.y" +{ yyval.integer.unsignedp = 0; + if (yyvsp[-2].integer.unsignedp || yyvsp[0].integer.unsignedp) + yyval.integer.value = (unsigned) yyvsp[-2].integer.value > yyvsp[0].integer.value; + else + yyval.integer.value = yyvsp[-2].integer.value > yyvsp[0].integer.value; ; + break;} +case 22: +#line 178 "./cexp.y" +{ yyval.integer.value = yyvsp[-2].integer.value & yyvsp[0].integer.value; + yyval.integer.unsignedp = yyvsp[-2].integer.unsignedp || yyvsp[0].integer.unsignedp; ; + break;} +case 23: +#line 181 "./cexp.y" +{ yyval.integer.value = yyvsp[-2].integer.value ^ yyvsp[0].integer.value; + yyval.integer.unsignedp = yyvsp[-2].integer.unsignedp || yyvsp[0].integer.unsignedp; ; + break;} +case 24: +#line 184 "./cexp.y" +{ yyval.integer.value = yyvsp[-2].integer.value | yyvsp[0].integer.value; + yyval.integer.unsignedp = yyvsp[-2].integer.unsignedp || yyvsp[0].integer.unsignedp; ; + break;} +case 25: +#line 187 "./cexp.y" +{ yyval.integer.value = (yyvsp[-2].integer.value && yyvsp[0].integer.value); + yyval.integer.unsignedp = 0; ; + break;} +case 26: +#line 190 "./cexp.y" +{ yyval.integer.value = (yyvsp[-2].integer.value || yyvsp[0].integer.value); + yyval.integer.unsignedp = 0; ; + break;} +case 27: +#line 193 "./cexp.y" +{ yyval.integer.value = yyvsp[-4].integer.value ? yyvsp[-2].integer.value : yyvsp[0].integer.value; + yyval.integer.unsignedp = yyvsp[-2].integer.unsignedp || yyvsp[0].integer.unsignedp; ; + break;} +case 28: +#line 196 "./cexp.y" +{ yyval.integer = yylval.integer; ; + break;} +case 29: +#line 198 "./cexp.y" +{ yyval.integer = yylval.integer; ; + break;} +case 30: +#line 200 "./cexp.y" +{ yyval.integer.value = 0; + yyval.integer.unsignedp = 0; ; + break;} +} + /* the action file gets copied in in place of this dollarsign */ +#line 423 "bison.simple" + + yyvsp -= yylen; + yyssp -= yylen; +#ifdef YYLSP_NEEDED + yylsp -= yylen; +#endif + +#if YYDEBUG != 0 + if (yydebug) + { + short *ssp1 = yyss - 1; + fprintf (stderr, "state stack now"); + while (ssp1 != yyssp) + fprintf (stderr, " %d", *++ssp1); + fprintf (stderr, "\n"); + } +#endif + + *++yyvsp = yyval; + +#ifdef YYLSP_NEEDED + yylsp++; + if (yylen == 0) + { + yylsp->first_line = yylloc.first_line; + yylsp->first_column = yylloc.first_column; + yylsp->last_line = (yylsp-1)->last_line; + yylsp->last_column = (yylsp-1)->last_column; + yylsp->text = 0; + } + else + { + yylsp->last_line = (yylsp+yylen-1)->last_line; + yylsp->last_column = (yylsp+yylen-1)->last_column; + } +#endif + + /* Now "shift" the result of the reduction. + Determine what state that goes to, + based on the state we popped back to + and the rule number reduced by. */ + + yyn = yyr1[yyn]; + + yystate = yypgoto[yyn - YYNTBASE] + *yyssp; + if (yystate >= 0 && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTBASE]; + + goto yynewstate; + +yyerrlab: /* here on detecting error */ + + if (! yyerrstatus) + /* If not already recovering from an error, report this error. */ + { + ++yynerrs; + +#ifdef YYERROR_VERBOSE + yyn = yypact[yystate]; + + if (yyn > YYFLAG && yyn < YYLAST) + { + int size = 0; + char *msg; + int x, count; + + count = 0; + for (x = 0; x < (sizeof(yytname) / sizeof(char *)); x++) + if (yycheck[x + yyn] == x) + size += strlen(yytname[x]) + 15, count++; + msg = (char *) xmalloc(size + 15); + strcpy(msg, "parse error"); + + if (count < 5) + { + count = 0; + for (x = 0; x < (sizeof(yytname) / sizeof(char *)); x++) + if (yycheck[x + yyn] == x) + { + strcat(msg, count == 0 ? ", expecting `" : " or `"); + strcat(msg, yytname[x]); + strcat(msg, "'"); + count++; + } + } + yyerror(msg); + free(msg); + } + else +#endif /* YYERROR_VERBOSE */ + yyerror("parse error"); + } + +yyerrlab1: /* here on error raised explicitly by an action */ + + if (yyerrstatus == 3) + { + /* if just tried and failed to reuse lookahead token after an error, discard it. */ + + /* return failure if at end of input */ + if (yychar == YYEOF) + YYABORT; + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Discarding token %d (%s).\n", yychar, yytname[yychar1]); +#endif + + yychar = YYEMPTY; + } + + /* Else will try to reuse lookahead token + after shifting the error token. */ + + yyerrstatus = 3; /* Each real token shifted decrements this */ + + goto yyerrhandle; + +yyerrdefault: /* current state does not do anything special for the error token. */ + +#if 0 + /* This is wrong; only states that explicitly want error tokens + should shift them. */ + yyn = yydefact[yystate]; /* If its default is to accept any token, ok. Otherwise pop it.*/ + if (yyn) goto yydefault; +#endif + +yyerrpop: /* pop the current state because it cannot handle the error token */ + + if (yyssp == yyss) YYABORT; + yyvsp--; + yystate = *--yyssp; +#ifdef YYLSP_NEEDED + yylsp--; +#endif + +#if YYDEBUG != 0 + if (yydebug) + { + short *ssp1 = yyss - 1; + fprintf (stderr, "Error: state stack now"); + while (ssp1 != yyssp) + fprintf (stderr, " %d", *++ssp1); + fprintf (stderr, "\n"); + } +#endif + +yyerrhandle: + + yyn = yypact[yystate]; + if (yyn == YYFLAG) + goto yyerrdefault; + + yyn += YYTERROR; + if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != YYTERROR) + goto yyerrdefault; + + yyn = yytable[yyn]; + if (yyn < 0) + { + if (yyn == YYFLAG) + goto yyerrpop; + yyn = -yyn; + goto yyreduce; + } + else if (yyn == 0) + goto yyerrpop; + + if (yyn == YYFINAL) + YYACCEPT; + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Shifting error token, "); +#endif + + *++yyvsp = yylval; +#ifdef YYLSP_NEEDED + *++yylsp = yylloc; +#endif + + yystate = yyn; + goto yynewstate; +} +#line 203 "./cexp.y" + + +/* During parsing of a C expression, the pointer to the next character + is in this variable. */ + +static char *lexptr; + +/* Take care of parsing a number (anything that starts with a digit). + Set yylval and return the token type; update lexptr. + LEN is the number of characters in it. */ + +/* maybe needs to actually deal with floating point numbers */ + +int +parse_number (olen) + int olen; +{ + register char *p = lexptr; + register long n = 0; + register int c; + register int base = 10; + register int len = olen; + + 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; + + if (len >= 3 && (!strncmp (p, "0x", 2) || !strncmp (p, "0X", 2))) { + p += 2; + base = 16; + len -= 2; + } + else if (*p == '0') + base = 8; + + while (len > 0) { + c = *p++; + len--; + if (c >= 'A' && c <= 'Z') c += 'a' - 'A'; + + if (c >= '0' && c <= '9') { + n *= base; + n += c - '0'; + } else if (base == 16 && c >= 'a' && c <= 'f') { + n *= base; + n += c - 'a' + 10; + } else { + /* `l' means long, and `u' means unsigned. */ + while (1) { + if (c == 'l' || c == 'L') + ; + else if (c == 'u' || c == 'U') + yylval.integer.unsignedp = 1; + else + break; + + if (len == 0) + break; + c = *p++; + len--; + } + /* Don't look for any more digits after the suffixes. */ + break; + } + } + + if (len != 0) { + yyerror ("Invalid number in #if expression"); + return ERROR; + } + + /* If too big to be signed, consider it unsigned. */ + if (n < 0) + yylval.integer.unsignedp = 1; + + lexptr = p; + yylval.integer.value = n; + return INT; +} + +struct token { + char *operator; + int token; +}; + +#ifndef NULL +#define NULL 0 +#endif + +static struct token tokentab2[] = { + {"&&", AND}, + {"||", OR}, + {"<<", LSH}, + {">>", RSH}, + {"==", EQUAL}, + {"!=", NOTEQUAL}, + {"<=", LEQ}, + {">=", GEQ}, + {NULL, ERROR} +}; + +/* Read one token, getting characters through lexptr. */ + +int +yylex () +{ + register int c; + register int namelen; + register char *tokstart; + register struct token *toktab; + + retry: + + tokstart = lexptr; + c = *tokstart; + /* See if it is a special token of length 2. */ + for (toktab = tokentab2; toktab->operator != NULL; toktab++) + if (c == *toktab->operator && tokstart[1] == toktab->operator[1]) { + lexptr += 2; + return toktab->token; + } + + switch (c) { + case 0: + return 0; + + case ' ': + case '\t': + case '\r': + case '\n': + lexptr++; + goto retry; + + case '\'': + lexptr++; + c = *lexptr++; + if (c == '\\') + c = parse_escape (&lexptr); + + /* Sign-extend the constant if chars are signed on target machine. */ + { + if (lookup ("__CHAR_UNSIGNED__", sizeof ("__CHAR_UNSIGNED__")-1, -1) + || ((c >> (CHAR_TYPE_SIZE - 1)) & 1) == 0) + yylval.integer.value = c & ((1 << CHAR_TYPE_SIZE) - 1); + else + yylval.integer.value = c | ~((1 << CHAR_TYPE_SIZE) - 1); + } + + yylval.integer.unsignedp = 0; + c = *lexptr++; + if (c != '\'') { + yyerror ("Invalid character constant in #if"); + return ERROR; + } + + return CHAR; + + /* some of these chars are invalid in constant expressions; + maybe do something about them later */ + case '/': + case '+': + case '-': + case '*': + case '%': + case '|': + case '&': + case '^': + case '~': + case '!': + case '@': + case '<': + case '>': + case '(': + case ')': + case '[': + case ']': + case '.': + case '?': + case ':': + case '=': + case '{': + case '}': + case ',': + lexptr++; + return c; + + case '"': + yyerror ("double quoted strings not allowed in #if expressions"); + return ERROR; + } + if (c >= '0' && c <= '9') { + /* It's a number */ + for (namelen = 0; + c = tokstart[namelen], is_idchar[c] || c == '.'; + namelen++) + ; + return parse_number (namelen); + } + + if (!is_idstart[c]) { + yyerror ("Invalid token in expression"); + return ERROR; + } + + /* It is a name. See how long it is. */ + + for (namelen = 0; is_idchar[tokstart[namelen]]; namelen++) + ; + + lexptr += namelen; + return NAME; +} + + +/* Parse a C escape sequence. STRING_PTR points to a variable + containing a pointer to the string to parse. That pointer + is updated past the characters we use. The value of the + escape sequence is returned. + + A negative value means the sequence \ newline was seen, + which is supposed to be equivalent to nothing at all. + + If \ is followed by a null character, we return a negative + value and leave the string pointer pointing at the null character. + + 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) + char **string_ptr; +{ + register int c = *(*string_ptr)++; + switch (c) + { + case 'a': + return TARGET_BELL; + case 'b': + return TARGET_BS; + case 'e': + return 033; + case 'f': + return TARGET_FF; + case 'n': + return TARGET_NEWLINE; + case 'r': + return TARGET_CR; + case 't': + return TARGET_TAB; + case 'v': + return TARGET_VT; + case '\n': + return -2; + case 0: + (*string_ptr)--; + return 0; + case '^': + c = *(*string_ptr)++; + if (c == '\\') + c = parse_escape (string_ptr); + if (c == '?') + return 0177; + return (c & 0200) | (c & 037); + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + { + register int i = c - '0'; + register int count = 0; + while (++count < 3) + { + c = *(*string_ptr)++; + if (c >= '0' && c <= '7') + i = (i << 3) + c - '0'; + else + { + (*string_ptr)--; + break; + } + } + if ((i & ~((1 << CHAR_TYPE_SIZE) - 1)) != 0) + { + i &= (1 << CHAR_TYPE_SIZE) - 1; + warning ("octal character constant does not fit in a byte"); + } + return i; + } + case 'x': + { + register int i = 0; + register int count = 0; + for (;;) + { + c = *(*string_ptr)++; + if (c >= '0' && c <= '9') + i = (i << 4) + c - '0'; + else if (c >= 'a' && c <= 'f') + i = (i << 4) + c - 'a' + 10; + else if (c >= 'A' && c <= 'F') + i = (i << 4) + c - 'A' + 10; + else + { + (*string_ptr)--; + break; + } + } + if ((i & ~((1 << BITS_PER_UNIT) - 1)) != 0) + { + i &= (1 << BITS_PER_UNIT) - 1; + warning ("hex character constant does not fit in a byte"); + } + return i; + } + default: + return c; + } +} + +void +yyerror (s) + char *s; +{ + error (s); + longjmp (parse_return_error, 1); +} + +/* 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 + this function is called. */ + +int +parse_c_expression (string) + char *string; +{ + lexptr = string; + + if (lexptr == 0 || *lexptr == 0) { + error ("empty #if expression"); + return 0; /* don't include the #if group */ + } + + /* if there is some sort of scanning error, just return 0 and assume + the parsing routine has printed an error message somewhere. + there is surely a better thing to do than this. */ + if (setjmp (parse_return_error)) + return 0; + + if (yyparse ()) + return 0; /* actually this is never reached + the way things stand. */ + if (*lexptr) + error ("Junk after end of expression."); + + return expression_value; /* set by yyparse () */ +} + +#ifdef TEST_EXP_READER +/* main program, for testing purposes. */ +main () +{ + int n, c; + char buf[1024]; + extern int yydebug; +/* + yydebug = 1; +*/ + initialize_random_junk (); + + for (;;) { + printf ("enter expression: "); + n = 0; + while ((buf[n] = getchar ()) != '\n' && buf[n] != EOF) + n++; + if (buf[n] == EOF) + break; + buf[n] = '\0'; + printf ("parser returned %d\n", parse_c_expression (buf)); + } +} + +/* 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]; + +/* + * initialize random junk in the hash table and maybe other places + */ +initialize_random_junk () +{ + register int i; + + /* + * Set up is_idchar and is_idstart tables. These should be + * faster than saying (is_alpha (c) || c == '_'), etc. + * Must do set up these things before calling any routines tthat + * refer to them. + */ + for (i = 'a'; i <= 'z'; i++) { + ++is_idchar[i - 'a' + 'A']; + ++is_idchar[i]; + ++is_idstart[i - 'a' + 'A']; + ++is_idstart[i]; + } + for (i = '0'; i <= '9'; i++) + ++is_idchar[i]; + ++is_idchar['_']; + ++is_idstart['_']; +#if DOLLARS_IN_IDENTIFIERS + ++is_idchar['$']; + ++is_idstart['$']; +#endif + + /* horizontal space table */ + ++is_hor_space[' ']; + ++is_hor_space['\t']; +} + +error (msg) +{ + printf ("error: %s\n", msg); +} + +warning (msg) +{ + printf ("warning: %s\n", msg); +} + +struct hashnode * +lookup (name, len, hash) + char *name; + int len; + int hash; +{ + return (DEFAULT_SIGNED_CHAR) ? 0 : ((struct hashnode *) -1); +} +#endif diff --git a/gcc-1.40/cexp.y b/gcc-1.40/cexp.y new file mode 100644 index 0000000..88f2039 --- /dev/null +++ b/gcc-1.40/cexp.y @@ -0,0 +1,656 @@ +/* Parse C expressions for CCCP. + Copyright (C) 1987 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 +Free Software Foundation; either version 1, 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, 675 Mass Ave, Cambridge, MA 02139, 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! + + Adapted from expread.y of GDB by Paul Rubin, July 1986. + +/* Parse a C expression from text in a string */ + +%{ +#include "config.h" +#include +/* #define YYDEBUG 1 */ + + int yylex (); + void yyerror (); + int expression_value; + + static jmp_buf parse_return_error; + + /* some external tables of character types */ + extern unsigned char is_idstart[], is_idchar[]; + +#ifndef CHAR_TYPE_SIZE +#define CHAR_TYPE_SIZE BITS_PER_UNIT +#endif +%} + +%union { + struct constant {long value; int unsignedp;} integer; + int voidval; + char *sval; +} + +%type exp exp1 start +%token INT CHAR +%token NAME +%token ERROR + +%right '?' ':' +%left ',' +%left OR +%left AND +%left '|' +%left '^' +%left '&' +%left EQUAL NOTEQUAL +%left '<' '>' LEQ GEQ +%left LSH RSH +%left '+' '-' +%left '*' '/' '%' +%right UNARY + +/* %expect 40 */ + +%% + +start : exp1 + { expression_value = $1.value; } + ; + +/* Expressions, including the comma operator. */ +exp1 : exp + | exp1 ',' exp + { $$ = $3; } + ; + +/* Expressions, not including the comma operator. */ +exp : '-' exp %prec UNARY + { $$.value = - $2.value; + $$.unsignedp = $2.unsignedp; } + | '!' exp %prec UNARY + { $$.value = ! $2.value; + $$.unsignedp = 0; } + | '+' exp %prec UNARY + { $$ = $2; } + | '~' exp %prec UNARY + { $$.value = ~ $2.value; + $$.unsignedp = $2.unsignedp; } + | '(' exp1 ')' + { $$ = $2; } + ; + +/* Binary operators in order of decreasing precedence. */ +exp : exp '*' exp + { $$.unsignedp = $1.unsignedp || $3.unsignedp; + if ($$.unsignedp) + $$.value = (unsigned) $1.value * $3.value; + else + $$.value = $1.value * $3.value; } + | exp '/' exp + { if ($3.value == 0) + { + error ("division by zero in #if"); + $3.value = 1; + } + $$.unsignedp = $1.unsignedp || $3.unsignedp; + if ($$.unsignedp) + $$.value = (unsigned) $1.value / $3.value; + else + $$.value = $1.value / $3.value; } + | exp '%' exp + { if ($3.value == 0) + { + error ("division by zero in #if"); + $3.value = 1; + } + $$.unsignedp = $1.unsignedp || $3.unsignedp; + if ($$.unsignedp) + $$.value = (unsigned) $1.value % $3.value; + else + $$.value = $1.value % $3.value; } + | exp '+' exp + { $$.value = $1.value + $3.value; + $$.unsignedp = $1.unsignedp || $3.unsignedp; } + | exp '-' exp + { $$.value = $1.value - $3.value; + $$.unsignedp = $1.unsignedp || $3.unsignedp; } + | exp LSH exp + { $$.unsignedp = $1.unsignedp; + if ($$.unsignedp) + $$.value = (unsigned) $1.value << $3.value; + else + $$.value = $1.value << $3.value; } + | exp RSH exp + { $$.unsignedp = $1.unsignedp; + if ($$.unsignedp) + $$.value = (unsigned) $1.value >> $3.value; + else + $$.value = $1.value >> $3.value; } + | exp EQUAL exp + { $$.value = ($1.value == $3.value); + $$.unsignedp = 0; } + | exp NOTEQUAL exp + { $$.value = ($1.value != $3.value); + $$.unsignedp = 0; } + | exp LEQ exp + { $$.unsignedp = 0; + if ($1.unsignedp || $3.unsignedp) + $$.value = (unsigned) $1.value <= $3.value; + else + $$.value = $1.value <= $3.value; } + | exp GEQ exp + { $$.unsignedp = 0; + if ($1.unsignedp || $3.unsignedp) + $$.value = (unsigned) $1.value >= $3.value; + else + $$.value = $1.value >= $3.value; } + | exp '<' exp + { $$.unsignedp = 0; + if ($1.unsignedp || $3.unsignedp) + $$.value = (unsigned) $1.value < $3.value; + else + $$.value = $1.value < $3.value; } + | exp '>' exp + { $$.unsignedp = 0; + if ($1.unsignedp || $3.unsignedp) + $$.value = (unsigned) $1.value > $3.value; + else + $$.value = $1.value > $3.value; } + | exp '&' exp + { $$.value = $1.value & $3.value; + $$.unsignedp = $1.unsignedp || $3.unsignedp; } + | exp '^' exp + { $$.value = $1.value ^ $3.value; + $$.unsignedp = $1.unsignedp || $3.unsignedp; } + | exp '|' exp + { $$.value = $1.value | $3.value; + $$.unsignedp = $1.unsignedp || $3.unsignedp; } + | exp AND exp + { $$.value = ($1.value && $3.value); + $$.unsignedp = 0; } + | exp OR exp + { $$.value = ($1.value || $3.value); + $$.unsignedp = 0; } + | exp '?' exp ':' exp + { $$.value = $1.value ? $3.value : $5.value; + $$.unsignedp = $3.unsignedp || $5.unsignedp; } + | INT + { $$ = yylval.integer; } + | CHAR + { $$ = yylval.integer; } + | NAME + { $$.value = 0; + $$.unsignedp = 0; } + ; +%% + +/* During parsing of a C expression, the pointer to the next character + is in this variable. */ + +static char *lexptr; + +/* Take care of parsing a number (anything that starts with a digit). + Set yylval and return the token type; update lexptr. + LEN is the number of characters in it. */ + +/* maybe needs to actually deal with floating point numbers */ + +int +parse_number (olen) + int olen; +{ + register char *p = lexptr; + register long n = 0; + register int c; + register int base = 10; + register int len = olen; + + 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; + + if (len >= 3 && (!strncmp (p, "0x", 2) || !strncmp (p, "0X", 2))) { + p += 2; + base = 16; + len -= 2; + } + else if (*p == '0') + base = 8; + + while (len > 0) { + c = *p++; + len--; + if (c >= 'A' && c <= 'Z') c += 'a' - 'A'; + + if (c >= '0' && c <= '9') { + n *= base; + n += c - '0'; + } else if (base == 16 && c >= 'a' && c <= 'f') { + n *= base; + n += c - 'a' + 10; + } else { + /* `l' means long, and `u' means unsigned. */ + while (1) { + if (c == 'l' || c == 'L') + ; + else if (c == 'u' || c == 'U') + yylval.integer.unsignedp = 1; + else + break; + + if (len == 0) + break; + c = *p++; + len--; + } + /* Don't look for any more digits after the suffixes. */ + break; + } + } + + if (len != 0) { + yyerror ("Invalid number in #if expression"); + return ERROR; + } + + /* If too big to be signed, consider it unsigned. */ + if (n < 0) + yylval.integer.unsignedp = 1; + + lexptr = p; + yylval.integer.value = n; + return INT; +} + +struct token { + char *operator; + int token; +}; + +#ifndef NULL +#define NULL 0 +#endif + +static struct token tokentab2[] = { + {"&&", AND}, + {"||", OR}, + {"<<", LSH}, + {">>", RSH}, + {"==", EQUAL}, + {"!=", NOTEQUAL}, + {"<=", LEQ}, + {">=", GEQ}, + {NULL, ERROR} +}; + +/* Read one token, getting characters through lexptr. */ + +int +yylex () +{ + register int c; + register int namelen; + register char *tokstart; + register struct token *toktab; + + retry: + + tokstart = lexptr; + c = *tokstart; + /* See if it is a special token of length 2. */ + for (toktab = tokentab2; toktab->operator != NULL; toktab++) + if (c == *toktab->operator && tokstart[1] == toktab->operator[1]) { + lexptr += 2; + return toktab->token; + } + + switch (c) { + case 0: + return 0; + + case ' ': + case '\t': + case '\r': + case '\n': + lexptr++; + goto retry; + + case '\'': + lexptr++; + c = *lexptr++; + if (c == '\\') + c = parse_escape (&lexptr); + + /* Sign-extend the constant if chars are signed on target machine. */ + { + if (lookup ("__CHAR_UNSIGNED__", sizeof ("__CHAR_UNSIGNED__")-1, -1) + || ((c >> (CHAR_TYPE_SIZE - 1)) & 1) == 0) + yylval.integer.value = c & ((1 << CHAR_TYPE_SIZE) - 1); + else + yylval.integer.value = c | ~((1 << CHAR_TYPE_SIZE) - 1); + } + + yylval.integer.unsignedp = 0; + c = *lexptr++; + if (c != '\'') { + yyerror ("Invalid character constant in #if"); + return ERROR; + } + + return CHAR; + + /* some of these chars are invalid in constant expressions; + maybe do something about them later */ + case '/': + case '+': + case '-': + case '*': + case '%': + case '|': + case '&': + case '^': + case '~': + case '!': + case '@': + case '<': + case '>': + case '(': + case ')': + case '[': + case ']': + case '.': + case '?': + case ':': + case '=': + case '{': + case '}': + case ',': + lexptr++; + return c; + + case '"': + yyerror ("double quoted strings not allowed in #if expressions"); + return ERROR; + } + if (c >= '0' && c <= '9') { + /* It's a number */ + for (namelen = 0; + c = tokstart[namelen], is_idchar[c] || c == '.'; + namelen++) + ; + return parse_number (namelen); + } + + if (!is_idstart[c]) { + yyerror ("Invalid token in expression"); + return ERROR; + } + + /* It is a name. See how long it is. */ + + for (namelen = 0; is_idchar[tokstart[namelen]]; namelen++) + ; + + lexptr += namelen; + return NAME; +} + + +/* Parse a C escape sequence. STRING_PTR points to a variable + containing a pointer to the string to parse. That pointer + is updated past the characters we use. The value of the + escape sequence is returned. + + A negative value means the sequence \ newline was seen, + which is supposed to be equivalent to nothing at all. + + If \ is followed by a null character, we return a negative + value and leave the string pointer pointing at the null character. + + 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) + char **string_ptr; +{ + register int c = *(*string_ptr)++; + switch (c) + { + case 'a': + return TARGET_BELL; + case 'b': + return TARGET_BS; + case 'e': + return 033; + case 'f': + return TARGET_FF; + case 'n': + return TARGET_NEWLINE; + case 'r': + return TARGET_CR; + case 't': + return TARGET_TAB; + case 'v': + return TARGET_VT; + case '\n': + return -2; + case 0: + (*string_ptr)--; + return 0; + case '^': + c = *(*string_ptr)++; + if (c == '\\') + c = parse_escape (string_ptr); + if (c == '?') + return 0177; + return (c & 0200) | (c & 037); + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + { + register int i = c - '0'; + register int count = 0; + while (++count < 3) + { + c = *(*string_ptr)++; + if (c >= '0' && c <= '7') + i = (i << 3) + c - '0'; + else + { + (*string_ptr)--; + break; + } + } + if ((i & ~((1 << CHAR_TYPE_SIZE) - 1)) != 0) + { + i &= (1 << CHAR_TYPE_SIZE) - 1; + warning ("octal character constant does not fit in a byte"); + } + return i; + } + case 'x': + { + register int i = 0; + register int count = 0; + for (;;) + { + c = *(*string_ptr)++; + if (c >= '0' && c <= '9') + i = (i << 4) + c - '0'; + else if (c >= 'a' && c <= 'f') + i = (i << 4) + c - 'a' + 10; + else if (c >= 'A' && c <= 'F') + i = (i << 4) + c - 'A' + 10; + else + { + (*string_ptr)--; + break; + } + } + if ((i & ~((1 << BITS_PER_UNIT) - 1)) != 0) + { + i &= (1 << BITS_PER_UNIT) - 1; + warning ("hex character constant does not fit in a byte"); + } + return i; + } + default: + return c; + } +} + +void +yyerror (s) + char *s; +{ + error (s); + longjmp (parse_return_error, 1); +} + +/* 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 + this function is called. */ + +int +parse_c_expression (string) + char *string; +{ + lexptr = string; + + if (lexptr == 0 || *lexptr == 0) { + error ("empty #if expression"); + return 0; /* don't include the #if group */ + } + + /* if there is some sort of scanning error, just return 0 and assume + the parsing routine has printed an error message somewhere. + there is surely a better thing to do than this. */ + if (setjmp (parse_return_error)) + return 0; + + if (yyparse ()) + return 0; /* actually this is never reached + the way things stand. */ + if (*lexptr) + error ("Junk after end of expression."); + + return expression_value; /* set by yyparse () */ +} + +#ifdef TEST_EXP_READER +/* main program, for testing purposes. */ +main () +{ + int n, c; + char buf[1024]; + extern int yydebug; +/* + yydebug = 1; +*/ + initialize_random_junk (); + + for (;;) { + printf ("enter expression: "); + n = 0; + while ((buf[n] = getchar ()) != '\n' && buf[n] != EOF) + n++; + if (buf[n] == EOF) + break; + buf[n] = '\0'; + printf ("parser returned %d\n", parse_c_expression (buf)); + } +} + +/* 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]; + +/* + * initialize random junk in the hash table and maybe other places + */ +initialize_random_junk () +{ + register int i; + + /* + * Set up is_idchar and is_idstart tables. These should be + * faster than saying (is_alpha (c) || c == '_'), etc. + * Must do set up these things before calling any routines tthat + * refer to them. + */ + for (i = 'a'; i <= 'z'; i++) { + ++is_idchar[i - 'a' + 'A']; + ++is_idchar[i]; + ++is_idstart[i - 'a' + 'A']; + ++is_idstart[i]; + } + for (i = '0'; i <= '9'; i++) + ++is_idchar[i]; + ++is_idchar['_']; + ++is_idstart['_']; +#if DOLLARS_IN_IDENTIFIERS + ++is_idchar['$']; + ++is_idstart['$']; +#endif + + /* horizontal space table */ + ++is_hor_space[' ']; + ++is_hor_space['\t']; +} + +error (msg) +{ + printf ("error: %s\n", msg); +} + +warning (msg) +{ + printf ("warning: %s\n", msg); +} + +struct hashnode * +lookup (name, len, hash) + char *name; + int len; + int hash; +{ + return (DEFAULT_SIGNED_CHAR) ? 0 : ((struct hashnode *) -1); +} +#endif diff --git a/gcc-1.40/combine.c b/gcc-1.40/combine.c new file mode 100644 index 0000000..cc6676e --- /dev/null +++ b/gcc-1.40/combine.c @@ -0,0 +1,2796 @@ +/* Optimize by combining instructions for GNU compiler. + Copyright (C) 1987, 1988 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 1, 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 is essentially the "combiner" phase of the U. of Arizona + Portable Optimizer, but redone to work on our list-structured + representation for RTL instead of their string representation. + + The LOG_LINKS of each insn identify the most recent assignment + to each REG used in the insn. It is a list of previous insns, + each of which contains a SET for a REG that is used in this insn + and not used or set in between. LOG_LINKs never cross basic blocks. + They were set up by the preceding pass (lifetime analysis). + + We try to combine each pair of insns joined by a logical link. + We also try to combine triples of insns A, B and C when + C has a link back to B and B has a link back to A. + + LOG_LINKS does not have links for use of the CC0. They don't + need to, because the insn that sets the CC0 is always immediately + before the insn that tests it. So we always regard a branch + insn as having a logical link to the preceding insn. + + We check (with use_crosses_set_p) to avoid combining in such a way + as to move a computation to a place where its value would be different. + + Combination is done by mathematically substituting the previous + insn(s) values for the regs they set into the expressions in + the later insns that refer to these regs. If the result is a valid insn + for our target machine, according to the machine description, + we install it, delete the earlier insns, and update the data flow + information (LOG_LINKS and REG_NOTES) for what we did. + + To simplify substitution, we combine only when the earlier insn(s) + consist of only a single assignment. To simplify updating afterward, + we never combine when a subroutine call appears in the middle. + + Since we do not represent assignments to CC0 explicitly except when that + is all an insn does, there is no LOG_LINKS entry in an insn that uses + the condition code for the insn that set the condition code. + Fortunately, these two insns must be consecutive. + Therefore, every JUMP_INSN is taken to have an implicit logical link + to the preceding insn. This is not quite right, since non-jumps can + also use the condition code; but in practice such insns would not + combine anyway. */ + +#include + +#include "config.h" +#include "rtl.h" +#include "flags.h" +#include "regs.h" +#include "basic-block.h" +#include "insn-config.h" +#include "recog.h" + +#define max(A,B) ((A) > (B) ? (A) : (B)) +#define min(A,B) ((A) < (B) ? (A) : (B)) + +/* It is not safe to use ordinary gen_lowpart in combine. + Use gen_lowpart_for_combine instead. See comments there. */ +#define gen_lowpart dont_use_gen_lowpart_you_dummy + +/* Number of attempts to combine instructions in this function. */ + +static int combine_attempts; +static int distrib_attempts; + +/* Number of attempts that got as far as substitution in this function. */ + +static int combine_merges; +static int distrib_merges_1, distrib_merges_2; + +/* Number of instructions combined with added SETs in this function. */ + +static int combine_extras; + +/* Number of instructions combined in this function. */ + +static int combine_successes; +static int distrib_successes; + +/* Totals over entire compilation. */ + +static int total_attempts, total_merges, total_extras, total_successes; +static int total_distrib_attempts, total_distrib_merges_1, total_distrib_merges_2, total_distrib_successes; + + +/* Vector mapping INSN_UIDs to cuids. + The cuids are like uids but increase monononically always. + Combine always uses cuids so that it can compare them. + But actually renumbering the uids, which we used to do, + proves to be a bad idea because it makes it hard to compare + the dumps produced by earlier passes with those from later passes. */ + +static int *uid_cuid; + +/* Get the cuid of an insn. */ + +#define INSN_CUID(INSN) (uid_cuid[INSN_UID (INSN)]) + + +/* Record last point of death of (hard or pseudo) register n. */ + +static rtx *reg_last_death; + +/* Record last point of modification of (hard or pseudo) register n. */ + +static rtx *reg_last_set; + +/* Record the cuid of the last insn that invalidated memory + (anything that writes memory, and subroutine calls). */ + +static int mem_last_set; + +/* Record the cuid of the last CALL_INSN + so we can tell whether a potential combination crosses any calls. */ + +static int last_call_cuid; + +/* When `subst' is called, this is the insn that is being modified + (by combining in a previous insn). The PATTERN of this insn + is still the old pattern partially modified and it should not be + looked at, but this may be used to examine the successors of the insn + to judge whether a simplification is valid. */ + +static rtx subst_insn; + +/* Record one modification to rtl structure + to be undone by storing old_contents into *where. + is_int is 1 if the contents are an int. */ + +struct undo +{ + rtx *where; + rtx old_contents; + int is_int; +}; + +struct undo_int +{ + int *where; + int old_contents; + int is_int; +}; + +/* Record a bunch of changes to be undone, up to MAX_UNDO of them. + num_undo says how many are currently recorded. + storage is nonzero if we must undo the allocation of new storage. + The value of storage is what to pass to obfree. */ + +#define MAX_UNDO 10 + +struct undobuf +{ + int num_undo; + char *storage; + struct undo undo[MAX_UNDO]; +}; + +static struct undobuf undobuf; + +/* Number of times the pseudo being substituted for + was found and replaced. */ + +static int n_occurrences; + +static void move_deaths (); +static void move_deaths_2 (); +void remove_death (); +static void record_dead_and_set_regs (); +int regno_dead_p (); +static int use_crosses_set_p (); +static int try_combine (); +static rtx try_distrib (); +static rtx subst (); +static void undo_all (); +static void copy_substitutions (); +static void add_links (); +static void remove_links (); +static void add_incs (); +static int adjacent_insns_p (); +static int check_asm_operands (); +static rtx simplify_and_const_int (); +static rtx gen_lowpart_for_combine (); +static void simplify_set_cc0_and (); + +/* Main entry point for combiner. F is the first insn of the function. + NREGS is the first unused pseudo-reg number. */ + +void +combine_instructions (f, nregs) + rtx f; + int nregs; +{ + register rtx insn; + register int i; + register rtx links, nextlinks; + rtx prev; + + combine_attempts = 0; + combine_merges = 0; + combine_extras = 0; + combine_successes = 0; + distrib_attempts = 0; + distrib_merges_1 = 0; + distrib_merges_2 = 0; + distrib_successes = 0; + + reg_last_death = (rtx *) alloca (nregs * sizeof (rtx)); + reg_last_set = (rtx *) alloca (nregs * sizeof (rtx)); + bzero (reg_last_death, nregs * sizeof (rtx)); + bzero (reg_last_set, nregs * sizeof (rtx)); + + init_recog (); + + /* Compute maximum uid value so uid_cuid can be allocated. */ + + for (insn = f, i = 0; insn; insn = NEXT_INSN (insn)) + if (INSN_UID (insn) > i) + i = INSN_UID (insn); + + uid_cuid = (int *) alloca ((i + 1) * sizeof (int)); + + /* Compute the mapping from uids to cuids. + Cuids are numbers assigned to insns, like uids, + except that cuids increase monotonically through the code. */ + + for (insn = f, i = 0; insn; insn = NEXT_INSN (insn)) + INSN_CUID (insn) = ++i; + + /* Now scan all the insns in forward order. */ + + last_call_cuid = 0; + mem_last_set = 0; + prev = 0; + + for (insn = f; insn; insn = NEXT_INSN (insn)) + { + if (GET_CODE (insn) == INSN + || GET_CODE (insn) == CALL_INSN + || GET_CODE (insn) == JUMP_INSN) + { + retry: + /* Try this insn with each insn it links back to. */ + + for (links = LOG_LINKS (insn); links; links = XEXP (links, 1)) + if (try_combine (insn, XEXP (links, 0), 0)) + goto retry; + + /* Try each sequence of three linked insns ending with this one. */ + + for (links = LOG_LINKS (insn); links; links = XEXP (links, 1)) + if (GET_CODE (XEXP (links, 0)) != NOTE) + for (nextlinks = LOG_LINKS (XEXP (links, 0)); nextlinks; + nextlinks = XEXP (nextlinks, 1)) + if (try_combine (insn, XEXP (links, 0), XEXP (nextlinks, 0))) + goto retry; + + /* Try to combine a jump insn that uses CC0 + with a preceding insn that sets CC0, and maybe with its + logical predecessor as well. + This is how we make decrement-and-branch insns. + We need this special code because data flow connections + via CC0 do not get entered in LOG_LINKS. */ + + if (GET_CODE (insn) == JUMP_INSN + && prev != 0 + && GET_CODE (prev) == INSN + && GET_CODE (PATTERN (prev)) == SET + && GET_CODE (SET_DEST (PATTERN (prev))) == CC0) + { + if (try_combine (insn, prev, 0)) + goto retry; + + if (GET_CODE (prev) != NOTE) + for (nextlinks = LOG_LINKS (prev); nextlinks; + nextlinks = XEXP (nextlinks, 1)) + if (try_combine (insn, prev, XEXP (nextlinks, 0))) + goto retry; + } + + /* Try to apply the distributive law to this insn + and two insns that compute the operands of this one. */ + for (links = LOG_LINKS (insn); links; links = XEXP (links, 1)) + if (GET_CODE (XEXP (links, 0)) != NOTE) + for (nextlinks = XEXP (links, 1); nextlinks; nextlinks = XEXP (nextlinks, 1)) + if (GET_CODE (XEXP (nextlinks, 0)) != NOTE) + { + rtx try_from = 0; + + if (GET_CODE (PATTERN (XEXP (links, 0))) == SET + && find_reg_note (insn, REG_DEAD, SET_DEST (PATTERN (XEXP (links, 0)))) + && GET_CODE (PATTERN (XEXP (nextlinks, 0))) == SET + && find_reg_note (insn, REG_DEAD, SET_DEST (PATTERN (XEXP (nextlinks, 0))))) + try_from = try_distrib (insn, XEXP (links, 0), XEXP (nextlinks, 0)); + if (try_from != 0) + { + insn = try_from; + goto retry; + } + } +#if 0 +/* Turned off because on 68020 it takes four insns to make + something like (a[b / 32] & (1 << (31 - (b % 32)))) != 0 + that could actually be optimized, and that's an unlikely piece of code. */ + /* If an insn gets or sets a bit field, try combining it + with two different insns whose results it uses. */ + if (GET_CODE (insn) == INSN + && GET_CODE (PATTERN (insn)) == SET + && (GET_CODE (SET_DEST (PATTERN (insn))) == ZERO_EXTRACT + || GET_CODE (SET_DEST (PATTERN (insn))) == SIGN_EXTRACT + || GET_CODE (SET_SRC (PATTERN (insn))) == ZERO_EXTRACT + || GET_CODE (SET_SRC (PATTERN (insn))) == SIGN_EXTRACT)) + { + for (links = LOG_LINKS (insn); links; links = XEXP (links, 1)) + if (GET_CODE (XEXP (links, 0)) != NOTE) + for (nextlinks = XEXP (links, 1); nextlinks; + nextlinks = XEXP (nextlinks, 1)) + if (try_combine (insn, XEXP (links, 0), XEXP (nextlinks, 0))) + goto retry; + } +#endif + if (GET_CODE (insn) != NOTE) + record_dead_and_set_regs (insn); + prev = insn; + } + else if (GET_CODE (insn) != NOTE) + prev = 0; + } + total_attempts += combine_attempts; + total_merges += combine_merges; + total_extras += combine_extras; + total_successes += combine_successes; +} + +/* Try to combine the insns I1 and I2 into I3. + Here I1 appears earlier than I2, which is earlier than I3. + I1 can be zero; then we combine just I2 into I3. + + Return 1 if successful; if that happens, I1 and I2 are pseudo-deleted + by turning them into NOTEs, and I3 is modified. + Return 0 if the combination does not work. Then nothing is changed. */ + +static int +try_combine (i3, i2, i1) + register rtx i3, i2, i1; +{ + register rtx newpat; + int added_sets_1 = 0; + int added_sets_2 = 0; + int total_sets; + int i2_is_used; + register rtx link; + int insn_code_number; + rtx i2dest, i2src; + rtx i1dest, i1src; + int maxreg; + rtx temp; + int i; + + combine_attempts++; + + /* Don't combine with something already used up by combination. */ + + if (GET_CODE (i2) == NOTE + || (i1 && GET_CODE (i1) == NOTE)) + return 0; + + /* Don't combine across a CALL_INSN, because that would possibly + change whether the life span of some REGs crosses calls or not, + and it is a pain to update that information. */ + + if (INSN_CUID (i2) < last_call_cuid + || (i1 && INSN_CUID (i1) < last_call_cuid)) + return 0; + + /* Can combine only if previous insn is a SET of a REG, a SUBREG or CC0. + That REG must be either set or dead by the final instruction + (so that we can safely forget about setting it). + Also test use_crosses_set_p to make sure that the value + that is to be substituted for the register + does not use any registers whose values alter in between. + Do not try combining with moves from one register to another + since it is better to let them be tied by register allocation. + (There is a switch to permit such combination; except the insns + that copy a function value into another register are never combined + because moving that too far away from the function call could cause + something else to be stored in that register in the interim.) + + A set of a SUBREG is considered as if it were a set from + SUBREG. Thus, (SET (SUBREG:X (REG:Y...)) (something:X...)) + is handled by substituting (SUBREG:Y (something:X...)) for (REG:Y...). */ + + if (GET_CODE (PATTERN (i2)) != SET) + return 0; + i2dest = SET_DEST (PATTERN (i2)); + i2src = SET_SRC (PATTERN (i2)); + if (GET_CODE (i2dest) == SUBREG) + { + i2dest = SUBREG_REG (i2dest); + i2src = gen_rtx (SUBREG, GET_MODE (i2dest), i2src, 0); + } + /* Don't eliminate a store in the stack pointer. */ + if (i2dest == stack_pointer_rtx) + return 0; + /* 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. */ + if (GET_CODE (i2src) == SUBREG + && ! MODES_TIEABLE_P (GET_MODE (i2src), GET_MODE (SUBREG_REG (i2src)))) + return 0; + if (GET_CODE (i2dest) != CC0 + && (GET_CODE (i2dest) != REG + || (GET_CODE (i2src) == REG + /* Do allow the combination of y = x; x = y; (with x dead) + because the result will turn into nothing. */ + && !(GET_CODE (PATTERN (i3)) == SET + && i2src == SET_DEST (PATTERN (i3))) + && (!flag_combine_regs + /* Don't substitute a function value reg for any other. */ + || FUNCTION_VALUE_REGNO_P (REGNO (i2src)))) + || GET_CODE (i2src) == CALL + /* Don't substitute into an incremented register. */ + || find_reg_note (i3, REG_INC, i2dest) + || use_crosses_set_p (i2src, INSN_CUID (i2)))) + return 0; + if (GET_CODE (i2src) == ASM_OPERANDS && MEM_VOLATILE_P (i2src)) + return 0; + /* Don't substitute for a register intended as a clobberable operand. */ + if (GET_CODE (PATTERN (i3)) == PARALLEL) + for (i = 0; i < XVECLEN (PATTERN (i3), 0); i++) + if (GET_CODE (XVECEXP (PATTERN (i3), 0, i)) == CLOBBER + && XEXP (XVECEXP (PATTERN (i3), 0, i), 0) == i2dest) + return 0; + + if (i1 != 0) + { + if (GET_CODE (PATTERN (i1)) != SET) + return 0; + i1dest = SET_DEST (PATTERN (i1)); + i1src = SET_SRC (PATTERN (i1)); + if (GET_CODE (i1dest) == SUBREG) + { + i1dest = SUBREG_REG (i1dest); + i1src = gen_rtx (SUBREG, GET_MODE (i1dest), i1src, 0); + } + if (i1dest == stack_pointer_rtx) + return 0; + if (GET_CODE (i1src) == SUBREG + && ! MODES_TIEABLE_P (GET_MODE (i1src), + GET_MODE (SUBREG_REG (i1src)))) + return 0; + if (GET_CODE (i1dest) != CC0 + && (GET_CODE (i1dest) != REG + || (GET_CODE (i1src) == REG + && (!flag_combine_regs + || FUNCTION_VALUE_REGNO_P (REGNO (i1src)))) + || GET_CODE (i1src) == CALL + || find_reg_note (i3, REG_INC, i1dest) + || find_reg_note (i2, REG_INC, i1dest) + || use_crosses_set_p (i1src, INSN_CUID (i1)))) + return 0; + if (GET_CODE (i1src) == ASM_OPERANDS && MEM_VOLATILE_P (i1src)) + return 0; + /* Don't substitute for a register intended as a clobberable operand. */ + if (GET_CODE (PATTERN (i3)) == PARALLEL) + for (i = 0; i < XVECLEN (PATTERN (i3), 0); i++) + if (GET_CODE (XVECEXP (PATTERN (i3), 0, i)) == CLOBBER + && XEXP (XVECEXP (PATTERN (i3), 0, i), 0) == i1dest) + return 0; + } + + /* If it is better that two different modes keep two different pseudos, + avoid combining them. */ + if (GET_CODE (PATTERN (i3)) == SET) + { + rtx i3dest = SET_DEST (PATTERN (i3)); + while (GET_CODE (i3dest) == SUBREG + || GET_CODE (i3dest) == STRICT_LOW_PART + || GET_CODE (i3dest) == SIGN_EXTRACT + || GET_CODE (i3dest) == ZERO_EXTRACT) + i3dest = SUBREG_REG (i3dest); + + if (SET_SRC (PATTERN (i3)) == i2dest + && GET_CODE (i3dest) == REG + && ! MODES_TIEABLE_P (GET_MODE (i2dest), GET_MODE (i3dest))) + return 0; + } + + /* If I2 contains anything volatile, reject, unless nothing + volatile comes between it and I3. */ + if (volatile_refs_p (PATTERN (i2))) + { + rtx insn; + for (insn = NEXT_INSN (i2); insn != i3; insn = NEXT_INSN (insn)) + if (GET_CODE (insn) == INSN || GET_CODE (insn) == CALL_INSN + || GET_CODE (insn) == JUMP_INSN) + if (volatile_refs_p (PATTERN (insn))) + return 0; + } + /* Likewise for I1; nothing volatile can come between it and I3, + except optionally I2. */ + if (i1 && volatile_refs_p (PATTERN (i1))) + { + rtx insn; + rtx end = (volatile_refs_p (PATTERN (i2)) ? i2 : i3); + for (insn = NEXT_INSN (i1); insn != end; insn = NEXT_INSN (insn)) + if (GET_CODE (insn) == INSN || GET_CODE (insn) == CALL_INSN + || GET_CODE (insn) == JUMP_INSN) + if (volatile_refs_p (PATTERN (insn))) + return 0; + } + + /* If I1 or I2 contains an autoincrement or autodecrement, + make sure that register is not used between there and I3, + and not already used in I3 either. + Also insist that I3 not be a jump; if it were one + and the incremented register were spilled, we would lose. */ + for (link = REG_NOTES (i2); link; link = XEXP (link, 1)) + if (REG_NOTE_KIND (link) == REG_INC + && (GET_CODE (i3) == JUMP_INSN + || reg_used_between_p (XEXP (link, 0), i2, i3) + || reg_mentioned_p (XEXP (link, 0), PATTERN (i3)))) + return 0; + + if (i1) + for (link = REG_NOTES (i1); link; link = XEXP (link, 1)) + if (REG_NOTE_KIND (link) == REG_INC + && (GET_CODE (i3) == JUMP_INSN + || reg_used_between_p (XEXP (link, 0), i1, i3) + || reg_mentioned_p (XEXP (link, 0), PATTERN (i3)))) + return 0; + + /* If I3 has an inc, then give up if I1 or I2 uses the reg that is inc'd, + EXCEPT in one case: I3 has a post-inc in an output operand. */ + if (!(GET_CODE (PATTERN (i3)) == SET + && GET_CODE (SET_SRC (PATTERN (i3))) == REG + && GET_CODE (SET_DEST (PATTERN (i3))) == MEM + && (GET_CODE (XEXP (SET_DEST (PATTERN (i3)), 0)) == POST_INC + || GET_CODE (XEXP (SET_DEST (PATTERN (i3)), 0)) == POST_DEC))) + /* It's not the exception. */ + for (link = REG_NOTES (i3); link; link = XEXP (link, 1)) + if (REG_NOTE_KIND (link) == REG_INC + && (reg_mentioned_p (XEXP (link, 0), PATTERN (i2)) + || (i1 != 0 + && reg_mentioned_p (XEXP (link, 0), PATTERN (i1))))) + return 0; + + /* Don't combine an insn I1 or I2 that follows a CC0-setting insn. + An insn that uses CC0 must not be separated from the one that sets it. + It would be more logical to test whether CC0 occurs inside I1 or I2, + but that would be much slower, and this ought to be equivalent. */ + temp = PREV_INSN (i2); + while (temp && GET_CODE (temp) == NOTE) + temp = PREV_INSN (temp); + if (temp && GET_CODE (temp) == INSN && sets_cc0_p (PATTERN (temp))) + return 0; + if (i1) + { + temp = PREV_INSN (i2); + while (temp && GET_CODE (temp) == NOTE) + temp = PREV_INSN (temp); + if (temp && GET_CODE (temp) == INSN && sets_cc0_p (PATTERN (temp))) + return 0; + } + + /* See if the SETs in i1 or i2 need to be kept around in the merged + instruction: whenever the value set there is still needed past i3. */ + added_sets_2 = (GET_CODE (i2dest) != CC0 + && ! dead_or_set_p (i3, i2dest)); + if (i1) + added_sets_1 = ! (dead_or_set_p (i3, i1dest) + || dead_or_set_p (i2, i1dest)); + + combine_merges++; + + undobuf.num_undo = 0; + undobuf.storage = 0; + + /* Substitute in the latest insn for the regs set by the earlier ones. */ + + maxreg = max_reg_num (); + + subst_insn = i3; + n_occurrences = 0; /* `subst' counts here */ + + newpat = subst (PATTERN (i3), i2dest, i2src); + /* Record whether i2's body now appears within i3's body. */ + i2_is_used = n_occurrences; + + if (i1) + { + n_occurrences = 0; + newpat = subst (newpat, i1dest, i1src); + } + + if (GET_CODE (PATTERN (i3)) == SET + && SET_DEST (PATTERN (i3)) == cc0_rtx + && (GET_CODE (SET_SRC (PATTERN (i3))) == AND + || GET_CODE (SET_SRC (PATTERN (i3))) == LSHIFTRT) + && next_insn_tests_no_inequality (i3)) + simplify_set_cc0_and (i3); + + if (max_reg_num () != maxreg) + abort (); + + /* If the actions of the earler insns must be kept + in addition to substituting them into the latest one, + we must make a new PARALLEL for the latest insn + to hold additional the SETs. */ + + if (added_sets_1 || added_sets_2) + { + combine_extras++; + + /* Arrange to free later what we allocate now + if we don't accept this combination. */ + if (!undobuf.storage) + undobuf.storage = (char *) oballoc (0); + + if (GET_CODE (newpat) == PARALLEL) + { + 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 (&old->elem[0], &XVECEXP (newpat, 0, 0), + 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)); + XVECEXP (newpat, 0, 0) = old; + } + if (added_sets_1) + { + XVECEXP (newpat, 0, --total_sets) = PATTERN (i1); + } + if (added_sets_2) + { + /* If there is no I1, use I2's body as is. */ + if (i1 == 0 + /* If I2 was stuck into I3, then anything within it has + already had I1 substituted into it when that was done to I3. */ + || i2_is_used) + { + XVECEXP (newpat, 0, --total_sets) = PATTERN (i2); + } + else + XVECEXP (newpat, 0, --total_sets) + = subst (PATTERN (i2), i1dest, i1src); + } + } + + /* Fail if an autoincrement side-effect has been duplicated. */ + if ((i2_is_used > 1 && find_reg_note (i2, REG_INC, 0) != 0) + || (i1 != 0 && n_occurrences > 1 && find_reg_note (i1, REG_INC, 0) != 0)) + { + undo_all (); + return 0; + } + + /* Is the result of combination a valid instruction? */ + insn_code_number = recog (newpat, i3); + + if (insn_code_number >= 0 + /* Is the result a reasonable ASM_OPERANDS? */ + || (check_asm_operands (newpat) && ! added_sets_1 && ! added_sets_2)) + { + /* Yes. Install it. */ + register int regno; + INSN_CODE (i3) = insn_code_number; + PATTERN (i3) = newpat; + /* If anything was substituted more than once, + copy it to avoid invalid shared rtl structure. */ + copy_substitutions (); + /* The data flowing into I2 now flows into I3. + But we cannot always move all of I2's LOG_LINKS into I3, + since they must go to a setting of a REG from the + first use following. If I2 was the first use following a set, + I3 is now a use, but it is not the first use + if some instruction between I2 and I3 is also a use. + Here, for simplicity, we move all the links only if + there are no real insns between I2 and I3. + Otherwise, we move only links that correspond to regs + that used to die in I2. They are always safe to move. */ + add_links (i3, i2, adjacent_insns_p (i2, i3)); + /* Most REGs that previously died in I2 now die in I3. */ + move_deaths (i2src, INSN_CUID (i2), i3); + if (GET_CODE (i2dest) == REG) + { + /* 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. */ + regno = REGNO (i2dest); + if (! added_sets_2) + { + reg_n_sets[regno]--; + /* Used to check && regno_dead_p (regno, i3) also here. */ + if (reg_n_sets[regno] == 0 + && ! (basic_block_live_at_start[0][regno / HOST_BITS_PER_INT] + & (1 << (regno % HOST_BITS_PER_INT)))) + reg_n_refs[regno] = 0; + } + /* If a ref to REGNO was substituted into I3 from I2, + then it still dies there if it previously did. + Otherwise either REGNO never did die in I3 so remove_death is safe + or this entire life of REGNO is gone so remove its death. */ + if (!added_sets_2 + && ! reg_mentioned_p (i2dest, PATTERN (i3))) + remove_death (regno, i3); + } + /* Any registers previously autoincremented in I2 + are now incremented in I3. */ + add_incs (i3, REG_NOTES (i2)); + if (i1) + { + /* Likewise, merge the info from I1 and get rid of it. */ + add_links (i3, i1, + adjacent_insns_p (i1, i2) && adjacent_insns_p (i2, i3)); + move_deaths (i1src, INSN_CUID (i1), i3); + if (GET_CODE (i1dest) == REG) + { + regno = REGNO (i1dest); + if (! added_sets_1) + { + reg_n_sets[regno]--; + /* Used to also check && regno_dead_p (regno, i3) here. */ + + if (reg_n_sets[regno] == 0 + && ! (basic_block_live_at_start[0][regno / HOST_BITS_PER_INT] + & (1 << (regno % HOST_BITS_PER_INT)))) + + reg_n_refs[regno] = 0; + } + /* If a ref to REGNO was substituted into I3 from I1, + then it still dies there if it previously did. + Else either REGNO never did die in I3 so remove_death is safe + or this entire life of REGNO is gone so remove its death. */ + if (! added_sets_1 + && ! reg_mentioned_p (i1dest, PATTERN (i3))) + remove_death (regno, i3); + } + add_incs (i3, REG_NOTES (i1)); + LOG_LINKS (i1) = 0; + PUT_CODE (i1, NOTE); + NOTE_LINE_NUMBER (i1) = NOTE_INSN_DELETED; + NOTE_SOURCE_FILE (i1) = 0; + } + /* Get rid of I2. */ + LOG_LINKS (i2) = 0; + PUT_CODE (i2, NOTE); + NOTE_LINE_NUMBER (i2) = NOTE_INSN_DELETED; + NOTE_SOURCE_FILE (i2) = 0; + + combine_successes++; + return 1; + } + + /* Failure: change I3 back the way it was. */ + undo_all (); + + return 0; +} + +/* Undo all the modifications recorded in undobuf. */ + +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--) + *undobuf.undo[i].where = undobuf.undo[i].old_contents; + if (undobuf.storage) + obfree (undobuf.storage); + undobuf.num_undo = 0; + undobuf.storage = 0; +} + +/* If this insn had more than one substitution, + copy all but one, so that no invalid shared substructure is introduced. */ + +static void +copy_substitutions () +{ + register int i; + if (undobuf.num_undo > 1) + { + for (i = undobuf.num_undo - 1; i >= 1; i--) + if (! undobuf.undo[i].is_int) + *undobuf.undo[i].where = copy_rtx (*undobuf.undo[i].where); + } +} + +/* Throughout X, replace FROM with TO, and return the result. + The result is TO if X is FROM; + otherwise the result is X, but its contents may have been modified. + If they were modified, a record was made in undobuf so that + undo_all will (among other things) return X to its original state. + + If the number of changes necessary is too much to record to undo, + the excess changes are not made, so the result is invalid. + The changes already made can still be undone. + undobuf.num_undo is incremented for such changes, so by testing that + the caller can tell whether the result is valid. + + `n_occurrences' is incremented each time FROM is replaced. */ + +static rtx +subst (x, from, to) + register rtx x, from, to; +{ + register char *fmt; + register int len, i; + register enum rtx_code code; + char was_replaced[2]; + +#define SUBST(INTO, NEWVAL) \ + do { if (undobuf.num_undo < MAX_UNDO) \ + { \ + undobuf.undo[undobuf.num_undo].where = &INTO; \ + undobuf.undo[undobuf.num_undo].old_contents = INTO; \ + undobuf.undo[undobuf.num_undo].is_int = 0; \ + INTO = NEWVAL; \ + } \ + undobuf.num_undo++; } while (0) + +#define SUBST_INT(INTO, NEWVAL) \ + do { if (undobuf.num_undo < MAX_UNDO) \ + { \ + struct undo_int *u = (struct undo_int *)&undobuf.undo[undobuf.num_undo];\ + u->where = &INTO; \ + u->old_contents = INTO; \ + u->is_int = 1; \ + INTO = NEWVAL; \ + } \ + undobuf.num_undo++; } while (0) + +/* FAKE_EXTEND_SAFE_P (MODE, FROM) is 1 if (subreg:MODE FROM 0) is a safe + replacement for (zero_extend:MODE FROM) or (sign_extend:MODE FROM). + If it is 0, that cannot be done. We can now do this for any MEM + because (SUBREG (MEM...)) is guaranteed to cause the MEM to be reloaded. + If not for that, MEM's would very rarely be safe. */ + +/* Reject MODEs bigger than a word, because we might not be able + to reference a two-register group starting with an arbitrary register + (and currently gen_lowpart might crash for a SUBREG). */ + +#define FAKE_EXTEND_SAFE_P(MODE, FROM) \ + (GET_MODE_SIZE (MODE) <= UNITS_PER_WORD \ + && (GET_CODE (FROM) == REG || GET_CODE (FROM) == SUBREG \ + || GET_CODE (FROM) == MEM)) + + if (x == from) + return to; + + /* It is possible to have a subexpression appear twice in the insn. + Suppose that FROM is a register that appears within TO. + Then, after that subexpression has been scanned once by `subst', + the second time it is scanned, TO may be found. If we were + to scan TO here, we would find FROM within it and create a + self-referent rtl structure which is completely wrong. */ + if (x == to) + return to; + + code = GET_CODE (x); + + /* A little bit of algebraic simplification here. */ + switch (code) + { + /* This case has no effect except to speed things up. */ + case REG: + case CONST_INT: + case CONST: + case SYMBOL_REF: + case LABEL_REF: + case PC: + case CC0: + return x; + } + + was_replaced[0] = 0; + was_replaced[1] = 0; + + len = GET_RTX_LENGTH (code); + fmt = GET_RTX_FORMAT (code); + + /* Don't replace FROM where it is being stored in rather than used. */ + if (code == SET && SET_DEST (x) == from) + fmt = "ie"; + if (code == SET && GET_CODE (SET_DEST (x)) == SUBREG + && SUBREG_REG (SET_DEST (x)) == from) + fmt = "ie"; + + for (i = 0; i < len; i++) + { + if (fmt[i] == 'E') + { + register int j; + for (j = XVECLEN (x, i) - 1; j >= 0; j--) + { + register rtx new; + if (XVECEXP (x, i, j) == from) + new = to, n_occurrences++; + else + new = subst (XVECEXP (x, i, j), from, to); + if (new != XVECEXP (x, i, j)) + SUBST (XVECEXP (x, i, j), new); + } + } + else if (fmt[i] == 'e') + { + register rtx new; + + if (XEXP (x, i) == from) + { + new = to; + n_occurrences++; + if (i < 2) + was_replaced[i] = 1; + } + else + new = subst (XEXP (x, i), from, to); + + if (new != XEXP (x, i)) + SUBST (XEXP (x, i), new); + } + } + + /* A little bit of algebraic simplification here. */ + switch (code) + { + case SUBREG: + /* Changing mode twice with SUBREG => just change it once, + or not at all if changing back to starting mode. */ + if (SUBREG_REG (x) == to + && GET_CODE (to) == SUBREG) + { + if (GET_MODE (x) == GET_MODE (SUBREG_REG (to))) + if (SUBREG_WORD (x) == 0 && SUBREG_WORD (to) == 0) + return SUBREG_REG (to); + SUBST (SUBREG_REG (x), SUBREG_REG (to)); + if (SUBREG_WORD (to) != 0) + SUBST_INT (SUBREG_WORD (x), SUBREG_WORD (x) + SUBREG_WORD (to)); + } + if (SUBREG_REG (x) == to + && (GET_CODE (to) == SIGN_EXTEND || GET_CODE (to) == ZERO_EXTEND) + && subreg_lowpart_p (x)) + { + /* (subreg (sign_extend X)) is X, if it has same mode as X. */ + if (GET_MODE (x) == GET_MODE (XEXP (to, 0))) + return XEXP (to, 0); + /* (subreg (sign_extend X)), if it has a mode wider than X, + can be done with (sign_extend X). */ + if (GET_MODE_SIZE (GET_MODE (x)) > GET_MODE_SIZE (GET_MODE (XEXP (to, 0)))) + { + if (!undobuf.storage) + undobuf.storage = (char *) oballoc (0); + return gen_rtx (GET_CODE (to), GET_MODE (x), XEXP (to, 0)); + } + /* Extend and then truncate smaller than it was to start with: + no need to extend. */ + if (GET_MODE_SIZE (GET_MODE (x)) < GET_MODE_SIZE (GET_MODE (XEXP (to, 0)))) + { + SUBST (XEXP (x, 0), XEXP (to, 0)); + } + } + /* (subreg:A (mem:B X) N) becomes a modified MEM. + If we can't do that safely, then it becomes something nonsensical + so that this combination won't take place. + This avoids producing any (subreg (mem))s except in the special + paradoxical case where gen_lowpart_for_combine makes them. */ + if (SUBREG_REG (x) == to + && GET_CODE (to) == MEM) + { + int endian_offset = 0; + /* Don't combine this if mode A is wider than B. */ + if (GET_MODE_SIZE (GET_MODE (x)) > GET_MODE_SIZE (GET_MODE (to))) + return gen_rtx (CLOBBER, VOIDmode, const0_rtx); + /* Don't change the mode of the MEM + if that would change the meaning of the address. */ + if (mode_dependent_address_p (XEXP (to, 0))) + return gen_rtx (CLOBBER, VOIDmode, const0_rtx); +#ifdef BYTES_BIG_ENDIAN + if (GET_MODE_SIZE (GET_MODE (x)) < UNITS_PER_WORD) + endian_offset += UNITS_PER_WORD - GET_MODE_SIZE (GET_MODE (x)); + if (GET_MODE_SIZE (GET_MODE (to)) < UNITS_PER_WORD) + endian_offset -= UNITS_PER_WORD - GET_MODE_SIZE (GET_MODE (to)); +#endif + if (!undobuf.storage) + undobuf.storage = (char *) oballoc (0); + /* Note if the plus_constant doesn't make a valid address + then this combination won't be accepted. */ + return gen_rtx (MEM, GET_MODE (x), + plus_constant (XEXP (to, 0), + (SUBREG_WORD (x) * UNITS_PER_WORD + + endian_offset))); + } + break; + + case NOT: + /* (not (minus X 1)) can become (neg X). */ + if (was_replaced[0] + && ((GET_CODE (to) == PLUS && INTVAL (XEXP (to, 1)) == -1) + || (GET_CODE (to) == MINUS && XEXP (to, 1) == const1_rtx))) + { + if (!undobuf.storage) + undobuf.storage = (char *) oballoc (0); + return gen_rtx (NEG, GET_MODE (to), XEXP (to, 0)); + } + /* Don't let substitution introduce double-negatives. */ + if (was_replaced[0] + && GET_CODE (to) == code) + return XEXP (to, 0); + break; + + case NEG: + /* (neg (minus X Y)) can become (minus Y X). */ + if (was_replaced[0] && GET_CODE (to) == MINUS) + { + if (!undobuf.storage) + undobuf.storage = (char *) oballoc (0); + return gen_rtx (MINUS, GET_MODE (to), + XEXP (to, 1), XEXP (to, 0)); + } + /* Don't let substitution introduce double-negatives. */ + if (was_replaced[0] + && GET_CODE (to) == code) + return XEXP (to, 0); + break; + + case FLOAT_TRUNCATE: + /* (float_truncate:SF (float_extend:DF foo:SF)) = foo:SF. */ + if (was_replaced[0] + && GET_CODE (to) == FLOAT_EXTEND + && GET_MODE (XEXP (to, 0)) == GET_MODE (x)) + return XEXP (to, 0); + break; + +#if 0 + case COMPARE: + /* -x>0 if 0>x. */ + if (GET_CODE (XEXP (x, 0)) == NEG && XEXP (x, 1) == const0_rtx) + { + SUBST (XEXP (x, 1), XEXP (XEXP (x, 0), 0)); + SUBST (XEXP (x, 0), const0_rtx); + } + if (GET_CODE (XEXP (x, 1)) == NEG && XEXP (x, 0) == const0_rtx) + { + SUBST (XEXP (x, 0), XEXP (XEXP (x, 1), 0)); + SUBST (XEXP (x, 1), const0_rtx); + } + break; +#endif + + case PLUS: +#if 0 /* Turned off for caution: turn it on after 1.36. */ + /* Identify constant sums as such. */ + if ((was_replaced[0] || was_replaced[1]) + && CONSTANT_P (XEXP (x, 0)) + && CONSTANT_P (XEXP (x, 1))) + { + if (!undobuf.storage) + undobuf.storage = (char *) oballoc (0); + return gen_rtx (CONST, GET_MODE (x), x); + } +#endif + /* In (plus (ashift )) + change the shift to a multiply so we can recognize + scaled indexed addresses. */ + if ((was_replaced[0] + || was_replaced[1]) + && GET_CODE (to) == ASHIFT + && GET_CODE (XEXP (to, 1)) == CONST_INT + && INTVAL (XEXP (to, 1)) < HOST_BITS_PER_INT) + { + rtx temp; + if (!undobuf.storage) + undobuf.storage = (char *) oballoc (0); + temp = gen_rtx (MULT, GET_MODE (to), + XEXP (to, 0), + gen_rtx (CONST_INT, VOIDmode, + 1 << INTVAL (XEXP (to, 1)))); + if (was_replaced[0]) + SUBST (XEXP (x, 0), temp); + else + SUBST (XEXP (x, 1), temp); + } + /* (plus X (neg Y)) becomes (minus X Y). */ + if (GET_CODE (XEXP (x, 1)) == NEG) + { + if (!undobuf.storage) + undobuf.storage = (char *) oballoc (0); + return gen_rtx (MINUS, GET_MODE (x), + XEXP (x, 0), XEXP (XEXP (x, 1), 0)); + } + /* (plus (neg X) Y) becomes (minus Y X). */ + if (GET_CODE (XEXP (x, 0)) == NEG) + { + if (!undobuf.storage) + undobuf.storage = (char *) oballoc (0); + return gen_rtx (MINUS, GET_MODE (x), + XEXP (x, 1), XEXP (XEXP (x, 0), 0)); + } + /* (plus (plus x c1) c2) => (plus x c1+c2) */ + if (GET_CODE (XEXP (x, 1)) == CONST_INT + && GET_CODE (XEXP (x, 0)) == PLUS + && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT) + { + int sum = (INTVAL (XEXP (x, 1)) + + INTVAL (XEXP (XEXP (x, 0), 1))); + if (sum == 0) + return XEXP (XEXP (x, 0), 0); + if (!undobuf.storage) + undobuf.storage = (char *) oballoc (0); + SUBST (XEXP (x, 1), gen_rtx (CONST_INT, VOIDmode, sum)); + SUBST (XEXP (x, 0), XEXP (XEXP (x, 0), 0)); + break; + } + /* If we have something (putative index) being added to a sum, + associate it so that any constant term is outermost. + That's because that's the way indexed addresses are + now supposed to appear. */ + if (((was_replaced[0] && GET_CODE (XEXP (x, 1)) == PLUS) + || (was_replaced[1] && GET_CODE (XEXP (x, 0)) == PLUS)) + || + ((was_replaced[0] || was_replaced[1]) + && GET_CODE (to) == PLUS)) + { + rtx offset = 0, base, index; + if (GET_CODE (to) != PLUS) + { + index = to; + base = was_replaced[0] ? XEXP (x, 1) : XEXP (x, 0); + } + else + { + index = was_replaced[0] ? XEXP (x, 1) : XEXP (x, 0); + base = to; + } + if (CONSTANT_ADDRESS_P (XEXP (base, 0))) + { + offset = XEXP (base, 0); + base = XEXP (base, 1); + } + else if (CONSTANT_ADDRESS_P (XEXP (base, 1))) + { + offset = XEXP (base, 1); + base = XEXP (base, 0); + } + if (offset != 0) + { + if (!undobuf.storage) + undobuf.storage = (char *) oballoc (0); + if (GET_CODE (offset) == CONST_INT) + return plus_constant (gen_rtx (PLUS, GET_MODE (index), + base, index), + INTVAL (offset)); + if (GET_CODE (index) == CONST_INT) + return plus_constant (gen_rtx (PLUS, GET_MODE (offset), + base, offset), + INTVAL (index)); + return gen_rtx (PLUS, GET_MODE (index), + gen_rtx (PLUS, GET_MODE (index), + base, index), + offset); + } + } + break; + + case EQ: + case NE: + /* If comparing a subreg against zero, discard the subreg. */ + if (was_replaced[0] + && GET_CODE (to) == SUBREG + && SUBREG_WORD (to) == 0 + && XEXP (x, 1) == const0_rtx) + SUBST (XEXP (x, 0), SUBREG_REG (to)); + + /* If comparing a ZERO_EXTRACT against zero, + canonicalize to a SIGN_EXTRACT, + since the two are equivalent here. */ + if (was_replaced[0] + && GET_CODE (to) == ZERO_EXTRACT + && XEXP (x, 1) == const0_rtx) + { + if (!undobuf.storage) + undobuf.storage = (char *) oballoc (0); + SUBST (XEXP (x, 0), + gen_rtx (SIGN_EXTRACT, GET_MODE (to), + XEXP (to, 0), XEXP (to, 1), + XEXP (to, 2))); + } +#ifndef BITS_BIG_ENDIAN + /* If we are putting (ASHIFT 1 x) into (EQ (AND ... y) 0), + arrange to return (EQ (SIGN_EXTRACT y 1 x) 0), + which is what jump-on-bit instructions are written with. */ + else if (XEXP (x, 1) == const0_rtx + && GET_CODE (XEXP (x, 0)) == AND + && (XEXP (XEXP (x, 0), 0) == to + || XEXP (XEXP (x, 0), 1) == to) + && GET_CODE (to) == ASHIFT + && XEXP (to, 0) == const1_rtx) + { + register rtx y = XEXP (XEXP (x, 0), + XEXP (XEXP (x, 0), 0) == to); + if (!undobuf.storage) + undobuf.storage = (char *) oballoc (0); + SUBST (XEXP (x, 0), + gen_rtx (SIGN_EXTRACT, GET_MODE (to), + y, + const1_rtx, XEXP (to, 1))); + } +#endif /* not BITS_BIG_ENDIAN */ + /* Negation is a no-op before equality test against zero. */ + if (GET_CODE (XEXP (x, 0)) == NEG && XEXP (x, 1) == const0_rtx) + { + SUBST (XEXP (x, 0), XEXP (XEXP (x, 0), 0)); + } + if (GET_CODE (XEXP (x, 1)) == NEG && XEXP (x, 0) == const0_rtx) + { + SUBST (XEXP (x, 1), XEXP (XEXP (x, 1), 0)); + } + break; + + case ZERO_EXTEND: + /* Nested zero-extends are equivalent to just one. */ + if (was_replaced[0] + && GET_CODE (to) == ZERO_EXTEND) + SUBST (XEXP (x, 0), XEXP (to, 0)); + /* Zero extending a constant int can be replaced + by a zero-extended constant. */ + if (was_replaced[0] + && HOST_BITS_PER_INT >= GET_MODE_BITSIZE (GET_MODE (from)) + && GET_CODE (to) == CONST_INT) + { + int intval = INTVAL (to) & GET_MODE_MASK (GET_MODE (from)); + if (!undobuf.storage) + undobuf.storage = (char *) oballoc (0); + return gen_rtx (CONST_INT, VOIDmode, intval); + } + /* Zero-extending the result of an and with a constant can be done + with a wider and. */ + if (was_replaced[0] + && GET_CODE (to) == AND + && GET_CODE (XEXP (to, 1)) == CONST_INT + && FAKE_EXTEND_SAFE_P (GET_MODE (x), XEXP (to, 0)) + /* Avoid getting wrong result if the constant has high bits set + that are irrelevant in the narrow mode where it is being used. */ + && 0 == (INTVAL (XEXP (to, 1)) + & ~ GET_MODE_MASK (GET_MODE (to)))) + { + if (!undobuf.storage) + undobuf.storage = (char *) oballoc (0); + return gen_rtx (AND, GET_MODE (x), + gen_lowpart_for_combine (GET_MODE (x), XEXP (to, 0)), + XEXP (to, 1)); + } + /* Change (zero_extend:M (subreg:N (zero_extract:M ...) 0)) + to (zero_extract:M ...) if the field extracted fits in mode N. */ + if (GET_CODE (XEXP (x, 0)) == SUBREG + && GET_CODE (XEXP (XEXP (x, 0), 0)) == ZERO_EXTRACT + && GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 1)) == CONST_INT + && (INTVAL (XEXP (XEXP (XEXP (x, 0), 0), 1)) + <= GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0))))) + { + return XEXP (XEXP (x, 0), 0); + } + /* Change (zero_extend:M (subreg:N (and:M ... ) 0)) + to (and:M ...) if the significant bits fit in mode N. */ + if (GET_CODE (XEXP (x, 0)) == SUBREG + && SUBREG_REG (XEXP (x, 0)) == to + && SUBREG_WORD (XEXP (x, 0)) == 0 + && GET_CODE (to) == AND + && GET_CODE (XEXP (to, 1)) == CONST_INT + && FAKE_EXTEND_SAFE_P (GET_MODE (x), XEXP (to, 0)) + /* Avoid getting wrong result if the constant has high bits set + that are irrelevant in the narrow mode where it is being used. */ + && 0 == (INTVAL (XEXP (to, 1)) + & ~ GET_MODE_MASK (GET_MODE (to)))) + { + if (!undobuf.storage) + undobuf.storage = (char *) oballoc (0); + return gen_rtx (AND, GET_MODE (x), + gen_lowpart_for_combine (GET_MODE (x), XEXP (to, 0)), + XEXP (to, 1)); + } + /* In (zero_extend:M (subreg:N (lshiftrt:M REG))), + where REG was assigned from (zero_extend:M (any:N ...)), + remove the outer zero extension. */ + if (GET_CODE (XEXP (x, 0)) == SUBREG + && SUBREG_REG (XEXP (x, 0)) == to + && SUBREG_WORD (XEXP (x, 0)) == 0 + && GET_CODE (to) == LSHIFTRT) + { + rtx tmp = XEXP (to, 0); + + /* See if arg of LSHIFTRT is a register whose value we can find. */ + if (GET_CODE (tmp) == REG) + if (reg_n_sets[REGNO (tmp)] == 1 + && reg_last_set[REGNO (tmp)] != 0 + && SET_DEST (PATTERN (reg_last_set[REGNO (tmp)])) == tmp) + tmp = SET_SRC (PATTERN (reg_last_set[REGNO (tmp)])); + else + break; + + if (GET_CODE (tmp) == ZERO_EXTEND + && GET_MODE (tmp) == GET_MODE (x) + && GET_MODE (XEXP (tmp, 0)) == GET_MODE (XEXP (x, 0))) + return SUBREG_REG (XEXP (x, 0)); + } + break; + + case SIGN_EXTEND: + /* Nested sign-extends are equivalent to just one. */ + if (was_replaced[0] + && GET_CODE (to) == SIGN_EXTEND) + SUBST (XEXP (x, 0), XEXP (to, 0)); + /* Sign extending a constant int can be replaced + by a sign-extended constant. */ + if (was_replaced[0] + && HOST_BITS_PER_INT >= GET_MODE_BITSIZE (GET_MODE (from)) + && GET_CODE (to) == CONST_INT) + { + int intval = INTVAL (to); + if (!undobuf.storage) + undobuf.storage = (char *) oballoc (0); + if (intval > 0 + && (intval & (1 << (GET_MODE_BITSIZE (GET_MODE (from)) - 1)))) + intval |= ~ GET_MODE_MASK (GET_MODE (from)); + return gen_rtx (CONST_INT, VOIDmode, intval); + } + /* Sign-extending the result of an and with a constant can be done + with a wider and, provided the high bit of the constant is 0. */ + if (was_replaced[0] + && GET_CODE (to) == AND + && GET_CODE (XEXP (to, 1)) == CONST_INT + && FAKE_EXTEND_SAFE_P (GET_MODE (x), XEXP (to, 0)) + && ((INTVAL (XEXP (to, 1)) + & (-1 << (GET_MODE_BITSIZE (GET_MODE (to)) - 1))) + == 0)) + { + if (!undobuf.storage) + undobuf.storage = (char *) oballoc (0); + return gen_rtx (AND, GET_MODE (x), + gen_lowpart_for_combine (GET_MODE (x), XEXP (to, 0)), + XEXP (to, 1)); + } + /* hacks added by tiemann. */ + /* Change (sign_extend:M (subreg:N (and:M ... ) 0)) + to (and:M ...), provided the result fits in mode N, + and the high bit of the constant is 0 in mode N. */ + if (GET_CODE (XEXP (x, 0)) == SUBREG + && SUBREG_REG (XEXP (x, 0)) == to + && SUBREG_WORD (XEXP (x, 0)) == 0 + && GET_CODE (to) == AND + && GET_CODE (XEXP (to, 1)) == CONST_INT + && FAKE_EXTEND_SAFE_P (GET_MODE (x), XEXP (to, 0)) + && ((INTVAL (XEXP (to, 1)) + & (-1 << (GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0))) - 1))) + == 0)) + { + if (!undobuf.storage) + undobuf.storage = (char *) oballoc (0); + return gen_rtx (AND, GET_MODE (x), + gen_lowpart_for_combine (GET_MODE (x), XEXP (to, 0)), + XEXP (to, 1)); + } + /* In (sign_extend:M (subreg:N (ashiftrt:M REG))), + where REG was assigned from (sign_extend:M (any:N ...)), + remove the outer sign extension. */ + if (GET_CODE (XEXP (x, 0)) == SUBREG + && SUBREG_REG (XEXP (x, 0)) == to + && SUBREG_WORD (XEXP (x, 0)) == 0 + && GET_CODE (to) == ASHIFTRT) + { + rtx tmp = XEXP (to, 0); + + /* See if arg of LSHIFTRT is a register whose value we can find. */ + if (GET_CODE (tmp) == REG) + if (reg_n_sets[REGNO (tmp)] == 1 + && reg_last_set[REGNO (tmp)] != 0 + && SET_DEST (PATTERN (reg_last_set[REGNO (tmp)])) == tmp) + tmp = SET_SRC (PATTERN (reg_last_set[REGNO (tmp)])); + else + break; + + if (GET_CODE (tmp) == SIGN_EXTEND + && GET_MODE (tmp) == GET_MODE (x) + && GET_MODE (XEXP (tmp, 0)) == GET_MODE (XEXP (x, 0))) + return SUBREG_REG (XEXP (x, 0)); + } + break; + + case SET: + /* In (set (zero-extract ) (and <(2**n-1) | anything>)) + the `and' can be deleted. This can happen when storing a bit + that came from a set-flag insn followed by masking to one bit. */ + if (GET_CODE (XEXP (x, 0)) == ZERO_EXTRACT + && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT + && was_replaced[1] + && GET_CODE (to) == AND + && GET_CODE (XEXP (to, 1)) == CONST_INT + && 0 == (((1 << INTVAL (XEXP (XEXP (x, 0), 1))) - 1) + & ~ INTVAL (XEXP (to, 1)))) + { + SUBST (XEXP (x, 1), XEXP (to, 0)); + } + /* In (set (zero-extract ) + (subreg (and <(2**n-1) | anything>))) + the `and' can be deleted. */ + if (GET_CODE (XEXP (x, 0)) == ZERO_EXTRACT + && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT + && GET_CODE (XEXP (x, 1)) == SUBREG + && SUBREG_WORD (XEXP (x, 1)) == 0 + && GET_CODE (SUBREG_REG (XEXP (x, 1))) == AND + && GET_CODE (XEXP (SUBREG_REG (XEXP (x, 1)), 1)) == CONST_INT + && 0 == (((1 << INTVAL (XEXP (XEXP (x, 0), 1))) - 1) + & ~ INTVAL (XEXP (SUBREG_REG (XEXP (x, 1)), 1)))) + { + SUBST (SUBREG_REG (XEXP (x, 1)), XEXP (SUBREG_REG (XEXP (x, 1)), 0)); + } + /* (set (zero_extract ...) (and/or/xor (zero_extract ...) const)), + if both zero_extracts have the same location, size and position, + can be changed to avoid the byte extracts. */ + if ((GET_CODE (XEXP (x, 0)) == ZERO_EXTRACT + || GET_CODE (XEXP (x, 0)) == SIGN_EXTRACT) + && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT + && (GET_CODE (XEXP (x, 1)) == AND + || GET_CODE (XEXP (x, 1)) == IOR + || GET_CODE (XEXP (x, 1)) == XOR) + && rtx_equal_p (XEXP (x, 0), XEXP (XEXP (x, 1), 0)) + && GET_CODE (XEXP (XEXP (x, 1), 0)) == GET_CODE (XEXP (x, 0)) + && GET_CODE (XEXP (XEXP (x, 1), 1)) == CONST_INT + /* zero_extract can apply to a QImode even if the bits extracted + don't fit inside that byte. In such a case, we may not do this + optimization, since the OR or AND insn really would need + to fit in a byte. */ + && (INTVAL (XEXP (XEXP (x, 0), 1)) + INTVAL (XEXP (XEXP (x, 0), 2)) + < GET_MODE_BITSIZE (GET_MODE (XEXP (XEXP (x, 0), 0))))) + { + int shiftcount; + int newmask; +#ifdef BITS_BIG_ENDIAN + shiftcount + = GET_MODE_BITSIZE (GET_MODE (XEXP (XEXP (x, 0), 0))) + - INTVAL (XEXP (XEXP (x, 0), 1)) - INTVAL (XEXP (XEXP (x, 0), 2)); +#else + shiftcount + = INTVAL (XEXP (XEXP (x, 0), 2)); +#endif + newmask = ((INTVAL (XEXP (XEXP (x, 1), 1)) << shiftcount) + + (GET_CODE (XEXP (x, 1)) == AND + ? (1 << shiftcount) - 1 + : 0)); + if (GET_MODE_BITSIZE (GET_MODE (XEXP (XEXP (x, 0), 0))) + < HOST_BITS_PER_INT) + newmask &= (1 << GET_MODE_BITSIZE (GET_MODE (XEXP (XEXP (x, 0), 0)))) - 1; + if (!undobuf.storage) + undobuf.storage = (char *) oballoc (0); + return + gen_rtx (SET, VOIDmode, + XEXP (XEXP (x, 0), 0), + gen_rtx (GET_CODE (XEXP (x, 1)), + GET_MODE (XEXP (XEXP (x, 0), 0)), + XEXP (XEXP (XEXP (x, 1), 0), 0), + gen_rtx (CONST_INT, VOIDmode, newmask))); + } + /* Can simplify (set (cc0) (compare (zero/sign_extend FOO) CONST)) + to (set (cc0) (compare FOO CONST)) if CONST fits in FOO's mode + and we are only testing equality. + In fact, this is valid for zero_extend if what follows is an + unsigned comparison, and for sign_extend with a signed comparison. */ + if (SET_DEST (x) == cc0_rtx + && GET_CODE (SET_SRC (x)) == COMPARE + && (GET_CODE (XEXP (SET_SRC (x), 0)) == ZERO_EXTEND + || GET_CODE (XEXP (SET_SRC (x), 0)) == SIGN_EXTEND) + && next_insn_tests_no_inequality (subst_insn) + && GET_CODE (XEXP (SET_SRC (x), 1)) == CONST_INT + /* This is overly cautious by one bit, but saves worrying about + whether it is zero-extension or sign extension. */ + && ((unsigned) INTVAL (XEXP (SET_SRC (x), 1)) + < (1 << (GET_MODE_BITSIZE (GET_MODE (XEXP (XEXP (SET_SRC (x), 0), 0))) - 1)))) + SUBST (XEXP (SET_SRC (x), 0), XEXP (XEXP (SET_SRC (x), 0), 0)); + break; + + case AND: + if (GET_CODE (XEXP (x, 1)) == CONST_INT) + { + rtx tem = simplify_and_const_int (x, to); + if (tem) + return tem; + } + break; + + case IOR: + case XOR: + /* (ior (ior x c1) c2) => (ior x c1|c2); likewise for xor. */ + if (GET_CODE (XEXP (x, 1)) == CONST_INT + && GET_CODE (XEXP (x, 0)) == code + && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT) + { + int c0 = INTVAL (XEXP (x, 1)); + int c1 = INTVAL (XEXP (XEXP (x, 0), 1)); + int combined = (code == IOR ? c0 | c1 : c0 ^ c1); + + if (combined == 0) + return XEXP (XEXP (x, 0), 0); + if (!undobuf.storage) + undobuf.storage = (char *) oballoc (0); + SUBST (XEXP (x, 1), gen_rtx (CONST_INT, VOIDmode, combined)); + SUBST (XEXP (x, 0), XEXP (XEXP (x, 0), 0)); + break; + } + + case FLOAT: + /* (float (sign_extend )) = (float ). */ + if (was_replaced[0] + && GET_CODE (to) == SIGN_EXTEND) + SUBST (XEXP (x, 0), XEXP (to, 0)); + break; + + case ZERO_EXTRACT: + /* (ZERO_EXTRACT (TRUNCATE x)...) + can become (ZERO_EXTRACT x ...). */ + if (was_replaced[0] + && GET_CODE (to) == TRUNCATE) + { +#ifdef BITS_BIG_ENDIAN + if (GET_CODE (XEXP (x, 2)) == CONST_INT) + { + if (!undobuf.storage) + undobuf.storage = (char *) oballoc (0); + /* On a big-endian machine, must increment the bit-number + since sign bit is farther away in the pre-truncated value. */ + return gen_rtx (ZERO_EXTRACT, GET_MODE (x), + XEXP (to, 0), + XEXP (x, 1), + gen_rtx (CONST_INT, VOIDmode, + (INTVAL (XEXP (x, 2)) + + GET_MODE_BITSIZE (GET_MODE (XEXP (to, 0))) + - GET_MODE_BITSIZE (GET_MODE (to))))); + } +#else + SUBST (XEXP (x, 0), XEXP (to, 0)); +#endif + } + /* Extracting a single bit from the result of a shift: + see which bit it was before the shift and extract that directly. */ + if (was_replaced[0] + && (GET_CODE (to) == ASHIFTRT || GET_CODE (to) == LSHIFTRT + || GET_CODE (to) == ASHIFT || GET_CODE (to) == LSHIFT) + && GET_CODE (XEXP (to, 1)) == CONST_INT + && XEXP (x, 1) == const1_rtx + && GET_CODE (XEXP (x, 2)) == CONST_INT) + { + int shift = INTVAL (XEXP (to, 1)); + int newpos; + if (GET_CODE (to) == ASHIFT || GET_CODE (to) == LSHIFT) + shift = - shift; +#ifdef BITS_BIG_ENDIAN + shift = - shift; +#endif + newpos = INTVAL (XEXP (x, 2)) + shift; + if (newpos >= 0 && + newpos < GET_MODE_BITSIZE (GET_MODE (to))) + { + if (!undobuf.storage) + undobuf.storage = (char *) oballoc (0); + return gen_rtx (ZERO_EXTRACT, GET_MODE (x), + XEXP (to, 0), const1_rtx, + gen_rtx (CONST_INT, VOIDmode, newpos)); + } + } + break; + + case LSHIFTRT: + case ASHIFTRT: + case ROTATE: + case ROTATERT: +#ifdef SHIFT_COUNT_TRUNCATED + /* (lshift (sign_extend )) = (lshift ) (most machines). + True for all kinds of shifts and also for zero_extend. */ + if (was_replaced[1] + && (GET_CODE (to) == SIGN_EXTEND + || GET_CODE (to) == ZERO_EXTEND) + && FAKE_EXTEND_SAFE_P (GET_MODE (to), XEXP (to, 0))) + { + if (!undobuf.storage) + undobuf.storage = (char *) oballoc (0); + SUBST (XEXP (x, 1), + /* This is a perverse SUBREG, wider than its base. */ + gen_lowpart_for_combine (GET_MODE (to), XEXP (to, 0))); + } +#endif + /* Two shifts in a row of same kind + in same direction with constant counts + may be combined. */ + if (was_replaced[0] + && GET_CODE (to) == GET_CODE (x) + && GET_CODE (XEXP (x, 1)) == CONST_INT + && GET_CODE (XEXP (to, 1)) == CONST_INT + && INTVAL (XEXP (to, 1)) > 0 + && INTVAL (XEXP (x, 1)) > 0 + && (INTVAL (XEXP (x, 1)) + INTVAL (XEXP (to, 1)) + < GET_MODE_BITSIZE (GET_MODE (x)))) + { + if (!undobuf.storage) + undobuf.storage = (char *) oballoc (0); + return gen_rtx (GET_CODE (x), GET_MODE (x), + XEXP (to, 0), + gen_rtx (CONST_INT, VOIDmode, + INTVAL (XEXP (x, 1)) + + INTVAL (XEXP (to, 1)))); + } + break; + + case LSHIFT: + case ASHIFT: +#ifdef SHIFT_COUNT_TRUNCATED + /* (lshift (sign_extend )) = (lshift ) (most machines). + True for all kinds of shifts and also for zero_extend. */ + if (was_replaced[1] + && (GET_CODE (to) == SIGN_EXTEND + || GET_CODE (to) == ZERO_EXTEND) + && FAKE_EXTEND_SAFE_P (GET_MODE (to), XEXP (to, 0))) + { + if (!undobuf.storage) + undobuf.storage = (char *) oballoc (0); + SUBST (XEXP (x, 1), + /* This is a perverse SUBREG, wider than its base. */ + gen_lowpart_for_combine (GET_MODE (to), XEXP (to, 0))); + } +#endif + /* (lshift (and (lshiftrt ) ) ) + happens copying between bit fields in similar structures. + It can be replaced by one and instruction. + It does not matter whether the shifts are logical or arithmetic. */ + if (GET_CODE (XEXP (x, 0)) == AND + && GET_CODE (XEXP (x, 1)) == CONST_INT + && INTVAL (XEXP (x, 1)) > 0 + && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT + && XEXP (XEXP (x, 0), 0) == to + && (GET_CODE (to) == LSHIFTRT + || GET_CODE (to) == ASHIFTRT) +#if 0 +/* I now believe this restriction is unnecessary. + The outer shift will discard those bits in any case, right? */ + + /* If inner shift is arithmetic, either it shifts left or + the bits it shifts the sign into are zeroed by the and. */ + && (INTVAL (XEXP (x, 1)) < 0 + || ((unsigned) INTVAL (XEXP (XEXP (x, 0), 1)) + < 1 << (GET_MODE_BITSIZE (GET_MODE (x)) + - INTVAL (XEXP (x, 0))))) +#endif + && GET_CODE (XEXP (to, 1)) == CONST_INT + && INTVAL (XEXP (x, 1)) == INTVAL (XEXP (to, 1))) + { + if (!undobuf.storage) + undobuf.storage = (char *) oballoc (0); + /* The constant in the new `and' is << + but clear out all bits that don't belong in our mode. */ + return gen_rtx (AND, GET_MODE (x), XEXP (to, 0), + gen_rtx (CONST_INT, VOIDmode, + (GET_MODE_MASK (GET_MODE (x)) + & ((GET_MODE_MASK (GET_MODE (x)) + & INTVAL (XEXP (XEXP (x, 0), 1))) + << INTVAL (XEXP (x, 1)))))); + } + /* Two shifts in a row in same direction with constant counts + may be combined. */ + if (was_replaced[0] + && (GET_CODE (to) == ASHIFT || GET_CODE (to) == LSHIFT) + && GET_CODE (XEXP (x, 1)) == CONST_INT + && GET_CODE (XEXP (to, 1)) == CONST_INT + && INTVAL (XEXP (to, 1)) > 0 + && INTVAL (XEXP (x, 1)) > 0 + && (INTVAL (XEXP (x, 1)) + INTVAL (XEXP (to, 1)) + < GET_MODE_BITSIZE (GET_MODE (x)))) + { + if (!undobuf.storage) + undobuf.storage = (char *) oballoc (0); + return gen_rtx (GET_CODE (x), GET_MODE (x), + XEXP (to, 0), + gen_rtx (CONST_INT, VOIDmode, + INTVAL (XEXP (x, 1)) + + INTVAL (XEXP (to, 1)))); + } + /* (ashift (ashiftrt ) ) + (or, on some machines, (ashift (ashift <-X>) ) instead) + happens if you divide by 2**N and then multiply by 2**N. + It can be replaced by one `and' instruction. + It does not matter whether the shifts are logical or arithmetic. */ + if (GET_CODE (XEXP (x, 1)) == CONST_INT + && INTVAL (XEXP (x, 1)) > 0 + && was_replaced[0] + && (((GET_CODE (to) == LSHIFTRT || GET_CODE (to) == ASHIFTRT) + && GET_CODE (XEXP (to, 1)) == CONST_INT + && INTVAL (XEXP (x, 1)) == INTVAL (XEXP (to, 1))) + || + ((GET_CODE (to) == LSHIFT || GET_CODE (to) == ASHIFT) + && GET_CODE (XEXP (to, 1)) == CONST_INT + && INTVAL (XEXP (x, 1)) == - INTVAL (XEXP (to, 1))))) + { + if (!undobuf.storage) + undobuf.storage = (char *) oballoc (0); + /* The constant in the new `and' is -1 << + but clear out all bits that don't belong in our mode. */ + return gen_rtx (AND, GET_MODE (x), XEXP (to, 0), + gen_rtx (CONST_INT, VOIDmode, + (GET_MODE_MASK (GET_MODE (x)) + & (GET_MODE_MASK (GET_MODE (x)) + << INTVAL (XEXP (x, 1)))))); + } + + } + + return x; +} + +/* This is the AND case of the function subst. */ + +static rtx +simplify_and_const_int (x, to) + rtx x, to; +{ + register rtx varop = XEXP (x, 0); + register int constop = INTVAL (XEXP (x, 1)); + + /* (and (subreg (and ) 0) ) + results from an andsi followed by an andqi, + which happens frequently when storing bit-fields + on something whose result comes from an andsi. */ + if (GET_CODE (varop) == SUBREG + && XEXP (varop, 0) == to + && subreg_lowpart_p (varop) + && GET_CODE (to) == AND + && GET_CODE (XEXP (to, 1)) == CONST_INT + /* Verify that the result of the outer `and' + is not affected by any bits not defined in the inner `and'. + True if the outer mode is narrower, or if the outer constant + masks to zero all the bits that the inner mode doesn't have. */ + && (GET_MODE_SIZE (GET_MODE (x)) < GET_MODE_SIZE (GET_MODE (to)) + || (constop & ~ GET_MODE_MASK (GET_MODE (to))) == 0)) + { + if (!undobuf.storage) + undobuf.storage = (char *) oballoc (0); + return gen_rtx (AND, GET_MODE (x), + gen_lowpart_for_combine (GET_MODE (x), XEXP (to, 0)), + gen_rtx (CONST_INT, VOIDmode, + constop + /* Remember that the bits outside that mode + are not being changed, so the effect + is as if they were all 1. */ + & INTVAL (XEXP (to, 1)))); + } + /* (and:SI (zero_extract:SI ...) ) + results from an andsi following a byte-fetch on risc machines. + When the constant includes all bits extracted, eliminate the `and'. */ + if (GET_CODE (varop) == ZERO_EXTRACT + && GET_CODE (XEXP (varop, 1)) == CONST_INT + /* The `and' must not clear any bits that the extract can give. */ + && (~ constop & ((1 << INTVAL (XEXP (varop, 1))) - 1)) == 0) + return varop; + /* (and (zero_extend ) ) + often results from storing in a bit-field something + that was calculated as a short. Replace with a single `and' + in whose constant all bits not in 's mode are zero. */ + if (varop == to + && GET_CODE (to) == ZERO_EXTEND + && FAKE_EXTEND_SAFE_P (GET_MODE (x), XEXP (to, 0))) + { + if (!undobuf.storage) + undobuf.storage = (char *) oballoc (0); + return gen_rtx (AND, GET_MODE (x), + /* This is a perverse SUBREG, wider than its base. */ + gen_lowpart_for_combine (GET_MODE (x), XEXP (to, 0)), + gen_rtx (CONST_INT, VOIDmode, + constop & GET_MODE_MASK (GET_MODE (XEXP (to, 0))))); + } + /* (and (sign_extend ) ) + can be replaced with (and (subreg ) ) + if is narrower than 's mode, + or with (zero_extend ) if is a mask for that mode. */ + if (varop == to + && GET_CODE (to) == SIGN_EXTEND + && ((unsigned) constop <= GET_MODE_MASK (GET_MODE (XEXP (to, 0)))) + && FAKE_EXTEND_SAFE_P (GET_MODE (x), XEXP (to, 0))) + { + if (!undobuf.storage) + undobuf.storage = (char *) oballoc (0); + if (constop == GET_MODE_MASK (GET_MODE (XEXP (to, 0)))) + return gen_rtx (ZERO_EXTEND, GET_MODE (x), XEXP (to, 0)); + return gen_rtx (AND, GET_MODE (x), + /* This is a perverse SUBREG, wider than its base. */ + gen_lowpart_for_combine (GET_MODE (x), XEXP (to, 0)), + XEXP (x, 1)); + } + /* (and (and ) ) + comes from two and instructions in a row. */ + if (varop == to + && GET_CODE (to) == AND + && GET_CODE (XEXP (to, 1)) == CONST_INT) + { + if (!undobuf.storage) + undobuf.storage = (char *) oballoc (0); + return gen_rtx (AND, GET_MODE (x), + XEXP (to, 0), + gen_rtx (CONST_INT, VOIDmode, + constop + & INTVAL (XEXP (to, 1)))); + } + /* (and (ashiftrt (ashift FOO N) N) CONST) + may be simplified to (and FOO CONST) if CONST masks off the bits + changed by the two shifts. */ + if (GET_CODE (varop) == ASHIFTRT + && GET_CODE (XEXP (varop, 1)) == CONST_INT + && XEXP (varop, 0) == to + && GET_CODE (to) == ASHIFT + && GET_CODE (XEXP (to, 1)) == CONST_INT + && INTVAL (XEXP (varop, 1)) == INTVAL (XEXP (to, 1)) + && ((unsigned) constop >> INTVAL (XEXP (varop, 1))) == 0) + { + if (!undobuf.storage) + undobuf.storage = (char *) oballoc (0); + /* If CONST is a mask for the low byte, + change this into a zero-extend instruction + from just the low byte of FOO. */ + if (constop == GET_MODE_MASK (QImode)) + { + rtx temp = gen_lowpart_for_combine (QImode, XEXP (to, 0)); + if (GET_CODE (temp) != CLOBBER) + return gen_rtx (ZERO_EXTEND, GET_MODE (x), temp); + } + return gen_rtx (AND, GET_MODE (x), + XEXP (to, 0), XEXP (x, 1)); + } + /* (and (ashiftrt (zero_extend FOO) N) CONST) + may be simplified to (and (ashiftrt (subreg FOO) N) CONST) + if CONST masks off the bits changed by extension. */ + if ((GET_CODE (varop) == ASHIFTRT || GET_CODE (varop) == LSHIFTRT) + && GET_CODE (XEXP (varop, 1)) == CONST_INT + && XEXP (varop, 0) == to + && (GET_CODE (to) == ZERO_EXTEND || GET_CODE (to) == SIGN_EXTEND) + /* Verify the and discards all the extended bits. */ + && (((unsigned) constop << INTVAL (XEXP (varop, 1))) + >> GET_MODE_BITSIZE (GET_MODE (XEXP (to, 0)))) == 0 + && FAKE_EXTEND_SAFE_P (GET_MODE (x), XEXP (to, 0))) + { + if (!undobuf.storage) + undobuf.storage = (char *) oballoc (0); + SUBST (XEXP (varop, 0), + gen_lowpart_for_combine (GET_MODE (x), XEXP (to, 0))); + return x; + } + /* (and x const) may be converted to (zero_extend (subreg x 0)). */ + if (constop == GET_MODE_MASK (QImode) + && GET_CODE (varop) == REG) + { + if (!undobuf.storage) + undobuf.storage = (char *) oballoc (0); + return gen_rtx (ZERO_EXTEND, GET_MODE (x), + gen_rtx (SUBREG, QImode, varop, 0)); + } + if (constop == GET_MODE_MASK (HImode) + && GET_CODE (varop) == REG) + { + if (!undobuf.storage) + undobuf.storage = (char *) oballoc (0); + return gen_rtx (ZERO_EXTEND, GET_MODE (x), + gen_rtx (SUBREG, HImode, varop, 0)); + } + /* No simplification applies. */ + return 0; +} + +/* Like gen_lowpart but for use by combine. In combine it is not possible + to create any new pseudoregs. However, it is safe to create + invalid memory addresses, because combine will try to recognize + them and all they will do is make the combine attempt fail. + + If for some reason this cannot do its job, an rtx + (clobber (const_int 0)) is returned. + An insn containing that will not be recognized. */ + +#undef gen_lowpart + +static rtx +gen_lowpart_for_combine (mode, x) + enum machine_mode mode; + register rtx x; +{ + if (GET_CODE (x) == SUBREG || GET_CODE (x) == REG) + return gen_lowpart (mode, x); + if (GET_MODE (x) == mode) + return gen_rtx (CLOBBER, VOIDmode, const0_rtx); + if (GET_CODE (x) == MEM) + { + register int offset = 0; + + /* Refuse to work on a volatile memory ref. */ + if (MEM_VOLATILE_P (x)) + return gen_rtx (CLOBBER, VOIDmode, 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); + +#ifdef WORDS_BIG_ENDIAN + offset = (max (GET_MODE_SIZE (GET_MODE (x)), UNITS_PER_WORD) + - max (GET_MODE_SIZE (mode), UNITS_PER_WORD)); +#endif +#ifdef BYTES_BIG_ENDIAN + /* Adjust the address so that the address-after-the-data + is unchanged. */ + offset -= (min (UNITS_PER_WORD, GET_MODE_SIZE (mode)) + - min (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (x)))); +#endif + return gen_rtx (MEM, mode, plus_constant (XEXP (x, 0), + offset)); + } + else + return gen_rtx (CLOBBER, VOIDmode, const0_rtx); +} + +/* After substitution, if the resulting pattern looks like + (set (cc0) (and ...)) or (set (cc0) (lshiftrt ...)), + this function is called to simplify the + pattern into a bit-field operation if possible. */ + +static void +simplify_set_cc0_and (insn) + rtx insn; +{ + register rtx value = XEXP (PATTERN (insn), 1); + register rtx op0 = XEXP (value, 0); + register rtx op1 = XEXP (value, 1); + int offset = 0; + rtx var = 0; + rtx bitnum = 0; + int temp; + int unit; + rtx newpat; + + if (GET_CODE (value) == AND) + { + op0 = XEXP (value, 0); + op1 = XEXP (value, 1); + } + else if (GET_CODE (value) == LSHIFTRT) + { + /* If there is no AND, but there is a shift that discards + all but the sign bit, we can pretend that the shift result + is ANDed with 1. Otherwise we cannot handle just a shift. */ + if (GET_CODE (XEXP (value, 1)) == CONST_INT + && (INTVAL (XEXP (value, 1)) + == GET_MODE_BITSIZE (GET_MODE (value)) - 1)) + { + op0 = value; + op1 = const1_rtx; + } + else + return; + } + else + abort (); + + /* Look for a constant power of 2 or a shifted 1 + on either side of the AND. Set VAR to the other side. + Set BITNUM to the shift count of the 1 (as an rtx). + Or, if bit number is constant, set OFFSET to the bit number. */ + + switch (GET_CODE (op0)) + { + case CONST_INT: + temp = exact_log2 (INTVAL (op0)); + if (temp < 0) + return; + offset = temp; + var = op1; + break; + + case ASHIFT: + case LSHIFT: + if (XEXP (op0, 0) == const1_rtx) + { + bitnum = XEXP (op0, 1); + var = op1; + } + } + if (var == 0) + switch (GET_CODE (op1)) + { + case CONST_INT: + temp = exact_log2 (INTVAL (op1)); + if (temp < 0) + return; + offset = temp; + var = op0; + break; + + case ASHIFT: + case LSHIFT: + if (XEXP (op1, 0) == const1_rtx) + { + bitnum = XEXP (op1, 1); + var = op0; + } + } + + /* If VAR is 0, we didn't find something recognizable. */ + if (var == 0) + return; + + if (!undobuf.storage) + undobuf.storage = (char *) oballoc (0); + + /* If the bit position is currently exactly 0, + extract a right-shift from the variable portion. */ + if (offset == 0 + && (GET_CODE (var) == ASHIFTRT || GET_CODE (var) == LSHIFTRT)) + { + bitnum = XEXP (var, 1); + var = XEXP (var, 0); + } + + if (GET_CODE (var) == SUBREG && SUBREG_WORD (var) == 0) + var = SUBREG_REG (var); + + /* Note that BITNUM and OFFSET are always little-endian thru here + even on a big-endian machine. */ + +#ifdef BITS_BIG_ENDIAN + unit = GET_MODE_BITSIZE (GET_MODE (var)) - 1; + + if (bitnum != 0) + bitnum = gen_rtx (MINUS, SImode, + gen_rtx (CONST_INT, VOIDmode, unit), bitnum); + else + offset = unit - offset; +#endif + + if (bitnum == 0) + bitnum = gen_rtx (CONST_INT, VOIDmode, offset); + + newpat = gen_rtx (SET, VOIDmode, cc0_rtx, + gen_rtx (ZERO_EXTRACT, VOIDmode, var, const1_rtx, bitnum)); + if (recog (newpat, insn) >= 0) + { + if (undobuf.num_undo < MAX_UNDO) + { + undobuf.undo[undobuf.num_undo].where = &XEXP (PATTERN (insn), 1); + undobuf.undo[undobuf.num_undo].old_contents = value; + XEXP (PATTERN (insn), 1) = XEXP (newpat, 1); + } + undobuf.num_undo++; + } +} + +/* Update the records of when each REG was most recently set or killed + for the things done by INSN. This is the last thing done in processing + INSN in the combiner loop. + + We update reg_last_set, reg_last_death, and also the similar information + mem_last_set (which insn most recently modified memory) + and last_call_cuid (which insn was the most recent subroutine call). */ + +static void +record_dead_and_set_regs (insn) + rtx insn; +{ + register rtx link; + for (link = REG_NOTES (insn); link; link = XEXP (link, 1)) + { + if (REG_NOTE_KIND (link) == REG_DEAD) + reg_last_death[REGNO (XEXP (link, 0))] = insn; + else if (REG_NOTE_KIND (link) == REG_INC) + reg_last_set[REGNO (XEXP (link, 0))] = insn; + } + + if (GET_CODE (insn) == CALL_INSN) + last_call_cuid = mem_last_set = INSN_CUID (insn); + + if (GET_CODE (PATTERN (insn)) == PARALLEL) + { + register int i; + for (i = XVECLEN (PATTERN (insn), 0) - 1; i >= 0; i--) + { + register rtx elt = XVECEXP (PATTERN (insn), 0, i); + register enum rtx_code code = GET_CODE (elt); + if (code == SET || code == CLOBBER) + { + rtx dest = XEXP (elt, 0); + while (GET_CODE (dest) == SUBREG + || GET_CODE (dest) == STRICT_LOW_PART + || GET_CODE (dest) == SIGN_EXTRACT + || GET_CODE (dest) == ZERO_EXTRACT) + dest = XEXP (dest, 0); + + if (GET_CODE (dest) == REG) + reg_last_set[REGNO (dest)] = insn; + else if (GET_CODE (dest) == MEM) + mem_last_set = INSN_CUID (insn); + } + } + } + else if (GET_CODE (PATTERN (insn)) == SET + || GET_CODE (PATTERN (insn)) == CLOBBER) + { + register rtx dest = XEXP (PATTERN (insn), 0); + + while (GET_CODE (dest) == SUBREG + || GET_CODE (dest) == STRICT_LOW_PART + || GET_CODE (dest) == SIGN_EXTRACT + || GET_CODE (dest) == ZERO_EXTRACT) + dest = XEXP (dest, 0); + + if (GET_CODE (dest) == REG) + reg_last_set[REGNO (dest)] = insn; + else if (GET_CODE (dest) == MEM) + mem_last_set = INSN_CUID (insn); + } +} + +/* Return nonzero if expression X refers to a REG or to memory + that is set in an instruction more recent than FROM_CUID. */ + +static int +use_crosses_set_p (x, from_cuid) + register rtx x; + int from_cuid; +{ + register char *fmt; + register int i; + register enum rtx_code code = GET_CODE (x); + + if (code == REG) + { + register int regno = REGNO (x); +#ifdef PUSH_ROUNDING + /* Don't allow uses of the stack pointer to be moved, + because we don't know whether the move crosses a push insn. */ + if (regno == STACK_POINTER_REGNUM) + return 1; +#endif + return (reg_last_set[regno] + && INSN_CUID (reg_last_set[regno]) > from_cuid); + } + + if (code == MEM && mem_last_set > from_cuid) + return 1; + + fmt = GET_RTX_FORMAT (code); + + for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) + { + if (fmt[i] == 'E') + { + register int j; + for (j = XVECLEN (x, i) - 1; j >= 0; j--) + if (use_crosses_set_p (XVECEXP (x, i, j), from_cuid)) + return 1; + } + else if (fmt[i] == 'e' + && use_crosses_set_p (XEXP (x, i), from_cuid)) + return 1; + } + return 0; +} + +/* Return nonzero if reg REGNO is marked as dying in INSN. */ + +int +regno_dead_p (regno, insn) + int regno; + rtx insn; +{ + register rtx link; + + for (link = REG_NOTES (insn); link; link = XEXP (link, 1)) + if ((REG_NOTE_KIND (link) == REG_DEAD + || REG_NOTE_KIND (link) == REG_INC) + && REGNO (XEXP (link, 0)) == regno) + return 1; + + return 0; +} + +/* Return nonzero if J is the first insn following I, + not counting labels, line numbers, etc. + We assume that J follows I. */ + +static int +adjacent_insns_p (i, j) + rtx i, j; +{ + register rtx insn; + for (insn = NEXT_INSN (i); insn != j; insn = NEXT_INSN (insn)) + if (GET_CODE (insn) == INSN + || GET_CODE (insn) == CALL_INSN + || GET_CODE (insn) == JUMP_INSN) + return 0; + return 1; +} + +/* Check that X is an insn-body for an `asm' with operands + and that the operands mentioned in it are legitimate. */ + +static int +check_asm_operands (x) + rtx x; +{ + int noperands = asm_noperands (x); + rtx *operands; + int i; + + if (noperands < 0) + return 0; + if (noperands == 0) + return 1; + + operands = (rtx *) alloca (noperands * sizeof (rtx)); + decode_asm_operands (x, operands, 0, 0, 0); + + for (i = 0; i < noperands; i++) + if (!general_operand (operands[i], VOIDmode)) + return 0; + + return 1; +} + +/* Concatenate the list of logical links of OINSN + into INSN's list of logical links. + Modifies OINSN destructively. + + If ALL_LINKS is nonzero, move all the links that OINSN has. + Otherwise, move only those that point to insns that set regs + that die in the insn OINSN. + Other links are clobbered so that they are no longer effective. */ + +static void +add_links (insn, oinsn, all_links) + rtx insn, oinsn; + int all_links; +{ + register rtx links = LOG_LINKS (oinsn); + if (! all_links) + { + rtx tail; + for (tail = links; tail; tail = XEXP (tail, 1)) + { + rtx target = XEXP (tail, 0); + if (GET_CODE (target) != INSN + || GET_CODE (PATTERN (target)) != SET + || GET_CODE (SET_DEST (PATTERN (target))) != REG + || ! dead_or_set_p (oinsn, SET_DEST (PATTERN (target)))) + /* OINSN is going to become a NOTE + so a link pointing there will have no effect. */ + XEXP (tail, 0) = oinsn; + } + } + if (LOG_LINKS (insn) == 0) + LOG_LINKS (insn) = links; + else + { + register rtx next, prev = LOG_LINKS (insn); + while (next = XEXP (prev, 1)) + prev = next; + XEXP (prev, 1) = links; + } +} + +/* Delete any LOG_LINKS of INSN which point at OINSN. */ + +static void +remove_links (insn, oinsn) + rtx insn, oinsn; +{ + register rtx next = LOG_LINKS (insn), prev = 0; + while (next) + { + if (XEXP (next, 0) == oinsn) + { + if (prev) + XEXP (prev, 1) = XEXP (next, 1); + else + LOG_LINKS (insn) = XEXP (next, 1); + } + else + prev = next; + next = XEXP (next, 1); + } +} + +/* Concatenate the any elements of the list of reg-notes INCS + which are of type REG_INC + into INSN's list of reg-notes. */ + +static void +add_incs (insn, incs) + rtx insn, incs; +{ + register rtx tail; + + for (tail = incs; tail; tail = XEXP (tail, 1)) + if (REG_NOTE_KIND (tail) == REG_INC) + REG_NOTES (insn) + = gen_rtx (EXPR_LIST, REG_INC, XEXP (tail, 0), REG_NOTES (insn)); +} + +/* Remove register number REGNO from the dead registers list of INSN. */ + +void +remove_death (regno, insn) + int regno; + rtx insn; +{ + register rtx link, next; + while ((link = REG_NOTES (insn)) + && REG_NOTE_KIND (link) == REG_DEAD + && REGNO (XEXP (link, 0)) == regno) + REG_NOTES (insn) = XEXP (link, 1); + + if (link) + while (next = XEXP (link, 1)) + { + if (REG_NOTE_KIND (next) == REG_DEAD + && REGNO (XEXP (next, 0)) == regno) + XEXP (link, 1) = XEXP (next, 1); + else + link = next; + } +} + +/* For each register (hardware or pseudo) used within expression X, + if its death is in an instruction with cuid + between FROM_CUID (inclusive) and TO_INSN (exclusive), + mark it as dead in TO_INSN instead. + + This is done when X is being merged by combination into TO_INSN. */ + +static void +move_deaths (x, from_cuid, to_insn) + rtx x; + int from_cuid; + rtx to_insn; +{ + register char *fmt; + register int len, i; + register enum rtx_code code = GET_CODE (x); + + if (code == REG) + { + register rtx where_dead = reg_last_death[REGNO (x)]; + + if (where_dead && INSN_CUID (where_dead) >= from_cuid + && INSN_CUID (where_dead) < INSN_CUID (to_insn)) + { + remove_death (REGNO (x), reg_last_death[REGNO (x)]); + if (! dead_or_set_p (to_insn, x)) + REG_NOTES (to_insn) + = gen_rtx (EXPR_LIST, REG_DEAD, x, REG_NOTES (to_insn)); + } + return; + } + + len = GET_RTX_LENGTH (code); + fmt = GET_RTX_FORMAT (code); + + for (i = 0; i < len; i++) + { + if (fmt[i] == 'E') + { + register int j; + for (j = XVECLEN (x, i) - 1; j >= 0; j--) + move_deaths (XVECEXP (x, i, j), from_cuid, to_insn); + } + else if (fmt[i] == 'e') + move_deaths (XEXP (x, i), from_cuid, to_insn); + } +} + +/* Like move_deaths, but deaths are moving both forward + (from FROM_CUID to TO_INSN), and backwards + (from FROM_INSN to TO_INSN). This is what happens + when an insn is removed after applying the distributive law. */ + +static void +move_deaths_2 (x, from_cuid, from_insn, to_insn) + rtx x; + int from_cuid; + rtx from_insn, to_insn; +{ + register char *fmt; + register int len, i; + register enum rtx_code code = GET_CODE (x); + + if (code == REG) + { + register rtx where_dead = reg_last_death[REGNO (x)]; + + if (where_dead && INSN_CUID (where_dead) >= from_cuid + && INSN_CUID (where_dead) < INSN_CUID (to_insn)) + { + remove_death (REGNO (x), reg_last_death[REGNO (x)]); + if (! dead_or_set_p (to_insn, x)) + REG_NOTES (to_insn) + = gen_rtx (EXPR_LIST, REG_DEAD, x, REG_NOTES (to_insn)); + } + /* Can't use where_dead for from_insn because it has + not been computed yet. */ + else if (dead_or_set_p (from_insn, x)) + { + remove_death (REGNO (x), from_insn); + if (! dead_or_set_p (to_insn, x)) + REG_NOTES (to_insn) + = gen_rtx (EXPR_LIST, REG_DEAD, x, REG_NOTES (to_insn)); + } + return; + } + + len = GET_RTX_LENGTH (code); + fmt = GET_RTX_FORMAT (code); + + for (i = 0; i < len; i++) + { + if (fmt[i] == 'E') + { + register int j; + for (j = XVECLEN (x, i) - 1; j >= 0; j--) + move_deaths_2 (XVECEXP (x, i, j), from_cuid, from_insn, to_insn); + } + else if (fmt[i] == 'e') + move_deaths_2 (XEXP (x, i), from_cuid, from_insn, to_insn); + } +} + +/* The distrib combiner rewrites groups of insns so that optimizations + can be more easily recognized. The front-end does not know how to + group certain kinds of operations for efficient execution, and the + resulting code can be quite poor. For example, on a machine without + bitfield instructions, bitfield references look like + + (and (lshiftrt ... n) m) + + When combining two bitfield operations, such as with ||, this can + yield code like + + (set z + (or (and (lshiftrt x n) 1) + (and (lshiftrt y n) 1))) + + which can be more efficiently executed as + + (set z + (lshiftrt (and (or x y) + (1 << m)) n)) + + From there, the combiner attempts to rewrite the insns, + keeping flow information accurate for later passes, + and reducing the total number of insns executed. + + This function returns the point at which we should try + looking for more simplifications. This will be before + INSN if the call succeeds. We do not need to fear + infinite loops, since this function is guaranteed to + eliminate at least one (non-note) instruction if it returns + successfully. */ + +static rtx +try_distrib (insn, xprev1, xprev2) + rtx insn, xprev1, xprev2; +{ + rtx pat = PATTERN (insn); + rtx prev1, prev2, pat1, pat2, src1, src2; + rtx to_prev, to_insn; + enum rtx_code code; + int insn_code_number, prev_code_number, regno; + rtx new_insn_pat, new_prev_pat; + + distrib_attempts++; + + /* ??? Need to implement a test that PREV2 and PREV1 + are completely independent. Right now their + recognition ability is sufficiently limited that + it should not be necessary, but better safe than sorry. */ + + /* Let PREV1 be the later of the two insns, and PREV2 the earlier. */ + if (INSN_CUID (xprev1) > INSN_CUID (xprev2)) + { + prev1 = xprev1; + prev2 = xprev2; + } + else + { + prev1 = xprev2; + prev2 = xprev1; + } + + pat1 = PATTERN (prev1); + pat2 = PATTERN (prev2); + + /* First, see if INSN, PREV1, and PREV2 have patterns we can expect + to simplify. */ + + if (GET_CODE (pat) != SET + || GET_CODE (pat1) != SET + || GET_CODE (pat2) != SET) + return 0; + + code = GET_CODE (SET_SRC (pat)); + src1 = SET_SRC (pat1); + src2 = SET_SRC (pat2); + + if (GET_CODE (SET_DEST (pat1)) != REG + || GET_CODE (SET_DEST (pat2)) != REG) + return 0; + + switch (code) + { + default: + return 0; + + case IOR: + case AND: + case XOR: + case PLUS: + ; + } + + /* Insns PREV1 and PREV2 must provide the two operands of the arithmetic + that is done in INSN. */ + if (! ((XEXP (SET_SRC (pat), 0) == SET_DEST (pat1) + && XEXP (SET_SRC (pat), 1) == SET_DEST (pat2)) + || + (XEXP (SET_SRC (pat), 0) == SET_DEST (pat2) + && XEXP (SET_SRC (pat), 1) == SET_DEST (pat1)))) + return 0; + + /* They must not be used in any other way in INSN. + In particular, they must not be used in a result memory address. */ + if (reg_mentioned_p (SET_DEST (pat1), SET_DEST (pat)) + || reg_mentioned_p (SET_DEST (pat2), SET_DEST (pat))) + return 0; + + /* Give up if the two operands' modes don't match. */ + if (GET_MODE (src1) != GET_MODE (src2)) + return 0; + + /* PREV1 and PREV2 must compute the same operation. + Actually, there are other cases that could be handled, + but are not implemented. For example: + + (set (reg:SI 94) + (and:SI (reg:SI 73) + (const_int 223))) + + (set (reg:SI 95) + (zero_extend:SI (subreg:QI (reg:SI 91) 0))) + + (set (reg:SI 96) + (ior:SI (reg:SI 94) + (reg:SI 95))) + + In this case, we know that because (reg:SI 94) has + been anded with 223, there is no need to zero_extend + (reg:SI 91), and we could eliminate (reg:SI 95). */ + + if (GET_CODE (src1) != GET_CODE (src2)) + return 0; + + /* The SETs in PREV1 and PREV2 do not need to be kept around. */ + + undobuf.num_undo = 0; + undobuf.storage = 0; + + /* Substitute in the latest insn for the regs set by the earlier ones. */ + subst_insn = insn; + n_occurrences = 0; /* `subst' counts here */ + + switch (GET_CODE (src1)) + { + /* case XOR: Does not distribute through anything! */ + case LSHIFTRT: + case ASHIFTRT: + /* Right-shift can't distribute through addition + since the round-off would happen differently. */ + case AND: + case IOR: + /* Boolean ops don't distribute through addition. */ + if (code == PLUS) + return 0; + goto do_distrib; + + case LSHIFT: + case ASHIFT: + /* Left shifts are multiplication; they distribute through + addition. Also, since they work bitwise, they + distribute through boolean operations. */ +#ifdef NEGATIVE_SHIFT_COUNTS + /* Negative count is really a right-shift. */ + if (NEGATIVE_SHIFT_COUNTS + && code == PLUS + && !(GET_CODE (XEXP (src1, 1)) + == CONST_INT && INTVAL (XEXP (src1, 1)) >= 0)) + return 0; +#endif + goto do_distrib; + + case MULT: + /* Multiplication distributes through addition only. */ + if (code != PLUS) + return 0; + + do_distrib: + if (GET_CODE (XEXP (src1, 1)) != CONST_INT + || GET_CODE (XEXP (src2, 1)) != CONST_INT + || INTVAL (XEXP (src1, 1)) != INTVAL (XEXP (src2, 1))) + return 0; + + /* Give up if we would move a use of a reg across an alteration. + Note this is unnecessarily conservative, since a problem really + happens only if this reg is set *between* PREV2 and PREV1 + But this test is easier. */ + if (use_crosses_set_p (XEXP (src2, 0), INSN_CUID (prev2))) + return 0; + + /* Try changing (+ (* x c) (* y c)) to (* (+ x y) c). */ + to_prev = gen_rtx (code, GET_MODE (src1), + XEXP (src1, 0), XEXP (src2, 0)); + to_insn = gen_rtx (GET_CODE (src1), GET_MODE (src1), SET_DEST (pat1), XEXP (src1, 1)); + break; + + case ZERO_EXTEND: + case SIGN_EXTEND: + /* Extension can't distribute through addition; + the carries could be changed. */ + if (code == PLUS) + return 0; + { + rtx inner1 = XEXP (src1, 0), inner2 = XEXP (src2, 0); + int subreg_needed = 0; + + /* Try changing (& (extend x) (extend y)) to (extend (& x y)). */ + /* But keep extend insns together with their subregs. */ + if (GET_CODE (inner1) == SUBREG) + { + if (SUBREG_WORD (inner1) != 0) + return 0; + else + { + subreg_needed = 1; + inner1 = SUBREG_REG (inner1); + } + } + + if (GET_CODE (inner2) == SUBREG) + { + if (SUBREG_WORD (inner2) != 0) + return 0; + else + { + subreg_needed = 1; + inner2 = SUBREG_REG (inner2); + } + } + + /* Give up if we would move a use of a reg across an alteration. + Note this is unnecessarily conservative, since a problem really + happens only if this reg is set *between* PREV2 and PREV1 + But this test is easier. */ + if (use_crosses_set_p (inner2, INSN_CUID (prev2))) + return 0; + + to_prev = gen_rtx (code, GET_MODE (src1), inner1, inner2); + to_insn = gen_rtx (GET_CODE (src1), GET_MODE (src1), + subreg_needed + ? gen_rtx (SUBREG, GET_MODE (XEXP (src1, 0)), + SET_DEST (pat1), 0) + : SET_DEST (pat1)); + } + break; + + default: + return 0; + } + + /* Are the results of this "substitution" a valid instruction? */ + + new_insn_pat = subst (PATTERN (insn), SET_SRC (PATTERN (insn)), to_insn); + distrib_merges_1++; + + insn_code_number = recog (new_insn_pat, insn); + if (insn_code_number < 0) + { + undo_all (); + return 0; + } + + subst_insn = prev1; + new_prev_pat = subst (pat1, src1, to_prev); + distrib_merges_2++; + + prev_code_number = recog (new_prev_pat, prev1); + if (prev_code_number < 0) + { + undo_all (); + return 0; + } + + /* Everything worked; install the new patterns. */ + INSN_CODE (insn) = insn_code_number; + PATTERN (insn) = new_insn_pat; + + INSN_CODE (prev1) = prev_code_number; + PATTERN (prev1) = new_prev_pat; + + /* Need to change LOG_LINKS around...PREV1 now gets + whatever flowed into PREV2. PREV2 is going to + become a NOTE, so we clear out its LOG_LINKS. */ + remove_links (insn, prev2); + add_links (prev1, prev2, adjacent_insns_p (prev2, prev1)); + + /* Registers which died in PREV2 now die in PREV1. + Also, registers born in PREV2 dying in INSN now die in PREV1. */ + move_deaths_2 (src2, INSN_CUID (prev2), insn, prev1); + + regno = REGNO (SET_DEST (pat2)); + + reg_n_sets[regno]--; + if (reg_n_sets[regno] == 0 + && ! (basic_block_live_at_start[0][regno / HOST_BITS_PER_INT] + & (1 << (regno % HOST_BITS_PER_INT)))) + reg_n_refs[regno] = 0; + remove_death (regno, insn); + + PUT_CODE (prev2, NOTE); + NOTE_LINE_NUMBER (prev2) = NOTE_INSN_DELETED; + NOTE_SOURCE_FILE (prev2) = 0; + + distrib_successes++; + return prev1; +} + +void +dump_combine_stats (file) + FILE *file; +{ + fprintf + (file, + ";; Combiner statistics: %d attempts, %d substitutions (%d requiring new space),\n;; %d successes.\n\n", + combine_attempts, combine_merges, combine_extras, combine_successes); + fprintf + (file, + ";; Distributer statistics: %d attempts, %d:%d substitutions,\n;; %d successes.\n\n", + distrib_attempts, distrib_merges_1, + distrib_merges_2, distrib_successes); +} + +void +dump_combine_total_stats (file) + FILE *file; +{ + fprintf + (file, + "\n;; Combiner totals: %d attempts, %d substitutions (%d requiring new space),\n;; %d successes.\n", + total_attempts, total_merges, total_extras, total_successes); + fprintf + (file, + "\n;; Distributer totals: %d attempts, %d:%d substitutions,\n;; %d successes.\n", + total_distrib_attempts, total_distrib_merges_1, + total_distrib_merges_2, total_distrib_successes); +} diff --git a/gcc-1.40/conditions.h b/gcc-1.40/conditions.h new file mode 100644 index 0000000..030c455 --- /dev/null +++ b/gcc-1.40/conditions.h @@ -0,0 +1,99 @@ +/* Definitions for condition code handling in final.c and output routines. + Copyright (C) 1987 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 1, 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 variable cc_status says how to interpret the condition code. + It is set by output routines for an instruction that sets the cc's + and examined by output routines for jump instructions. + + cc_status contains two components named `value1' and `value2' + that record two equivalent expressions for the values that the + condition codes were set from. (Either or both may be null if + there is no useful expression to record.) These fields are + used for eliminating redundant test and compare instructions + in the cases where the condition codes were already set by the + previous instruction. + + cc_status.flags contains flags which say that the condition codes + were set in a nonstandard manner. The output of jump instructions + uses these flags to compensate and produce the standard result + with the nonstandard condition codes. Standard flags are defined here. + The tm- file can also define other machine-dependent flags. + + cc_status also contains a machine-dependent component `mdep' + whose type, `CC_STATUS_MDEP', may be defined as a macro in the + tm- file. */ + +#ifndef CC_STATUS_MDEP +#define CC_STATUS_MDEP int +#endif + +#ifndef CC_STATUS_MDEP_INIT +#define CC_STATUS_MDEP_INIT 0 +#endif + +typedef struct {int flags; rtx value1, value2; CC_STATUS_MDEP mdep;} CC_STATUS; + +/* While outputting an insn as assembler code, + this is the status BEFORE that insn. */ +extern CC_STATUS cc_prev_status; + +/* While outputting an insn as assembler code, + this is being altered to the status AFTER that insn. */ +extern CC_STATUS cc_status; + +/* These are the machine-independent flags: */ + +/* Set if the sign of the cc value is inverted: + output a following jump-if-less as a jump-if-greater, etc. */ +#define CC_REVERSED 1 + +/* This bit means that the current setting of the N bit is bogus + and conditional jumps should use the Z bit in its place. + This state obtains when an extraction of a signed single-bit field + or an arithmetic shift right of a byte by 7 bits + is turned into a btst, because btst does not set the N bit. */ +#define CC_NOT_POSITIVE 2 + +/* This bit means that the current setting of the N bit is bogus + and conditional jumps should pretend that the N bit is clear. + Used after extraction of an unsigned bit + or logical shift right of a byte by 7 bits is turned into a btst. + The btst does not alter the N bit, but the result of that shift + or extract is never negative. */ +#define CC_NOT_NEGATIVE 4 + +/* This bit means that the current setting of the overflow flag + is bogus and conditional jumps should pretend there is no overflow. */ +#define CC_NO_OVERFLOW 010 + +/* This bit means that what ought to be in the Z bit + should be tested as the complement of the N bit. */ +#define CC_Z_IN_NOT_N 020 + +/* This bit means that what ought to be in the Z bit + should be tested as the N bit. */ +#define CC_Z_IN_N 040 + +/* This is how to initialize the variable cc_status. + final does this at appropriate moments. */ + +#define CC_STATUS_INIT \ + (cc_status.flags = 0, cc_status.value1 = 0, cc_status.value2 = 0, \ + CC_STATUS_MDEP_INIT) diff --git a/gcc-1.40/config-gcc.com b/gcc-1.40/config-gcc.com new file mode 100644 index 0000000..f8102f8 --- /dev/null +++ b/gcc-1.40/config-gcc.com @@ -0,0 +1,26 @@ +$ ! +$ ! Set up to compile GCC on VMS +$ ! +$ echo = "write sys$output" +$ ! +$ if f$search("config.h") .nes. "" then delete config.h.* +$ copy [.config]xm-vms.h []config.h +$ echo "Linked `config.h' to `[.config]xm-vms.h'. +$ ! +$ if f$search("tm.h") .nes. "" then delete tm.h.* +$ copy [.config]tm-vms.h []tm.h +$ echo "Linked `tm.h' to `[.config]tm-vms.h'. +$ ! +$ if f$search("md.") .nes. "" then delete md..* +$ copy [.config]vax.md []md. +$ echo "Linked `md' to `[.config]vax.md'. +$ ! +$ if f$search("aux-output.c") .nes. "" then delete aux-output.c.* +$ copy [.config]out-vax.c []aux-output.c +$ echo "Linked `aux-output.c' to `[.config]out-vax.c'. +$ ! +$ if f$search("config.status") .nes. "" then delete config.status.* +$ open/write file config.status +$ write file "Links are now set up for use with a vax running VMS." +$ close file +$ type config.status diff --git a/gcc-1.40/config.gcc b/gcc-1.40/config.gcc new file mode 100755 index 0000000..8e8a2ce --- /dev/null +++ b/gcc-1.40/config.gcc @@ -0,0 +1,418 @@ +#!/bin/sh +# Configuration script for GNU CC +# Copyright (C) 1988 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 1, 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. + +# +# Shell script to create proper links to machine-dependent files in +# preparation for compiling gcc. +# +# Usage: config.gcc [vint] [-srcdir=DIR] machine +# +# If config.gcc succeeds, it leaves its status in config.status. +# If config.gcc fails after disturbing the status quo, +# config.status is removed. +# + +progname=$0 + +remove=rm +hard_link=ln +symbolic_link='ln -s' + +#for Test +#remove="echo rm" +#hard_link="echo ln" +#symbolic_link="echo ln -s" + +for arg in $*; +do + case $arg in + -srcdir=*) + srcdir=`echo $arg | sed s/-srcdir=//` + ;; + -vint) + vint=on + ;; + *) + machine=$arg + ;; + esac +done + +# Find the source files, if location was not specified. +if [ x$srcdir = x ] +then + srcdirdefaulted=1 + srcdir=. + if [ ! -r tree.c ] + then + srcdir=.. + fi +fi + +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 + +if [ x$machine != x ]; +then + case $machine in + vax) # for vaxen running bsd + ;; + ultrix) # for vaxen running ultrix + cpu_type=vax + ;; + tahoe) # for tahoe's running bsd + ;; + harris) # for harris tahoe, using COFF. + cpu_type=tahoe + ;; + vms) # for vaxen running VMS + cpu_type=vax + configuration_file=xm-${machine}.h + target_machine=tm-${machine}.h + ;; + vax-sysv | vaxv) # for vaxen running system V + cpu_type=vax + configuration_file=xm-vaxv.h + target_machine=tm-vaxv.h + ;; + sequent-i386) # for Intel 80386's on Sequent Symmetry + cpu_type=i386 + configuration_file=xm-i386.h + target_machine=tm-seq386.h + ;; + i386-mach) + cpu_type=i386 + configuration_file=xm-i386.h + target_machine=tm-i386gas.h + ;; + i386-sysv | i386v) # for Intel 80386's running system V + machine=i386v + cpu_type=i386 + configuration_file=xm-${machine}.h + ;; + i386-sysv4 | i386v4) # for Intel 80386's running system V.4 + machine=i386v4 + cpu_type=i386 + configuration_file=xm-i386v.h + ;; + i386-sysv-gas | i386g) + cpu_type=i386 + configuration_file=xm-i386v.h + target_machine=tm-i386vgas.h + ;; + i386-sco) # for Intel 80386's running SCO system + machine=i386sco + cpu_type=i386 + configuration_file=xm-i386v.h + ;; + i386-esix) # for Intel 80386's running ESIX system + machine=i386esix + cpu_type=i386 + configuration_file=xm-i386v.h + ;; + i386-isc) # for Intel 80386's running ISC + machine=i386isc + cpu_type=i386 + configuration_file=xm-i386v.h + ;; + i386-aix | ps2-aix | aix386 | ps2aix ) # for IBM PS/2 running AIX + machine=aix386 + cpu_type=i386 + configuration_file=xm-${machine}.h + ;; + i860) + ;; + i860-gas) + target_machine=tm-i860g.h + ;; + next ) + cpu_type=m68k + target_machine=tm-next.h + ;; + sun4-os3 | sun-4-os3) + cpu_type=sparc + target_machine=tm-sun4os3.h + ;; + sun3-os3 | sun-3-os3) + cpu_type=m68k + target_machine=tm-sun3os3.h + ;; + sun3-nfp-os3 | sun-3-nfp-os3) + cpu_type=m68k + target_machine=tm-sun3os3nf.h + ;; + sun3-mach) + cpu_type=m68k + target_machine=tm-sun3mach.h + ;; + sun2 | sun-2 | sun2-os3 | sun-2-os3) + cpu_type=m68k + target_machine=tm-sun2.h + ;; + sun2-os4 | sun-2-os4) + cpu_type=m68k + target_machine=tm-sun2os4.h + ;; + sun386 | sun386i | roadrunner) + cpu_type=i386 + configuration_file=xm-sun386i.h + target_machine=tm-sun386i.h + ;; + sun4 | sun-4 | sun4-os4 | sun-4-os4) + cpu_type=sparc + target_machine=tm-sparc.h + ;; + sun3 | sun-3 | sun3-os4 | sun-3-os4) + cpu_type=m68k + target_machine=tm-sun3.h + ;; + sun3-nfp | sun-3-nfp | sun3-nfp-os4 | sun-3-nfp-os4) + cpu_type=m68k + target_machine=tm-sun3-nfp.h + ;; + sun2-os4 |sun-2-os4) + cpu_type=m68k + target_machine=tm-sun2.h + ;; + hp9k320) # HP 9000 series 300 with gcc alone + cpu_type=m68k + configuration_file=xm-hp9k320.h + ;; + hp9k320-old) # HP 9000 series 300 with gcc alone + cpu_type=m68k + target_machine=tm-hp9k32old.h + configuration_file=xm-hp9k320.h + ;; + hp9k320-gas | hp9k320g) # with gnu as, ld and gdb + cpu_type=m68k + configuration_file=xm-hp9k320.h + target_machine=tm-hp9k320g.h + ;; + hp9k320-bsd) # HP 9000/3xx running Berkeley Unix + cpu_type=m68k + target_machine=tm-hp9k3bsd.h + ;; + hp9k200-bsd) # HP 9000/2xx running Berkeley Unix + cpu_type=m68k + target_machine=tm-hp9k2bsd.h + ;; + isi68) + cpu_type=m68k + ;; + isi68-nfp) + cpu_type=m68k + ;; + news | news800) + configuration_file=xm-m68k.h + target_machine=tm-news.h + cpu_type=m68k + ;; + news-gas | news-g) + configuration_file=xm-m68k.h + target_machine=tm-newsgas.h + cpu_type=m68k + ;; + altos | altos3068) # Altos 3068 with gnu as, ld and gdb + cpu_type=m68k + configuration_file=xm-altos3068.h + target_machine=tm-altos3068.h + ;; + 3b1) + cpu_type=m68k + configuration_file=xm-${machine}.h + ;; + 3b1g | 3b1-gas) + machine=3b1g + cpu_type=m68k + configuration_file=xm-3b1.h + ;; + delta68k | motorola-3300 | delta) + cpu_type=m68k + configuration_file=xm-delta68k.h + target_machine=tm-delta68k.h + ;; + sequent-ns32k | sequent) + machine=sequent + cpu_type=ns32k + ;; + encore) + cpu_type=ns32k + ;; + genix) + target_machine=tm-genix.h + machine=ns32k + cpu_type=ns32k + configuration_file=xm-genix.h + ;; + 88000) + cpu_type=m88k + target_machine=tm-${cpu_type}.h + ;; + alliant) # Alliant FX/8 + ;; + convex-c1) # Convex C1 + if [ -r /usr/include/stdlib.h ] + then + target_machine=tm-convex1.h + else + target_machine=tm-conv1os7.h + fi + cpu_type=convex + ;; + convex-c2) # Convex C2 + if [ -r /usr/include/stdlib.h ] + then + target_machine=tm-convex2.h + else + target_machine=tm-conv2os7.h + fi + cpu_type=convex + ;; + iris) # Mostly like a MIPS. + cpu_type=mips + target_machine=tm-iris.h + configuration_file=xm-iris.h + ;; + mips) # Default MIPS environment + ;; + mips-sysv) # SYSV variant of MIPS system. + cpu_type=mips + target_machine=tm-mips-sysv.h + configuration_file=xm-umips.h + ;; + mips-bsd43) # BSD 4.3 variant of MIPS system. + cpu_type=mips + target_machine=tm-mips-bsd.h + ;; + mips-news | news-3600 | risc-news) # Sony NEWS 3600 or risc/news. + cpu_type=mips + target_machine=tm-mips-news.h + ;; + dec-3100 | decstation) # Decstation or pmax. + cpu_type=mips + target_machine=tm-decstatn.h + ;; + apollo68) + cpu_type=m68k + ;; + tower) # NCR Tower 32 SVR3. as with sdb debugging. + cpu_type=m68k + target_machine=tm-tower-as.h + configuration_file=xm-tower.h + ;; + pyr | pyramid) + machine=pyr + ;; +# 370) +# machine=370 +# ;; + esac + + # if cpu_type is not set, define cpu_type to machine. + # + cpu_type=${cpu_type-$machine} + configuration_file=${configuration_file-xm-$cpu_type.h} + target_machine=${target_machine-tm-$machine.h} + machine_description=${cpu_type}.md + aux_output=${aux_output-out-$cpu_type.c} + + if [ xx${vint} = xx ] + then + files="$configuration_file $target_machine + $machine_description $aux_output" + links="config.h tm.h md aux-output.c" + else + files="$configuration_file tm-vmc.h $target_machine + $machine_description $aux_output" + links="config.h tm.h tm-pre.h md aux-output.c" + fi + + while [ -n "$files" ] + do + # set file to car of files, files to cdr of files + set $files; file=$1; shift; files=$* + set $links; link=$1; shift; links=$* + + if [ ! -r ${srcdir}/config/$file ] + then + echo "$progname: cannot create a link \`$link'," 1>&2 + echo "since the file \`config/$file' does not exist." 1>&2 + exit 1 + fi + + $remove -f $link + rm -f config.status + # Make a symlink if possible, otherwise try a hard link + $symbolic_link ${srcdir}/config/$file $link 2>/dev/null || $hard_link ${srcdir}/config/$file $link + + if [ ! -r $link ] + then + echo "$progname: unable to link \`$link' to \`${srcdir}/config/$file'." 1>&2 + exit 1 + fi + echo "Linked \`$link' to \`${srcdir}/config/$file'." + done + + if [ xx${vint} = xx ] + then + echo "Links are now set up for use with a $machine." \ + | tee config.status + else + echo "Links are now set up for use with a $machine (vint)." \ + | tee config.status + fi + + # Install a makefile, and 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 + .) + ;; + *) + echo "VPATH = ${srcdir}" > x + cat x ${srcdir}/Makefile | sed "s@^srcdir = \.@srcdir = ${srcdir}@" > Makefile + rm x + echo "dir ." > .gdbinit + echo "dir ${srcdir}" >> .gdbinit + echo "source ${srcdir}/.gdbinit" >> .gdbinit + ;; + esac + + exit 0 +else + echo "Usage: $progname machine" + echo -n "Where \`machine' is something like " + echo "\`vax', \`sun3', \`encore', etc." + if [ -r config.status ] + then + cat config.status + fi + exit 1 +fi diff --git a/gcc-1.40/config/alliant.md b/gcc-1.40/config/alliant.md new file mode 100644 index 0000000..0dffea3 --- /dev/null +++ b/gcc-1.40/config/alliant.md @@ -0,0 +1,2784 @@ +;;- Machine description for GNU C compiler for Alliant FX systems +;; Copyright (C) 1989 Free Software Foundation, Inc. +;; Adapted from m68k.md by Paul Petersen (petersen@uicsrd.csrd.uiuc.edu) +;; and Joe Weening (weening@gang-of-four.stanford.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 1, 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. + + +;;- instruction definitions + +;;- @@The original PO technology requires these to be ordered by speed, +;;- @@ so that assigner will pick the fastest. + +;;- See file "rtl.def" for documentation on define_insn, match_*, et. al. + +;;- When naming insn's (operand 0 of define_insn) be careful about using +;;- names from other targets machine descriptions. + +;;- cpp macro #define NOTICE_UPDATE_CC in file tm.h handles condition code +;;- updates for most instructions. + +;;- Operand classes for the register allocator: +;;- 'a' one of the address registers can be used. +;;- 'd' one of the data registers can be used. +;;- 'f' one of the CE floating point registers can be used +;;- 'r' either a data or an address register can be used. + +;;- Immediate integer operand constraints: +;;- 'I' 1 .. 8 +;;- 'J' -32768 .. 32767 +;;- 'K' -128 .. 127 +;;- 'L' -8 .. -1 + +;;- Some remnants of constraint codes for the m68k ('x','y','G','H') +;;- may remain in the insn definitions. + +;;- Some of these insn's are composites of several Alliant op codes. +;;- The assembler (or final @@??) insures that the appropriate one is +;;- selected. + +;; Put tstsi first among test insns so it matches a CONST_INT operand. + +(define_insn "tstsi" + [(set (cc0) + (match_operand:SI 0 "general_operand" "rm"))] + "" + "* +{ + if (TARGET_68020 || ! ADDRESS_REG_P (operands[0])) + return \"tst%.l %0\"; + /* If you think that the 68020 does not support tstl a0, + reread page B-167 of the 68020 manual more carefully. */ + /* On an address reg, cmpw may replace cmpl. */ + return \"cmp%.w %#0,%0\"; +}") + +(define_insn "tsthi" + [(set (cc0) + (match_operand:HI 0 "general_operand" "rm"))] + "" + "* +{ + if (TARGET_68020 || ! ADDRESS_REG_P (operands[0])) + return \"tst%.w %0\"; + return \"cmp%.w %#0,%0\"; +}") + +(define_insn "tstqi" + [(set (cc0) + (match_operand:QI 0 "general_operand" "dm"))] + "" + "tst%.b %0") + +(define_insn "tstsf" + [(set (cc0) + (match_operand:SF 0 "nonimmediate_operand" "fm"))] + "TARGET_CE" + "* +{ + cc_status.flags = CC_IN_FP; + return \"ftest%.s %0\"; +}") + +(define_insn "tstdf" + [(set (cc0) + (match_operand:DF 0 "nonimmediate_operand" "fm"))] + "TARGET_CE" + "* +{ + cc_status.flags = CC_IN_FP; + return \"ftest%.d %0\"; +}") + +;; compare instructions. + +;; Put cmpsi first among compare insns so it matches two CONST_INT operands. + +;; A composite of the cmp, cmpa, & cmpi m68000 op codes. +(define_insn "cmpsi" + [(set (cc0) + (compare (match_operand:SI 0 "general_operand" "rKs,mr,>") + (match_operand:SI 1 "general_operand" "mr,Ksr,>")))] + "" + "* +{ + if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM) + return \"cmpm%.l %1,%0\"; + if (REG_P (operands[1]) + || (!REG_P (operands[0]) && GET_CODE (operands[0]) != MEM)) + { + cc_status.flags |= CC_REVERSED; + return \"cmp%.l %d0,%d1\"; + } + return \"cmp%.l %d1,%d0\"; +}") + +(define_insn "cmphi" + [(set (cc0) + (compare (match_operand:HI 0 "general_operand" "rnm,d,n,m") + (match_operand:HI 1 "general_operand" "d,rnm,m,n")))] + "" + "* +{ + if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM) + return \"cmpm%.w %1,%0\"; + if ((REG_P (operands[1]) && !ADDRESS_REG_P (operands[1])) + || (!REG_P (operands[0]) && GET_CODE (operands[0]) != MEM)) + { cc_status.flags |= CC_REVERSED; + return \"cmp%.w %d0,%d1\"; + } + return \"cmp%.w %d1,%d0\"; +}") + +(define_insn "cmpqi" + [(set (cc0) + (compare (match_operand:QI 0 "general_operand" "dn,md,>") + (match_operand:QI 1 "general_operand" "dm,nd,>")))] + "" + "* +{ + if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM) + return \"cmpm%.b %1,%0\"; + if (REG_P (operands[1]) + || (!REG_P (operands[0]) && GET_CODE (operands[0]) != MEM)) + { + cc_status.flags |= CC_REVERSED; + return \"cmp%.b %d0,%d1\"; + } + return \"cmp%.b %d1,%d0\"; +}") + +(define_insn "cmpdf" + [(set (cc0) + (compare (match_operand:DF 0 "nonimmediate_operand" "f,m") + (match_operand:DF 1 "nonimmediate_operand" "fm,f")))] + "TARGET_CE" + "* +{ + cc_status.flags = CC_IN_FP; + if (FP_REG_P (operands[0])) + return \"fcmp%.d %1,%0\"; + cc_status.flags |= CC_REVERSED; + return \"fcmp%.d %0,%1\"; +}") + +(define_insn "cmpsf" + [(set (cc0) + (compare (match_operand:SF 0 "nonimmediate_operand" "f,m") + (match_operand:SF 1 "nonimmediate_operand" "fm,f")))] + "TARGET_CE" + "* +{ + cc_status.flags = CC_IN_FP; + if (FP_REG_P (operands[0])) + return \"fcmp%.s %1,%0\"; + cc_status.flags |= CC_REVERSED; + return \"fcmp%.s %0,%1\"; +}") + +;; Recognizers for btst instructions. + +(define_insn "" + [(set (cc0) (zero_extract (match_operand:QI 0 "nonimmediate_operand" "do") + (const_int 1) + (minus:SI (const_int 7) + (match_operand:SI 1 "general_operand" "di"))))] + "" + "* { return output_btst (operands, operands[1], operands[0], insn, 7); }") + +(define_insn "" + [(set (cc0) (zero_extract (match_operand:SI 0 "nonimmediate_operand" "d") + (const_int 1) + (minus:SI (const_int 31) + (match_operand:SI 1 "general_operand" "di"))))] + "" + "* { return output_btst (operands, operands[1], operands[0], insn, 31); }") + +;; The following two patterns are like the previous two +;; except that they use the fact that bit-number operands +;; are automatically masked to 3 or 5 bits. + +(define_insn "" + [(set (cc0) (zero_extract (match_operand:QI 0 "nonimmediate_operand" "do") + (const_int 1) + (minus:SI (const_int 7) + (and:SI + (match_operand:SI 1 "general_operand" "d") + (const_int 7)))))] + "" + "* { return output_btst (operands, operands[1], operands[0], insn, 7); }") + +(define_insn "" + [(set (cc0) (zero_extract (match_operand:SI 0 "nonimmediate_operand" "d") + (const_int 1) + (minus:SI (const_int 31) + (and:SI + (match_operand:SI 1 "general_operand" "d") + (const_int 31)))))] + "" + "* { return output_btst (operands, operands[1], operands[0], insn, 31); }") + +;; Nonoffsettable mem refs are ok in this one pattern +;; since we don't try to adjust them. +(define_insn "" + [(set (cc0) (zero_extract (match_operand:QI 0 "nonimmediate_operand" "md") + (const_int 1) + (match_operand:SI 1 "general_operand" "i")))] + "GET_CODE (operands[1]) == CONST_INT + && (unsigned) INTVAL (operands[1]) < 8" + "* +{ + operands[1] = gen_rtx (CONST_INT, VOIDmode, 7 - INTVAL (operands[1])); + return output_btst (operands, operands[1], operands[0], insn, 7); +}") + +(define_insn "" + ;; The constraint "o,d" here means that a nonoffsettable memref + ;; will match the first alternative, and its address will be reloaded. + ;; Copying the memory contents into a reg would be incorrect if the + ;; bit position is over 7. + [(set (cc0) (zero_extract (match_operand:HI 0 "nonimmediate_operand" "o,d") + (const_int 1) + (match_operand:SI 1 "general_operand" "i,i")))] + "GET_CODE (operands[1]) == CONST_INT" + "* +{ + if (GET_CODE (operands[0]) == MEM) + { + operands[0] = adj_offsettable_operand (operands[0], + INTVAL (operands[1]) / 8); + operands[1] = gen_rtx (CONST_INT, VOIDmode, + 7 - INTVAL (operands[1]) % 8); + return output_btst (operands, operands[1], operands[0], insn, 7); + } + operands[1] = gen_rtx (CONST_INT, VOIDmode, + 15 - INTVAL (operands[1])); + return output_btst (operands, operands[1], operands[0], insn, 15); +}") + +(define_insn "" + [(set (cc0) (zero_extract (match_operand:SI 0 "nonimmediate_operand" "do") + (const_int 1) + (match_operand:SI 1 "general_operand" "i")))] + "GET_CODE (operands[1]) == CONST_INT" + "* +{ + if (GET_CODE (operands[0]) == MEM) + { + operands[0] = adj_offsettable_operand (operands[0], + INTVAL (operands[1]) / 8); + operands[1] = gen_rtx (CONST_INT, VOIDmode, + 7 - INTVAL (operands[1]) % 8); + return output_btst (operands, operands[1], operands[0], insn, 7); + } + operands[1] = gen_rtx (CONST_INT, VOIDmode, + 31 - INTVAL (operands[1])); + return output_btst (operands, operands[1], operands[0], insn, 31); +}") + +(define_insn "" + [(set (cc0) (subreg:SI (lshiftrt:QI (match_operand:QI 0 "nonimmediate_operand" "dm") + (const_int 7)) + 0))] + "" + "* +{ + cc_status.flags = CC_Z_IN_NOT_N | CC_NOT_NEGATIVE; + return \"tst%.b %0\"; +}") + +(define_insn "" + [(set (cc0) (and:SI (sign_extend:SI (sign_extend:HI (match_operand:QI 0 "nonimmediate_operand" "dm"))) + (match_operand:SI 1 "general_operand" "i")))] + "(GET_CODE (operands[1]) == CONST_INT + && (unsigned) INTVAL (operands[1]) < 0x100 + && exact_log2 (INTVAL (operands[1])) >= 0)" + "* +{ register int log = exact_log2 (INTVAL (operands[1])); + operands[1] = gen_rtx (CONST_INT, VOIDmode, log); + return output_btst (operands, operands[1], operands[0], insn, 7); +}") + +;; move instructions + +;; A special case in which it is not desirable +;; to reload the constant into a data register. +(define_insn "" + [(set (match_operand:SI 0 "push_operand" "=m") + (match_operand:SI 1 "general_operand" "J"))] + "GET_CODE (operands[1]) == CONST_INT + && INTVAL (operands[1]) >= -0x8000 + && INTVAL (operands[1]) < 0x8000" + "* +{ + if (operands[1] == const0_rtx) + return \"clr%.l %0\"; + return \"pea %a1\"; +}") + +;This is never used. +;(define_insn "swapsi" +; [(set (match_operand:SI 0 "general_operand" "r") +; (match_operand:SI 1 "general_operand" "r")) +; (set (match_dup 1) (match_dup 0))] +; "" +; "exg %1,%0") + +;; Special case of fullword move when source is zero. +;; The reason this is special is to avoid loading a zero +;; into a data reg with moveq in order to store it elsewhere. + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=g") + (const_int 0))] + "" + "* +{ + if (ADDRESS_REG_P (operands[0])) + return \"sub%.l %0,%0\"; + return \"clr%.l %0\"; +}") + +;; General case of fullword move. The register constraints +;; force integer constants in range for a moveq to be reloaded +;; if they are headed for memory. +(define_insn "movsi" + ;; Notes: make sure no alternative allows g vs g. + ;; We don't allow f-regs since fixed point cannot go in them. + ;; We do allow y and x regs since fixed point is allowed in them. + [(set (match_operand:SI 0 "general_operand" "=g,da,y,!*x*r*m") + (match_operand:SI 1 "general_operand" "daymKs,i,g,*x*r*m"))] + "" + "* +{ + if (GET_CODE (operands[1]) == CONST_INT) + { + if (operands[1] == const0_rtx + && (DATA_REG_P (operands[0]) + || GET_CODE (operands[0]) == MEM)) + return \"clr%.l %0\"; + else if (DATA_REG_P (operands[0]) + && INTVAL (operands[1]) < 128 + && INTVAL (operands[1]) >= -128) + return \"moveq %1,%0\"; + else if (ADDRESS_REG_P (operands[0]) + && INTVAL (operands[1]) < 0x8000 + && INTVAL (operands[1]) >= -0x8000) + return \"mov%.w %1,%0\"; + else if (push_operand (operands[0], SImode) + && INTVAL (operands[1]) < 0x8000 + && INTVAL (operands[1]) >= -0x8000) + return \"pea %a1\"; + } + else if ((GET_CODE (operands[1]) == SYMBOL_REF + || GET_CODE (operands[1]) == CONST) + && push_operand (operands[0], SImode)) + return \"pea %a1\"; + else if ((GET_CODE (operands[1]) == SYMBOL_REF + || GET_CODE (operands[1]) == CONST) + && ADDRESS_REG_P (operands[0])) + return \"lea %a1,%0\"; + return \"mov%.l %1,%0\"; +}") + +(define_insn "movhi" + [(set (match_operand:HI 0 "general_operand" "=g") + (match_operand:HI 1 "general_operand" "g"))] + "" + "* +{ + if (GET_CODE (operands[1]) == CONST_INT) + { + if (operands[1] == const0_rtx + && (DATA_REG_P (operands[0]) + || GET_CODE (operands[0]) == MEM)) + return \"clr%.w %0\"; + else if (DATA_REG_P (operands[0]) + && INTVAL (operands[1]) < 128 + && INTVAL (operands[1]) >= -128) + { + return \"moveq %1,%0\"; + } + else if (INTVAL (operands[1]) < 0x8000 + && INTVAL (operands[1]) >= -0x8000) + return \"mov%.w %1,%0\"; + } + else if (CONSTANT_P (operands[1])) + return \"mov%.l %1,%0\"; + /* Recognize the insn before a tablejump, one that refers + to a table of offsets. Such an insn will need to refer + to a label on the insn. So output one. Use the label-number + of the table of offsets to generate this label. */ + if (GET_CODE (operands[1]) == MEM + && GET_CODE (XEXP (operands[1], 0)) == PLUS + && (GET_CODE (XEXP (XEXP (operands[1], 0), 0)) == LABEL_REF + || GET_CODE (XEXP (XEXP (operands[1], 0), 1)) == LABEL_REF) + && GET_CODE (XEXP (XEXP (operands[1], 0), 0)) != PLUS + && GET_CODE (XEXP (XEXP (operands[1], 0), 1)) != PLUS) + { + rtx labelref; + if (GET_CODE (XEXP (XEXP (operands[1], 0), 0)) == LABEL_REF) + labelref = XEXP (XEXP (operands[1], 0), 0); + else + labelref = XEXP (XEXP (operands[1], 0), 1); + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, \"LI\", + CODE_LABEL_NUMBER (XEXP (labelref, 0))); + } + return \"mov%.w %1,%0\"; +}") + +(define_insn "movstricthi" + [(set (strict_low_part (match_operand:HI 0 "general_operand" "+dm")) + (match_operand:HI 1 "general_operand" "rmn"))] + "" + "* +{ + if (GET_CODE (operands[1]) == CONST_INT) + { + if (operands[1] == const0_rtx + && (DATA_REG_P (operands[0]) + || GET_CODE (operands[0]) == MEM)) + return \"clr%.w %0\"; + } + return \"mov%.w %1,%0\"; +}") + +(define_insn "movqi" + [(set (match_operand:QI 0 "general_operand" "=d,*a,m,m,?*a") + (match_operand:QI 1 "general_operand" "dmi*a,d*a,dmi,?*a,m"))] + "" + "* +{ + rtx xoperands[4]; + if (ADDRESS_REG_P (operands[0]) && GET_CODE (operands[1]) == MEM) + { + xoperands[1] = operands[1]; + xoperands[2] + = gen_rtx (MEM, QImode, + gen_rtx (PLUS, VOIDmode, stack_pointer_rtx, const1_rtx)); + xoperands[3] = stack_pointer_rtx; + /* Just pushing a byte puts it in the high byte of the halfword. */ + /* We must put it in the low half, the second byte. */ + output_asm_insn (\"subq%.w %#2,%3\;mov%.b %1,%2\", xoperands); + return \"mov%.w %+,%0\"; + } + if (ADDRESS_REG_P (operands[1]) && GET_CODE (operands[0]) == MEM) + { + xoperands[0] = operands[0]; + xoperands[1] = operands[1]; + xoperands[2] + = gen_rtx (MEM, QImode, + gen_rtx (PLUS, VOIDmode, stack_pointer_rtx, const1_rtx)); + xoperands[3] = stack_pointer_rtx; + output_asm_insn (\"mov%.w %1,%-\;mov%.b %2,%0\;addq%.w %#2,%3\", xoperands); + return \"\"; + } + if (operands[1] == const0_rtx) + return \"clr%.b %0\"; + if (GET_CODE (operands[1]) == CONST_INT + && INTVAL (operands[1]) == -1) + return \"st %0\"; + if (GET_CODE (operands[1]) != CONST_INT && CONSTANT_P (operands[1])) + return \"mov%.l %1,%0\"; + if (ADDRESS_REG_P (operands[0]) || ADDRESS_REG_P (operands[1])) + return \"mov%.w %1,%0\"; + return \"mov%.b %1,%0\"; +}") + +(define_insn "movstrictqi" + [(set (strict_low_part (match_operand:QI 0 "general_operand" "+dm")) + (match_operand:QI 1 "general_operand" "dmn"))] + "" + "* +{ + if (operands[1] == const0_rtx) + return \"clr%.b %0\"; + return \"mov%.b %1,%0\"; +}") + +;; Floating-point moves on a CE are faster using an FP register than +;; with movl instructions. (Especially for double floats, but also +;; for single floats, even though it takes an extra instruction.) But +;; on an IP, the FP registers are simulated and so should be avoided. +;; We do this by using define_expand for movsf and movdf, and using +;; different constraints for each target type. The constraints for +;; TARGET_CE allow general registers because they sometimes need to +;; hold floats, but they are not preferable. + +(define_expand "movsf" + [(set (match_operand:SF 0 "general_operand" "") + (match_operand:SF 1 "nonimmediate_operand" ""))] + "" + "") + +(define_insn "" + [(set (match_operand:SF 0 "general_operand" "=f,m,!*r,!f*m") + (match_operand:SF 1 "nonimmediate_operand" "fm,f,f*r*m,*r"))] + "TARGET_CE" + "* +{ + if (FP_REG_P (operands[0])) + { + if (FP_REG_P (operands[1])) + return \"fmove%.s %1,%0\"; + if (REG_P (operands[1])) + return \"mov%.l %1,%-\;fmove%.s %+,%0\"; + return \"fmove%.s %1,%0\"; + } + if (FP_REG_P (operands[1])) + { + if (REG_P (operands[0])) + return \"fmove%.s %1,%-\;mov%.l %+,%0\"; + return \"fmove%.s %1,%0\"; + } + return \"mov%.l %1,%0\"; +}") + +(define_insn "" + [(set (match_operand:SF 0 "general_operand" "=frm") + (match_operand:SF 1 "nonimmediate_operand" "frm"))] + "!TARGET_CE" + "* +{ + if (FP_REG_P (operands[0])) + { + if (FP_REG_P (operands[1])) + return \"fmove%.s %1,%0\"; + if (REG_P (operands[1])) + return \"mov%.l %1,%-\;fmove%.s %+,%0\"; + return \"fmove%.s %1,%0\"; + } + if (FP_REG_P (operands[1])) + { + if (REG_P (operands[0])) + return \"fmove%.s %1,%-\;mov%.l %+,%0\"; + return \"fmove%.s %1,%0\"; + } + return \"mov%.l %1,%0\"; +}") + +(define_expand "movdf" + [(set (match_operand:DF 0 "general_operand" "") + (match_operand:DF 1 "nonimmediate_operand" ""))] + "" + "") + +(define_insn "" + [(set (match_operand:DF 0 "general_operand" "=f,m,!*r,!f*m") + (match_operand:DF 1 "nonimmediate_operand" "fm,f,f*r*m,*r"))] + "TARGET_CE" + "* +{ + if (FP_REG_P (operands[0])) + { + if (FP_REG_P (operands[1])) + return \"fmove%.d %1,%0\"; + if (REG_P (operands[1])) + { + rtx xoperands[2]; + xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1); + output_asm_insn (\"mov%.l %1,%-\", xoperands); + output_asm_insn (\"mov%.l %1,%-\", operands); + return \"fmove%.d %+,%0\"; + } + return \"fmove%.d %1,%0\"; + } + else if (FP_REG_P (operands[1])) + { + if (REG_P (operands[0])) + { + output_asm_insn (\"fmove%.d %1,%-\;mov%.l %+,%0\", operands); + operands[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); + return \"mov%.l %+,%0\"; + } + return \"fmove%.d %1,%0\"; + } + return output_move_double (operands); +}") + +(define_insn "" + [(set (match_operand:DF 0 "general_operand" "=frm") + (match_operand:DF 1 "nonimmediate_operand" "frm"))] + "!TARGET_CE" + "* +{ + if (FP_REG_P (operands[0])) + { + if (FP_REG_P (operands[1])) + return \"fmove%.d %1,%0\"; + if (REG_P (operands[1])) + { + rtx xoperands[2]; + xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1); + output_asm_insn (\"mov%.l %1,%-\", xoperands); + output_asm_insn (\"mov%.l %1,%-\", operands); + return \"fmove%.d %+,%0\"; + } + return \"fmove%.d %1,%0\"; + } + else if (FP_REG_P (operands[1])) + { + if (REG_P (operands[0])) + { + output_asm_insn (\"fmove%.d %1,%-\;mov%.l %+,%0\", operands); + operands[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); + return \"mov%.l %+,%0\"; + } + return \"fmove%.d %1,%0\"; + } + return output_move_double (operands); +}") + +(define_insn "movdi" + [(set (match_operand:DI 0 "general_operand" "=rm,&r,&ro<>") + (match_operand:DI 1 "general_operand" "r,m,roi<>"))] + "" + "* +{ + return output_move_double (operands); +} +") + +;; This goes after the move instructions +;; because the move instructions are better (require no spilling) +;; when they can apply. It goes before the add/sub insns +;; so we will prefer it to them. + +(define_insn "pushasi" + [(set (match_operand:SI 0 "push_operand" "=m") + (match_operand:SI 1 "address_operand" "p"))] + "" + "pea %a1") + +;; truncation instructions +(define_insn "truncsiqi2" + [(set (match_operand:QI 0 "general_operand" "=dm,d") + (truncate:QI + (match_operand:SI 1 "general_operand" "doJ,i")))] + "" + "* +{ + if (GET_CODE (operands[0]) == REG) + return \"mov%.l %1,%0\"; + if (GET_CODE (operands[1]) == MEM) + operands[1] = adj_offsettable_operand (operands[1], 3); + return \"mov%.b %1,%0\"; +}") + +(define_insn "trunchiqi2" + [(set (match_operand:QI 0 "general_operand" "=dm,d") + (truncate:QI + (match_operand:HI 1 "general_operand" "doJ,i")))] + "" + "* +{ + if (GET_CODE (operands[0]) == REG + && (GET_CODE (operands[1]) == MEM + || GET_CODE (operands[1]) == CONST_INT)) + return \"mov%.w %1,%0\"; + if (GET_CODE (operands[0]) == REG) + return \"mov%.l %1,%0\"; + if (GET_CODE (operands[1]) == MEM) + operands[1] = adj_offsettable_operand (operands[1], 1); + return \"mov%.b %1,%0\"; +}") + +(define_insn "truncsihi2" + [(set (match_operand:HI 0 "general_operand" "=dm,d") + (truncate:HI + (match_operand:SI 1 "general_operand" "roJ,i")))] + "" + "* +{ + if (GET_CODE (operands[0]) == REG) + return \"mov%.l %1,%0\"; + if (GET_CODE (operands[1]) == MEM) + operands[1] = adj_offsettable_operand (operands[1], 2); + return \"mov%.w %1,%0\"; +}") + +;; zero extension instructions + +(define_expand "zero_extendhisi2" + [(set (match_operand:SI 0 "register_operand" "") + (const_int 0)) + (set (strict_low_part (subreg:HI (match_dup 0) 0)) + (match_operand:HI 1 "general_operand" ""))] + "" + "operands[1] = make_safe_from (operands[1], operands[0]);") + +(define_expand "zero_extendqihi2" + [(set (match_operand:HI 0 "register_operand" "") + (const_int 0)) + (set (strict_low_part (subreg:QI (match_dup 0) 0)) + (match_operand:QI 1 "general_operand" ""))] + "" + "operands[1] = make_safe_from (operands[1], operands[0]);") + +(define_expand "zero_extendqisi2" + [(set (match_operand:SI 0 "register_operand" "") + (const_int 0)) + (set (strict_low_part (subreg:QI (match_dup 0) 0)) + (match_operand:QI 1 "general_operand" ""))] + "" + " operands[1] = make_safe_from (operands[1], operands[0]); ") + +;; Patterns to recognize zero-extend insns produced by the combiner. + +;; Note that the one starting from HImode comes before those for QImode +;; so that a constant operand will match HImode, not QImode. +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=do<>") + (zero_extend:SI + (match_operand:HI 1 "general_operand" "rmn")))] + "" + "* +{ + if (DATA_REG_P (operands[0])) + { + if (GET_CODE (operands[1]) == REG + && REGNO (operands[0]) == REGNO (operands[1])) + return \"and%.l %#0xFFFF,%0\"; + if (reg_mentioned_p (operands[0], operands[1])) + return \"mov%.w %1,%0\;and%.l %#0xFFFF,%0\"; + return \"clr%.l %0\;mov%.w %1,%0\"; + } + else if (GET_CODE (operands[0]) == MEM + && GET_CODE (XEXP (operands[0], 0)) == PRE_DEC) + return \"mov%.w %1,%0\;clr%.w %0\"; + else if (GET_CODE (operands[0]) == MEM + && GET_CODE (XEXP (operands[0], 0)) == POST_INC) + return \"clr%.w %0\;mov%.w %1,%0\"; + else + { + output_asm_insn (\"clr%.w %0\", operands); + operands[0] = adj_offsettable_operand (operands[0], 2); + return \"mov%.w %1,%0\"; + } +}") + +(define_insn "" + [(set (match_operand:HI 0 "general_operand" "=do<>") + (zero_extend:HI + (match_operand:QI 1 "general_operand" "dmn")))] + "" + "* +{ + if (DATA_REG_P (operands[0])) + { + if (GET_CODE (operands[1]) == REG + && REGNO (operands[0]) == REGNO (operands[1])) + return \"and%.w %#0xFF,%0\"; + if (reg_mentioned_p (operands[0], operands[1])) + return \"mov%.b %1,%0\;and%.w %#0xFF,%0\"; + return \"clr%.w %0\;mov%.b %1,%0\"; + } + else if (GET_CODE (operands[0]) == MEM + && GET_CODE (XEXP (operands[0], 0)) == PRE_DEC) + { + if (REGNO (XEXP (XEXP (operands[0], 0), 0)) + == STACK_POINTER_REGNUM) + return \"clr%.w %-\;mov%.b %1,%0\"; + else + return \"mov%.b %1,%0\;clr%.b %0\"; + } + else if (GET_CODE (operands[0]) == MEM + && GET_CODE (XEXP (operands[0], 0)) == POST_INC) + return \"clr%.b %0\;mov%.b %1,%0\"; + else + { + output_asm_insn (\"clr%.b %0\", operands); + operands[0] = adj_offsettable_operand (operands[0], 1); + return \"mov%.b %1,%0\"; + } +}") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=do<>") + (zero_extend:SI + (match_operand:QI 1 "general_operand" "dmn")))] + "" + "* +{ + if (DATA_REG_P (operands[0])) + { + if (GET_CODE (operands[1]) == REG + && REGNO (operands[0]) == REGNO (operands[1])) + return \"and%.l %#0xFF,%0\"; + if (reg_mentioned_p (operands[0], operands[1])) + return \"mov%.b %1,%0\;and%.l %#0xFF,%0\"; + return \"clr%.l %0\;mov%.b %1,%0\"; + } + else if (GET_CODE (operands[0]) == MEM + && GET_CODE (XEXP (operands[0], 0)) == PRE_DEC) + { + operands[0] = XEXP (XEXP (operands[0], 0), 0); + return \"clr%.l %0@-\;mov%.b %1,%0@(3)\"; + } + else if (GET_CODE (operands[0]) == MEM + && GET_CODE (XEXP (operands[0], 0)) == POST_INC) + { + operands[0] = XEXP (XEXP (operands[0], 0), 0); + return \"clr%.l %0@+\;mov%.b %1,%0@(-1)\"; + } + else + { + output_asm_insn (\"clr%.l %0\", operands); + operands[0] = adj_offsettable_operand (operands[0], 3); + return \"mov%.b %1,%0\"; + } +}") + +;; sign extension instructions +;; Note that the one starting from HImode comes before those for QImode +;; so that a constant operand will match HImode, not QImode. + +(define_insn "extendhisi2" + [(set (match_operand:SI 0 "general_operand" "=*d,a") + (sign_extend:SI + (match_operand:HI 1 "general_operand" "0,rmn")))] + "" + "* +{ + if (ADDRESS_REG_P (operands[0])) + return \"mov%.w %1,%0\"; + return \"ext%.l %0\"; +}") + +(define_insn "extendqihi2" + [(set (match_operand:HI 0 "general_operand" "=d") + (sign_extend:HI + (match_operand:QI 1 "general_operand" "0")))] + "" + "ext%.w %0") + +(define_insn "extendqisi2" + [(set (match_operand:SI 0 "general_operand" "=d") + (sign_extend:SI + (match_operand:QI 1 "general_operand" "0")))] + "TARGET_68020" + "extb%.l %0") + +;; Conversions between float and double. + +(define_insn "extendsfdf2" + [(set (match_operand:DF 0 "general_operand" "=f,m") + (float_extend:DF + (match_operand:SF 1 "nonimmediate_operand" "fm,f")))] + "TARGET_CE" + "fmovesd %1,%0") + +(define_insn "truncdfsf2" + [(set (match_operand:SF 0 "general_operand" "=f,m") + (float_truncate:SF + (match_operand:DF 1 "nonimmediate_operand" "fm,f")))] + "TARGET_CE" + "fmoveds %1,%0") + +;; Conversion between fixed point and floating point. +;; Note that among the fix-to-float insns +;; the ones that start with SImode come first. +;; That is so that an operand that is a CONST_INT +;; (and therefore lacks a specific machine mode). +;; will be recognized as SImode (which is always valid) +;; rather than as QImode or HImode. + +(define_insn "floatsisf2" + [(set (match_operand:SF 0 "register_operand" "=f") + (float:SF (match_operand:SI 1 "nonimmediate_operand" "dm")))] + "TARGET_CE" + "fmovels %1,%0") + +(define_insn "floatsidf2" + [(set (match_operand:DF 0 "register_operand" "=f") + (float:DF (match_operand:SI 1 "nonimmediate_operand" "dm")))] + "TARGET_CE" + "fmoveld %1,%0") + +(define_insn "floathisf2" + [(set (match_operand:SF 0 "register_operand" "=f") + (float:SF (match_operand:HI 1 "nonimmediate_operand" "dm")))] + "TARGET_CE" + "fmovews %1,%0") + +(define_insn "floathidf2" + [(set (match_operand:DF 0 "register_operand" "=f") + (float:DF (match_operand:HI 1 "nonimmediate_operand" "dm")))] + "TARGET_CE" + "fmovewd %1,%0") + +(define_insn "floatqisf2" + [(set (match_operand:SF 0 "register_operand" "=f") + (float:SF (match_operand:QI 1 "nonimmediate_operand" "dm")))] + "TARGET_CE" + "fmovebs %1,%0") + +(define_insn "floatqidf2" + [(set (match_operand:DF 0 "register_operand" "=f") + (float:DF (match_operand:QI 1 "nonimmediate_operand" "dm")))] + "TARGET_CE" + "fmovebd %1,%0") + +;; Float-to-fix conversion insns. + +(define_insn "fix_truncsfqi2" + [(set (match_operand:QI 0 "general_operand" "=dm") + (fix:QI (fix:SF (match_operand:SF 1 "register_operand" "f"))))] + "TARGET_CE" + "fmovesb %1,%0") + +(define_insn "fix_truncsfhi2" + [(set (match_operand:HI 0 "general_operand" "=dm") + (fix:HI (fix:SF (match_operand:SF 1 "register_operand" "f"))))] + "TARGET_CE" + "fmovesw %1,%0") + +(define_insn "fix_truncsfsi2" + [(set (match_operand:SI 0 "general_operand" "=dm") + (fix:SI (fix:SF (match_operand:SF 1 "register_operand" "f"))))] + "TARGET_CE" + "fmovesl %1,%0") + +(define_insn "fix_truncdfqi2" + [(set (match_operand:QI 0 "general_operand" "=dm") + (fix:QI (fix:DF (match_operand:DF 1 "register_operand" "f"))))] + "TARGET_CE" + "fmovedb %1,%0") + +(define_insn "fix_truncdfhi2" + [(set (match_operand:HI 0 "general_operand" "=dm") + (fix:HI (fix:DF (match_operand:DF 1 "register_operand" "f"))))] + "TARGET_CE" + "fmovedw %1,%0") + +(define_insn "fix_truncdfsi2" + [(set (match_operand:SI 0 "general_operand" "=dm") + (fix:SI (fix:DF (match_operand:DF 1 "register_operand" "f"))))] + "TARGET_CE" + "fmovedl %1,%0") + +;; add instructions + +(define_insn "addsi3" + [(set (match_operand:SI 0 "general_operand" "=m,r,!a,!a") + (plus:SI (match_operand:SI 1 "general_operand" "%0,0,a,rJK") + (match_operand:SI 2 "general_operand" "dIKLs,mrIKLs,rJK,a")))] + "" + "* +{ + if (! operands_match_p (operands[0], operands[1])) + { + if (!ADDRESS_REG_P (operands[1])) + { + rtx tmp = operands[1]; + + operands[1] = operands[2]; + operands[2] = tmp; + } + + /* These insns can result from reloads to access + stack slots over 64k from the frame pointer. */ + if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) + 0x8000 >= (unsigned) 0x10000) + return \"mov%.l %2,%0\;add%.l %1,%0\"; + if (GET_CODE (operands[2]) == REG) + return \"lea %1@[%2:L:B],%0\"; + else + return \"lea %1@(%c2),%0\"; + } + if (GET_CODE (operands[2]) == CONST_INT) + { + if (INTVAL (operands[2]) > 0 + && INTVAL (operands[2]) <= 8) + return (ADDRESS_REG_P (operands[0]) + ? \"addq%.w %2,%0\" + : \"addq%.l %2,%0\"); + if (INTVAL (operands[2]) < 0 + && INTVAL (operands[2]) >= -8) + { + operands[2] = gen_rtx (CONST_INT, VOIDmode, + - INTVAL (operands[2])); + return (ADDRESS_REG_P (operands[0]) + ? \"subq%.w %2,%0\" + : \"subq%.l %2,%0\"); + } + if (ADDRESS_REG_P (operands[0]) + && INTVAL (operands[2]) >= -0x8000 + && INTVAL (operands[2]) < 0x8000) + return \"add%.w %2,%0\"; + } + return \"add%.l %2,%0\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=a") + (plus:SI (match_operand:SI 1 "general_operand" "0") + (sign_extend:SI (match_operand:HI 2 "general_operand" "rmn"))))] + "" + "add%.w %2,%0") + +(define_insn "addhi3" + [(set (match_operand:HI 0 "general_operand" "=m,r") + (plus:HI (match_operand:HI 1 "general_operand" "%0,0") + (match_operand:HI 2 "general_operand" "dn,rmn")))] + "" + "* +{ + if (GET_CODE (operands[2]) == CONST_INT) + { + if (INTVAL (operands[2]) > 0 + && INTVAL (operands[2]) <= 8) + return \"addq%.w %2,%0\"; + } + if (GET_CODE (operands[2]) == CONST_INT) + { + if (INTVAL (operands[2]) < 0 + && INTVAL (operands[2]) >= -8) + { + operands[2] = gen_rtx (CONST_INT, VOIDmode, + - INTVAL (operands[2])); + return \"subq%.w %2,%0\"; + } + } + return \"add%.w %2,%0\"; +}") + +(define_insn "" + [(set (strict_low_part (match_operand:HI 0 "general_operand" "+m,d")) + (plus:HI (match_dup 0) + (match_operand:HI 1 "general_operand" "dn,rmn")))] + "" + "add%.w %1,%0") + +(define_insn "addqi3" + [(set (match_operand:QI 0 "general_operand" "=m,d") + (plus:QI (match_operand:QI 1 "general_operand" "%0,0") + (match_operand:QI 2 "general_operand" "dn,dmn")))] + "" + "* +{ + if (GET_CODE (operands[2]) == CONST_INT) + { + if (INTVAL (operands[2]) > 0 + && INTVAL (operands[2]) <= 8) + return \"addq%.b %2,%0\"; + } + if (GET_CODE (operands[2]) == CONST_INT) + { + if (INTVAL (operands[2]) < 0 && INTVAL (operands[2]) >= -8) + { + operands[2] = gen_rtx (CONST_INT, VOIDmode, - INTVAL (operands[2])); + return \"subq%.b %2,%0\"; + } + } + return \"add%.b %2,%0\"; +}") + +(define_insn "" + [(set (strict_low_part (match_operand:QI 0 "general_operand" "+m,d")) + (plus:QI (match_dup 0) + (match_operand:QI 1 "general_operand" "dn,dmn")))] + "" + "add%.b %1,%0") + +(define_insn "adddf3" + [(set (match_operand:DF 0 "register_operand" "=f") + (plus:DF (match_operand:DF 1 "nonimmediate_operand" "%f") + (match_operand:DF 2 "nonimmediate_operand" "fm")))] + "TARGET_CE" + "fadd%.d %2,%1,%0") + +(define_insn "addsf3" + [(set (match_operand:SF 0 "register_operand" "=f") + (plus:SF (match_operand:SF 1 "nonimmediate_operand" "%f") + (match_operand:SF 2 "nonimmediate_operand" "fm")))] + "TARGET_CE" + "fadd%.s %2,%1,%0") + +;; subtract instructions + +(define_insn "subsi3" + [(set (match_operand:SI 0 "general_operand" "=m,r,!a,?d") + (minus:SI (match_operand:SI 1 "general_operand" "0,0,a,mrIKs") + (match_operand:SI 2 "general_operand" "dIKs,mrIKs,J,0")))] + "" + "* +{ + if (! operands_match_p (operands[0], operands[1])) + { + if (operands_match_p (operands[0], operands[2])) + { + if (GET_CODE (operands[1]) == CONST_INT) + { + if (INTVAL (operands[1]) > 0 + && INTVAL (operands[1]) <= 8) + return \"subq%.l %1,%0\;neg%.l %0\"; + } + return \"sub%.l %1,%0\;neg%.l %0\"; + } + /* This case is matched by J, but negating -0x8000 + in an lea would give an invalid displacement. + So do this specially. */ + if (INTVAL (operands[2]) == -0x8000) + return \"mov%.l %1,%0\;sub%.l %2,%0\"; + return \"lea %1@(%n2),%0\"; + } + if (GET_CODE (operands[2]) == CONST_INT) + { + if (INTVAL (operands[2]) > 0 + && INTVAL (operands[2]) <= 8) + return \"subq%.l %2,%0\"; + if (ADDRESS_REG_P (operands[0]) + && INTVAL (operands[2]) >= -0x8000 + && INTVAL (operands[2]) < 0x8000) + return \"sub%.w %2,%0\"; + } + return \"sub%.l %2,%0\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=a") + (minus:SI (match_operand:SI 1 "general_operand" "0") + (sign_extend:SI (match_operand:HI 2 "general_operand" "rmn"))))] + "" + "sub%.w %2,%0") + +(define_insn "subhi3" + [(set (match_operand:HI 0 "general_operand" "=m,r") + (minus:HI (match_operand:HI 1 "general_operand" "0,0") + (match_operand:HI 2 "general_operand" "dn,rmn")))] + "" + "sub%.w %2,%0") + +(define_insn "" + [(set (strict_low_part (match_operand:HI 0 "general_operand" "+m,d")) + (minus:HI (match_dup 0) + (match_operand:HI 1 "general_operand" "dn,rmn")))] + "" + "sub%.w %1,%0") + +(define_insn "subqi3" + [(set (match_operand:QI 0 "general_operand" "=m,d") + (minus:QI (match_operand:QI 1 "general_operand" "0,0") + (match_operand:QI 2 "general_operand" "dn,dmn")))] + "" + "sub%.b %2,%0") + +(define_insn "" + [(set (strict_low_part (match_operand:QI 0 "general_operand" "+m,d")) + (minus:QI (match_dup 0) + (match_operand:QI 1 "general_operand" "dn,dmn")))] + "" + "sub%.b %1,%0") + +(define_insn "subdf3" + [(set (match_operand:DF 0 "register_operand" "=f,f") + (minus:DF (match_operand:DF 1 "nonimmediate_operand" "f,fm") + (match_operand:DF 2 "nonimmediate_operand" "fm,f")))] + "TARGET_CE" + "* +{ + if (FP_REG_P (operands[1])) + return \"fsub%.d %2,%1,%0\"; + return \"frsub%.d %1,%2,%0\"; +}") + +(define_insn "subsf3" + [(set (match_operand:SF 0 "register_operand" "=f,f") + (minus:SF (match_operand:SF 1 "nonimmediate_operand" "f,fm") + (match_operand:SF 2 "nonimmediate_operand" "fm,f")))] + "TARGET_CE" + "* +{ + if (FP_REG_P (operands[1])) + return \"fsub%.s %2,%1,%0\"; + return \"frsub%.s %1,%2,%0\"; +}") + +;; multiply instructions + +(define_insn "mulhi3" + [(set (match_operand:HI 0 "general_operand" "=d") + (mult:HI (match_operand:HI 1 "general_operand" "%0") + (match_operand:HI 2 "general_operand" "dmn")))] + "" + "muls %2,%0") + +(define_insn "mulhisi3" + [(set (match_operand:SI 0 "general_operand" "=d") + (mult:SI (match_operand:HI 1 "general_operand" "%0") + (match_operand:HI 2 "general_operand" "dmn")))] + "" + "muls %2,%0") + +(define_insn "mulsi3" + [(set (match_operand:SI 0 "general_operand" "=d") + (mult:SI (match_operand:SI 1 "general_operand" "%0") + (match_operand:SI 2 "general_operand" "dmsK")))] + "TARGET_68020" + "muls%.l %2,%0") + +(define_insn "umulhi3" + [(set (match_operand:HI 0 "general_operand" "=d") + (umult:HI (match_operand:HI 1 "general_operand" "%0") + (match_operand:HI 2 "general_operand" "dmn")))] + "" + "mulu %2,%0") + +(define_insn "umulhisi3" + [(set (match_operand:SI 0 "general_operand" "=d") + (umult:SI (match_operand:HI 1 "general_operand" "%0") + (match_operand:HI 2 "general_operand" "dmn")))] + "" + "mulu %2,%0") + +(define_insn "umulsi3" + [(set (match_operand:SI 0 "general_operand" "=d") + (umult:SI (match_operand:SI 1 "general_operand" "%0") + (match_operand:SI 2 "general_operand" "dmsK")))] + "TARGET_68020" + "mulu%.l %2,%0") + +(define_insn "muldf3" + [(set (match_operand:DF 0 "register_operand" "=f") + (mult:DF (match_operand:DF 1 "nonimmediate_operand" "%f") + (match_operand:DF 2 "nonimmediate_operand" "fm")))] + "TARGET_CE" + "fmul%.d %2,%1,%0") + +(define_insn "mulsf3" + [(set (match_operand:SF 0 "register_operand" "=f") + (mult:SF (match_operand:SF 1 "nonimmediate_operand" "%f") + (match_operand:SF 2 "nonimmediate_operand" "fm")))] + "TARGET_CE" + "fmul%.s %2,%1,%0") + +;; divide instructions + +(define_insn "divhi3" + [(set (match_operand:HI 0 "general_operand" "=d") + (div:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "dmn")))] + "" + "extl %0\;divs %2,%0") + +(define_insn "divhisi3" + [(set (match_operand:HI 0 "general_operand" "=d") + (div:HI (match_operand:SI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "dmn")))] + "" + "divs %2,%0") + +(define_insn "divsi3" + [(set (match_operand:SI 0 "general_operand" "=d") + (div:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "dmsK")))] + "TARGET_68020" + "divs%.l %2,%0,%0") + +(define_insn "udivhi3" + [(set (match_operand:HI 0 "general_operand" "=d") + (udiv:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "dmn")))] + "" + "and%.l %#0xFFFF,%0\;divu %2,%0") + +(define_insn "udivhisi3" + [(set (match_operand:HI 0 "general_operand" "=d") + (udiv:HI (match_operand:SI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "dmn")))] + "" + "divu %2,%0") + +(define_insn "udivsi3" + [(set (match_operand:SI 0 "general_operand" "=d") + (udiv:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "dmsK")))] + "TARGET_68020" + "divu%.l %2,%0,%0") + +(define_insn "divdf3" + [(set (match_operand:DF 0 "register_operand" "=f,f") + (div:DF (match_operand:DF 1 "nonimmediate_operand" "f,fm") + (match_operand:DF 2 "nonimmediate_operand" "fm,f")))] + "TARGET_CE" + "* +{ + if (FP_REG_P (operands[1])) + return \"fdiv%.d %2,%1,%0\"; + return \"frdiv%.d %1,%2,%0\"; +}") + +(define_insn "divsf3" + [(set (match_operand:SF 0 "register_operand" "=f,f") + (div:SF (match_operand:SF 1 "nonimmediate_operand" "f,fm") + (match_operand:SF 2 "nonimmediate_operand" "fm,f")))] + "TARGET_CE" + "* +{ + if (FP_REG_P (operands[1])) + return \"fdiv%.s %2,%1,%0\"; + return \"frdiv%.s %1,%2,%0\"; +}") + +;; Remainder instructions. + +(define_insn "modhi3" + [(set (match_operand:HI 0 "general_operand" "=d") + (mod:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "dmn")))] + "" + "* +{ + /* The swap insn produces cc's that don't correspond to the result. */ + CC_STATUS_INIT; + return \"extl %0\;divs %2,%0\;swap %0\"; +}") + +(define_insn "modhisi3" + [(set (match_operand:HI 0 "general_operand" "=d") + (mod:HI (match_operand:SI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "dmn")))] + "" + "* +{ + /* The swap insn produces cc's that don't correspond to the result. */ + CC_STATUS_INIT; + return \"divs %2,%0\;swap %0\"; +}") + +(define_insn "umodhi3" + [(set (match_operand:HI 0 "general_operand" "=d") + (umod:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "dmn")))] + "" + "* +{ + /* The swap insn produces cc's that don't correspond to the result. */ + CC_STATUS_INIT; + return \"and%.l %#0xFFFF,%0\;divu %2,%0\;swap %0\"; +}") + +(define_insn "umodhisi3" + [(set (match_operand:HI 0 "general_operand" "=d") + (umod:HI (match_operand:SI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "dmn")))] + "" + "* +{ + /* The swap insn produces cc's that don't correspond to the result. */ + CC_STATUS_INIT; + return \"divu %2,%0\;swap %0\"; +}") + +(define_insn "divmodsi4" + [(set (match_operand:SI 0 "general_operand" "=d") + (div:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "dmsK"))) + (set (match_operand:SI 3 "general_operand" "=d") + (mod:SI (match_dup 1) (match_dup 2)))] + "TARGET_68020" + "divs%.l %2,%0,%3") + +(define_insn "udivmodsi4" + [(set (match_operand:SI 0 "general_operand" "=d") + (udiv:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "dmsK"))) + (set (match_operand:SI 3 "general_operand" "=d") + (umod:SI (match_dup 1) (match_dup 2)))] + "TARGET_68020" + "divu%.l %2,%0,%3") + +;; logical-and instructions + +(define_insn "andsi3" + [(set (match_operand:SI 0 "general_operand" "=m,d") + (and:SI (match_operand:SI 1 "general_operand" "%0,0") + (match_operand:SI 2 "general_operand" "dKs,dmKs")))] + "" + "* +{ + if (GET_CODE (operands[2]) == CONST_INT + && (INTVAL (operands[2]) | 0xffff) == 0xffffffff + && (DATA_REG_P (operands[0]) + || offsettable_memref_p (operands[0]))) + { + if (GET_CODE (operands[0]) != REG) + operands[0] = adj_offsettable_operand (operands[0], 2); + operands[2] = gen_rtx (CONST_INT, VOIDmode, + INTVAL (operands[2]) & 0xffff); + /* Do not delete a following tstl %0 insn; that would be incorrect. */ + CC_STATUS_INIT; + if (operands[2] == const0_rtx) + return \"clr%.w %0\"; + return \"and%.w %2,%0\"; + } + return \"and%.l %2,%0\"; +}") + +(define_insn "andhi3" + [(set (match_operand:HI 0 "general_operand" "=m,d") + (and:HI (match_operand:HI 1 "general_operand" "%0,0") + (match_operand:HI 2 "general_operand" "dn,dmn")))] + "" + "and%.w %2,%0") + +(define_insn "andqi3" + [(set (match_operand:QI 0 "general_operand" "=m,d") + (and:QI (match_operand:QI 1 "general_operand" "%0,0") + (match_operand:QI 2 "general_operand" "dn,dmn")))] + "" + "and%.b %2,%0") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=d") + (and:SI (zero_extend:SI (match_operand:HI 1 "general_operand" "dm")) + (match_operand:SI 2 "general_operand" "0")))] + "GET_CODE (operands[2]) == CONST_INT + && (unsigned int) INTVAL (operands[2]) < (1 << GET_MODE_BITSIZE (HImode))" + "and%.w %1,%0") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=d") + (and:SI (zero_extend:SI (match_operand:QI 1 "general_operand" "dm")) + (match_operand:SI 2 "general_operand" "0")))] + "GET_CODE (operands[2]) == CONST_INT + && (unsigned int) INTVAL (operands[2]) < (1 << GET_MODE_BITSIZE (QImode))" + "and%.b %1,%0") + +;; inclusive-or instructions + +(define_insn "iorsi3" + [(set (match_operand:SI 0 "general_operand" "=m,d") + (ior:SI (match_operand:SI 1 "general_operand" "%0,0") + (match_operand:SI 2 "general_operand" "dKs,dmKs")))] + "" + "* +{ + register int logval; + if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) >> 16 == 0 + && (DATA_REG_P (operands[0]) + || offsettable_memref_p (operands[0]))) + { + if (GET_CODE (operands[0]) != REG) + operands[0] = adj_offsettable_operand (operands[0], 2); + /* Do not delete a following tstl %0 insn; that would be incorrect. */ + CC_STATUS_INIT; + return \"or%.w %2,%0\"; + } + if (GET_CODE (operands[2]) == CONST_INT + && (logval = exact_log2 (INTVAL (operands[2]))) >= 0 + && (DATA_REG_P (operands[0]) + || offsettable_memref_p (operands[0]))) + { + if (DATA_REG_P (operands[0])) + operands[1] = gen_rtx (CONST_INT, VOIDmode, logval); + else + { + operands[0] = adj_offsettable_operand (operands[0], 3 - (logval / 8)); + operands[1] = gen_rtx (CONST_INT, VOIDmode, logval % 8); + } + return \"bset %1,%0\"; + } + return \"or%.l %2,%0\"; +}") + +(define_insn "iorhi3" + [(set (match_operand:HI 0 "general_operand" "=m,d") + (ior:HI (match_operand:HI 1 "general_operand" "%0,0") + (match_operand:HI 2 "general_operand" "dn,dmn")))] + "" + "or%.w %2,%0") + +(define_insn "iorqi3" + [(set (match_operand:QI 0 "general_operand" "=m,d") + (ior:QI (match_operand:QI 1 "general_operand" "%0,0") + (match_operand:QI 2 "general_operand" "dn,dmn")))] + "" + "or%.b %2,%0") + +;; xor instructions + +(define_insn "xorsi3" + [(set (match_operand:SI 0 "general_operand" "=do,m") + (xor:SI (match_operand:SI 1 "general_operand" "%0,0") + (match_operand:SI 2 "general_operand" "di,dKs")))] + "" + "* +{ + if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) >> 16 == 0 + && (offsettable_memref_p (operands[0]) || DATA_REG_P (operands[0]))) + { + if (! DATA_REG_P (operands[0])) + operands[0] = adj_offsettable_operand (operands[0], 2); + /* Do not delete a following tstl %0 insn; that would be incorrect. */ + CC_STATUS_INIT; + return \"eor%.w %2,%0\"; + } + return \"eor%.l %2,%0\"; +}") + +(define_insn "xorhi3" + [(set (match_operand:HI 0 "general_operand" "=dm") + (xor:HI (match_operand:HI 1 "general_operand" "%0") + (match_operand:HI 2 "general_operand" "dn")))] + "" + "eor%.w %2,%0") + +(define_insn "xorqi3" + [(set (match_operand:QI 0 "general_operand" "=dm") + (xor:QI (match_operand:QI 1 "general_operand" "%0") + (match_operand:QI 2 "general_operand" "dn")))] + "" + "eor%.b %2,%0") + +;; negation instructions + +(define_insn "negsi2" + [(set (match_operand:SI 0 "general_operand" "=dm") + (neg:SI (match_operand:SI 1 "general_operand" "0")))] + "" + "neg%.l %0") + +(define_insn "neghi2" + [(set (match_operand:HI 0 "general_operand" "=dm") + (neg:HI (match_operand:HI 1 "general_operand" "0")))] + "" + "neg%.w %0") + +(define_insn "negqi2" + [(set (match_operand:QI 0 "general_operand" "=dm") + (neg:QI (match_operand:QI 1 "general_operand" "0")))] + "" + "neg%.b %0") + +(define_insn "negsf2" + [(set (match_operand:SF 0 "register_operand" "=f") + (neg:SF (match_operand:SF 1 "nonimmediate_operand" "fm")))] + "TARGET_CE" + "fneg%.s %1,%0") + +(define_insn "negdf2" + [(set (match_operand:DF 0 "register_operand" "=f") + (neg:DF (match_operand:DF 1 "nonimmediate_operand" "fm")))] + "TARGET_CE" + "fneg%.d %1,%0") + +;; Absolute value instructions + +(define_insn "abssf2" + [(set (match_operand:SF 0 "register_operand" "=f") + (abs:SF (match_operand:SF 1 "nonimmediate_operand" "fm")))] + "TARGET_CE" + "fabs%.s %1,%0") + +(define_insn "absdf2" + [(set (match_operand:DF 0 "register_operand" "=f") + (abs:DF (match_operand:DF 1 "nonimmediate_operand" "fm")))] + "TARGET_CE" + "fabs%.d %1,%0") + +;; Square root instructions + +(define_insn "sqrtsf2" + [(set (match_operand:SF 0 "register_operand" "=f") + (sqrt:SF (match_operand:SF 1 "nonimmediate_operand" "fm")))] + "TARGET_CE" + "fsqrt%.s %1,%0") + +(define_insn "sqrtdf2" + [(set (match_operand:DF 0 "register_operand" "=f") + (sqrt:DF (match_operand:DF 1 "nonimmediate_operand" "fm")))] + "TARGET_CE" + "fsqrt%.d %1,%0") + +;; one complement instructions + +(define_insn "one_cmplsi2" + [(set (match_operand:SI 0 "general_operand" "=dm") + (not:SI (match_operand:SI 1 "general_operand" "0")))] + "" + "not%.l %0") + +(define_insn "one_cmplhi2" + [(set (match_operand:HI 0 "general_operand" "=dm") + (not:HI (match_operand:HI 1 "general_operand" "0")))] + "" + "not%.w %0") + +(define_insn "one_cmplqi2" + [(set (match_operand:QI 0 "general_operand" "=dm") + (not:QI (match_operand:QI 1 "general_operand" "0")))] + "" + "not%.b %0") + +;; Optimized special case of shifting. +;; Must precede the general case. + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=d") + (ashiftrt:SI (match_operand:SI 1 "memory_operand" "m") + (const_int 24)))] + "GET_CODE (XEXP (operands[1], 0)) != POST_INC + && GET_CODE (XEXP (operands[1], 0)) != PRE_DEC" + "* +{ + if (TARGET_68020) + return \"mov%.b %1,%0\;extb%.l %0\"; + return \"mov%.b %1,%0\;ext%.w %0\;ext%.l %0\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=d") + (lshiftrt:SI (match_operand:SI 1 "memory_operand" "m") + (const_int 24)))] + "GET_CODE (XEXP (operands[1], 0)) != POST_INC + && GET_CODE (XEXP (operands[1], 0)) != PRE_DEC" + "* +{ + if (reg_mentioned_p (operands[0], operands[1])) + return \"mov%.b %1,%0\;and%.l %#0xFF,%0\"; + return \"clr%.l %0\;mov%.b %1,%0\"; +}") + +(define_insn "" + [(set (cc0) (compare (match_operand:QI 0 "general_operand" "i") + (lshiftrt:SI (match_operand:SI 1 "memory_operand" "m") + (const_int 24))))] + "(GET_CODE (operands[0]) == CONST_INT + && (INTVAL (operands[0]) & ~0xff) == 0)" + "* cc_status.flags |= CC_REVERSED; + return \"cmp%.b %0,%1\"; +") + +(define_insn "" + [(set (cc0) (compare (lshiftrt:SI (match_operand:SI 0 "memory_operand" "m") + (const_int 24)) + (match_operand:QI 1 "general_operand" "i")))] + "(GET_CODE (operands[1]) == CONST_INT + && (INTVAL (operands[1]) & ~0xff) == 0)" + "* + return \"cmp%.b %1,%0\"; +") + +(define_insn "" + [(set (cc0) (compare (match_operand:QI 0 "general_operand" "i") + (ashiftrt:SI (match_operand:SI 1 "memory_operand" "m") + (const_int 24))))] + "(GET_CODE (operands[0]) == CONST_INT + && ((INTVAL (operands[0]) + 0x80) & ~0xff) == 0)" + "* cc_status.flags |= CC_REVERSED; + return \"cmp%.b %0,%1\"; +") + +(define_insn "" + [(set (cc0) (compare (ashiftrt:SI (match_operand:SI 0 "memory_operand" "m") + (const_int 24)) + (match_operand:QI 1 "general_operand" "i")))] + "(GET_CODE (operands[1]) == CONST_INT + && ((INTVAL (operands[1]) + 0x80) & ~0xff) == 0)" + "* + return \"cmp%.b %1,%0\"; +") + +;; arithmetic shift instructions +;; We don't need the shift memory by 1 bit instruction + +(define_insn "ashlsi3" + [(set (match_operand:SI 0 "general_operand" "=d") + (ashift:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "dI")))] + "" + "asl%.l %2,%0") + +(define_insn "ashlhi3" + [(set (match_operand:HI 0 "general_operand" "=d") + (ashift:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "dI")))] + "" + "asl%.w %2,%0") + +(define_insn "ashlqi3" + [(set (match_operand:QI 0 "general_operand" "=d") + (ashift:QI (match_operand:QI 1 "general_operand" "0") + (match_operand:QI 2 "general_operand" "dI")))] + "" + "asl%.b %2,%0") + +(define_insn "ashrsi3" + [(set (match_operand:SI 0 "general_operand" "=d") + (ashiftrt:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "dI")))] + "" + "asr%.l %2,%0") + +(define_insn "ashrhi3" + [(set (match_operand:HI 0 "general_operand" "=d") + (ashiftrt:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "dI")))] + "" + "asr%.w %2,%0") + +(define_insn "ashrqi3" + [(set (match_operand:QI 0 "general_operand" "=d") + (ashiftrt:QI (match_operand:QI 1 "general_operand" "0") + (match_operand:QI 2 "general_operand" "dI")))] + "" + "asr%.b %2,%0") + +;; logical shift instructions + +(define_insn "lshlsi3" + [(set (match_operand:SI 0 "general_operand" "=d") + (lshift:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "dI")))] + "" + "lsl%.l %2,%0") + +(define_insn "lshlhi3" + [(set (match_operand:HI 0 "general_operand" "=d") + (lshift:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "dI")))] + "" + "lsl%.w %2,%0") + +(define_insn "lshlqi3" + [(set (match_operand:QI 0 "general_operand" "=d") + (lshift:QI (match_operand:QI 1 "general_operand" "0") + (match_operand:QI 2 "general_operand" "dI")))] + "" + "lsl%.b %2,%0") + +(define_insn "lshrsi3" + [(set (match_operand:SI 0 "general_operand" "=d") + (lshiftrt:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "dI")))] + "" + "lsr%.l %2,%0") + +(define_insn "lshrhi3" + [(set (match_operand:HI 0 "general_operand" "=d") + (lshiftrt:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "dI")))] + "" + "lsr%.w %2,%0") + +(define_insn "lshrqi3" + [(set (match_operand:QI 0 "general_operand" "=d") + (lshiftrt:QI (match_operand:QI 1 "general_operand" "0") + (match_operand:QI 2 "general_operand" "dI")))] + "" + "lsr%.b %2,%0") + +;; rotate instructions + +(define_insn "rotlsi3" + [(set (match_operand:SI 0 "general_operand" "=d") + (rotate:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "dI")))] + "" + "rol%.l %2,%0") + +(define_insn "rotlhi3" + [(set (match_operand:HI 0 "general_operand" "=d") + (rotate:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "dI")))] + "" + "rol%.w %2,%0") + +(define_insn "rotlqi3" + [(set (match_operand:QI 0 "general_operand" "=d") + (rotate:QI (match_operand:QI 1 "general_operand" "0") + (match_operand:QI 2 "general_operand" "dI")))] + "" + "rol%.b %2,%0") + +(define_insn "rotrsi3" + [(set (match_operand:SI 0 "general_operand" "=d") + (rotatert:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "dI")))] + "" + "ror%.l %2,%0") + +(define_insn "rotrhi3" + [(set (match_operand:HI 0 "general_operand" "=d") + (rotatert:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "dI")))] + "" + "ror%.w %2,%0") + +(define_insn "rotrqi3" + [(set (match_operand:QI 0 "general_operand" "=d") + (rotatert:QI (match_operand:QI 1 "general_operand" "0") + (match_operand:QI 2 "general_operand" "dI")))] + "" + "ror%.b %2,%0") + +;; Special cases of bit-field insns which we should +;; recognize in preference to the general case. +;; These handle aligned 8-bit and 16-bit fields, +;; which can usually be done with move instructions. + +(define_insn "" + [(set (zero_extract:SI (match_operand:SI 0 "nonimmediate_operand" "+do") + (match_operand:SI 1 "immediate_operand" "i") + (match_operand:SI 2 "immediate_operand" "i")) + (match_operand:SI 3 "general_operand" "d"))] + "TARGET_68020 && TARGET_BITFIELD + && GET_CODE (operands[1]) == CONST_INT + && (INTVAL (operands[1]) == 8 || INTVAL (operands[1]) == 16) + && GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) % INTVAL (operands[1]) == 0 + && (GET_CODE (operands[0]) == REG + || ! mode_dependent_address_p (XEXP (operands[0], 0)))" + "* +{ + if (REG_P (operands[0])) + { + if (INTVAL (operands[1]) + INTVAL (operands[2]) != 32) + return \"bfins %3,[%c2,%c1]%0\"; + } + else + operands[0] + = adj_offsettable_operand (operands[0], INTVAL (operands[2]) / 8); + + if (GET_CODE (operands[3]) == MEM) + operands[3] = adj_offsettable_operand (operands[3], + (32 - INTVAL (operands[1])) / 8); + if (INTVAL (operands[1]) == 8) + return \"mov%.b %3,%0\"; + return \"mov%.w %3,%0\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=&d") + (zero_extract:SI (match_operand:SI 1 "nonimmediate_operand" "do") + (match_operand:SI 2 "immediate_operand" "i") + (match_operand:SI 3 "immediate_operand" "i")))] + "TARGET_68020 && TARGET_BITFIELD + && GET_CODE (operands[2]) == CONST_INT + && (INTVAL (operands[2]) == 8 || INTVAL (operands[2]) == 16) + && GET_CODE (operands[3]) == CONST_INT + && INTVAL (operands[3]) % INTVAL (operands[2]) == 0 + && (GET_CODE (operands[1]) == REG + || ! mode_dependent_address_p (XEXP (operands[1], 0)))" + "* +{ + if (REG_P (operands[1])) + { + if (INTVAL (operands[2]) + INTVAL (operands[3]) != 32) + return \"bfextu [%c3,%c2]%1,%0\"; + } + else + operands[1] + = adj_offsettable_operand (operands[1], INTVAL (operands[3]) / 8); + + output_asm_insn (\"clrl %0\", operands); + if (GET_CODE (operands[0]) == MEM) + operands[0] = adj_offsettable_operand (operands[0], + (32 - INTVAL (operands[1])) / 8); + if (INTVAL (operands[2]) == 8) + return \"mov%.b %1,%0\"; + return \"mov%.w %1,%0\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=d") + (sign_extract:SI (match_operand:SI 1 "nonimmediate_operand" "do") + (match_operand:SI 2 "immediate_operand" "i") + (match_operand:SI 3 "immediate_operand" "i")))] + "TARGET_68020 && TARGET_BITFIELD + && GET_CODE (operands[2]) == CONST_INT + && (INTVAL (operands[2]) == 8 || INTVAL (operands[2]) == 16) + && GET_CODE (operands[3]) == CONST_INT + && INTVAL (operands[3]) % INTVAL (operands[2]) == 0 + && (GET_CODE (operands[1]) == REG + || ! mode_dependent_address_p (XEXP (operands[1], 0)))" + "* +{ + if (REG_P (operands[1])) + { + if (INTVAL (operands[2]) + INTVAL (operands[3]) != 32) + return \"bfexts [%c3,%c2]%1,%0\"; + } + else + operands[1] + = adj_offsettable_operand (operands[1], INTVAL (operands[3]) / 8); + + if (INTVAL (operands[2]) == 8) + return \"mov%.b %1,%0\;extb%.l %0\"; + return \"mov%.w %1,%0\;ext%.l %0\"; +}") + +;; Bit field instructions, general cases. +;; "o,d" constraint causes a nonoffsettable memref to match the "o" +;; so that its address is reloaded. + +(define_insn "extv" + [(set (match_operand:SI 0 "general_operand" "=d,d") + (sign_extract:SI (match_operand:QI 1 "nonimmediate_operand" "o,d") + (match_operand:SI 2 "general_operand" "di,di") + (match_operand:SI 3 "general_operand" "di,di")))] + "TARGET_68020 && TARGET_BITFIELD" + "bfexts [%c3,%c2]%1,%0") + +(define_insn "extzv" + [(set (match_operand:SI 0 "general_operand" "=d,d") + (zero_extract:SI (match_operand:QI 1 "nonimmediate_operand" "o,d") + (match_operand:SI 2 "general_operand" "di,di") + (match_operand:SI 3 "general_operand" "di,di")))] + "TARGET_68020 && TARGET_BITFIELD" + "bfextu [%c3,%c2]%1,%0") + +(define_insn "" + [(set (zero_extract:SI (match_operand:QI 0 "nonimmediate_operand" "+o,d") + (match_operand:SI 1 "general_operand" "di,di") + (match_operand:SI 2 "general_operand" "di,di")) + (xor:SI (zero_extract:SI (match_dup 0) (match_dup 1) (match_dup 2)) + (match_operand 3 "immediate_operand" "i,i")))] + "TARGET_68020 && TARGET_BITFIELD + && GET_CODE (operands[3]) == CONST_INT + && (INTVAL (operands[3]) == -1 + || (GET_CODE (operands[1]) == CONST_INT + && (~ INTVAL (operands[3]) & ((1 << INTVAL (operands[1]))- 1)) == 0))" + "* +{ + CC_STATUS_INIT; + return \"bfchg [%c2,%c1]%0\"; +}") + +(define_insn "" + [(set (zero_extract:SI (match_operand:QI 0 "nonimmediate_operand" "+o,d") + (match_operand:SI 1 "general_operand" "di,di") + (match_operand:SI 2 "general_operand" "di,di")) + (const_int 0))] + "TARGET_68020 && TARGET_BITFIELD" + "* +{ + CC_STATUS_INIT; + return \"bfclr [%c2,%c1]%0\"; +}") + +(define_insn "" + [(set (zero_extract:SI (match_operand:QI 0 "nonimmediate_operand" "+o,d") + (match_operand:SI 1 "general_operand" "di,di") + (match_operand:SI 2 "general_operand" "di,di")) + (const_int -1))] + "TARGET_68020 && TARGET_BITFIELD" + "* +{ + CC_STATUS_INIT; + return \"bfset [%c2,%c1]%0\"; +}") + +(define_insn "insv" + [(set (zero_extract:SI (match_operand:QI 0 "nonimmediate_operand" "+o,d") + (match_operand:SI 1 "general_operand" "di,di") + (match_operand:SI 2 "general_operand" "di,di")) + (match_operand:SI 3 "general_operand" "d,d"))] + "TARGET_68020 && TARGET_BITFIELD" + "bfins %3,[%c2,%c1]%0") + +;; Now recognize bit field insns that operate on registers +;; (or at least were intended to do so). + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=d") + (sign_extract:SI (match_operand:SI 1 "nonimmediate_operand" "d") + (match_operand:SI 2 "general_operand" "di") + (match_operand:SI 3 "general_operand" "di")))] + "TARGET_68020 && TARGET_BITFIELD" + "bfexts [%c3,%c2]%1,%0") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=d") + (zero_extract:SI (match_operand:SI 1 "nonimmediate_operand" "d") + (match_operand:SI 2 "general_operand" "di") + (match_operand:SI 3 "general_operand" "di")))] + "TARGET_68020 && TARGET_BITFIELD" + "bfextu [%c3,%c2]%1,%0") + +(define_insn "" + [(set (zero_extract:SI (match_operand:SI 0 "nonimmediate_operand" "+d") + (match_operand:SI 1 "general_operand" "di") + (match_operand:SI 2 "general_operand" "di")) + (const_int 0))] + "TARGET_68020 && TARGET_BITFIELD" + "* +{ + CC_STATUS_INIT; + return \"bfclr [%c2,%c1]%0\"; +}") + +(define_insn "" + [(set (zero_extract:SI (match_operand:SI 0 "nonimmediate_operand" "+d") + (match_operand:SI 1 "general_operand" "di") + (match_operand:SI 2 "general_operand" "di")) + (const_int -1))] + "TARGET_68020 && TARGET_BITFIELD" + "* +{ + CC_STATUS_INIT; + return \"bfset [%c2,%c1]%0\"; +}") + +(define_insn "" + [(set (zero_extract:SI (match_operand:SI 0 "nonimmediate_operand" "+d") + (match_operand:SI 1 "general_operand" "di") + (match_operand:SI 2 "general_operand" "di")) + (match_operand:SI 3 "general_operand" "d"))] + "TARGET_68020 && TARGET_BITFIELD" + "* +{ + return \"bfins %3,[%c2,%c1]%0\"; +}") + +;; Special patterns for optimizing bit-field instructions. + +(define_insn "" + [(set (cc0) + (zero_extract:SI (match_operand:QI 0 "memory_operand" "o") + (match_operand:SI 1 "general_operand" "di") + (match_operand:SI 2 "general_operand" "di")))] + "TARGET_68020 && TARGET_BITFIELD + && GET_CODE (operands[1]) == CONST_INT" + "* +{ + if (operands[1] == const1_rtx + && GET_CODE (operands[2]) == CONST_INT) + { + int width = GET_CODE (operands[0]) == REG ? 31 : 7; + return output_btst (operands, + gen_rtx (CONST_INT, VOIDmode, + width - INTVAL (operands[2])), + operands[0], + insn, 1000); + /* Pass 1000 as SIGNPOS argument so that btst will + not think we are testing the sign bit for an `and' + and assume that nonzero implies a negative result. */ + } + if (INTVAL (operands[1]) != 32) + cc_status.flags = CC_NOT_NEGATIVE; + return \"bftst [%c2,%c1]%0\"; +}") + +(define_insn "" + [(set (cc0) + (subreg:QI + (zero_extract:SI (match_operand:QI 0 "memory_operand" "o") + (match_operand:SI 1 "general_operand" "di") + (match_operand:SI 2 "general_operand" "di")) + 0))] + "TARGET_68020 && TARGET_BITFIELD + && GET_CODE (operands[1]) == CONST_INT" + "* +{ + if (operands[1] == const1_rtx + && GET_CODE (operands[2]) == CONST_INT) + { + int width = GET_CODE (operands[0]) == REG ? 31 : 7; + return output_btst (operands, + gen_rtx (CONST_INT, VOIDmode, + width - INTVAL (operands[2])), + operands[0], + insn, 1000); + /* Pass 1000 as SIGNPOS argument so that btst will + not think we are testing the sign bit for an `and' + and assume that nonzero implies a negative result. */ + } + if (INTVAL (operands[1]) != 32) + cc_status.flags = CC_NOT_NEGATIVE; + return \"bftst [%c2,%c1]%0\"; +}") + +(define_insn "" + [(set (cc0) + (subreg:HI + (zero_extract:SI (match_operand:QI 0 "memory_operand" "o") + (match_operand:SI 1 "general_operand" "di") + (match_operand:SI 2 "general_operand" "di")) + 0))] + "TARGET_68020 && TARGET_BITFIELD + && GET_CODE (operands[1]) == CONST_INT" + "* +{ + if (operands[1] == const1_rtx + && GET_CODE (operands[2]) == CONST_INT) + { + int width = GET_CODE (operands[0]) == REG ? 31 : 7; + return output_btst (operands, + gen_rtx (CONST_INT, VOIDmode, + width - INTVAL (operands[2])), + operands[0], + insn, 1000); + /* Pass 1000 as SIGNPOS argument so that btst will + not think we are testing the sign bit for an `and' + and assume that nonzero implies a negative result. */ + } + if (INTVAL (operands[1]) != 32) + cc_status.flags = CC_NOT_NEGATIVE; + return \"bftst [%c2,%c1]%0\"; +}") + +;;; now handle the register cases +(define_insn "" + [(set (cc0) + (zero_extract:SI (match_operand:SI 0 "nonimmediate_operand" "d") + (match_operand:SI 1 "general_operand" "di") + (match_operand:SI 2 "general_operand" "di")))] + "TARGET_68020 && TARGET_BITFIELD + && GET_CODE (operands[1]) == CONST_INT" + "* +{ + if (operands[1] == const1_rtx + && GET_CODE (operands[2]) == CONST_INT) + { + int width = GET_CODE (operands[0]) == REG ? 31 : 7; + return output_btst (operands, + gen_rtx (CONST_INT, VOIDmode, + width - INTVAL (operands[2])), + operands[0], + insn, 1000); + /* Pass 1000 as SIGNPOS argument so that btst will + not think we are testing the sign bit for an `and' + and assume that nonzero implies a negative result. */ + } + if (INTVAL (operands[1]) != 32) + cc_status.flags = CC_NOT_NEGATIVE; + return \"bftst [%c2,%c1]%0\"; +}") + +(define_insn "" + [(set (cc0) + (subreg:QI + (zero_extract:SI (match_operand:SI 0 "nonimmediate_operand" "d") + (match_operand:SI 1 "general_operand" "di") + (match_operand:SI 2 "general_operand" "di")) + 0))] + "TARGET_68020 && TARGET_BITFIELD + && GET_CODE (operands[1]) == CONST_INT" + "* +{ + if (operands[1] == const1_rtx + && GET_CODE (operands[2]) == CONST_INT) + { + int width = GET_CODE (operands[0]) == REG ? 31 : 7; + return output_btst (operands, + gen_rtx (CONST_INT, VOIDmode, + width - INTVAL (operands[2])), + operands[0], + insn, 1000); + /* Pass 1000 as SIGNPOS argument so that btst will + not think we are testing the sign bit for an `and' + and assume that nonzero implies a negative result. */ + } + if (INTVAL (operands[1]) != 32) + cc_status.flags = CC_NOT_NEGATIVE; + return \"bftst [%c2,%c1]%0\"; +}") + +(define_insn "" + [(set (cc0) + (subreg:HI + (zero_extract:SI (match_operand:SI 0 "nonimmediate_operand" "d") + (match_operand:SI 1 "general_operand" "di") + (match_operand:SI 2 "general_operand" "di")) + 0))] + "TARGET_68020 && TARGET_BITFIELD + && GET_CODE (operands[1]) == CONST_INT" + "* +{ + if (operands[1] == const1_rtx + && GET_CODE (operands[2]) == CONST_INT) + { + int width = GET_CODE (operands[0]) == REG ? 31 : 7; + return output_btst (operands, + gen_rtx (CONST_INT, VOIDmode, + width - INTVAL (operands[2])), + operands[0], + insn, 1000); + /* Pass 1000 as SIGNPOS argument so that btst will + not think we are testing the sign bit for an `and' + and assume that nonzero implies a negative result. */ + } + if (INTVAL (operands[1]) != 32) + cc_status.flags = CC_NOT_NEGATIVE; + return \"bftst [%c2,%c1]%0\"; +}") + +(define_insn "seq" + [(set (match_operand:QI 0 "general_operand" "=d") + (eq (cc0) (const_int 0)))] + "" + "* + cc_status = cc_prev_status; + OUTPUT_JUMP (\"seq %0\", \"fseq %0\", \"seq %0\"); +") + +(define_insn "sne" + [(set (match_operand:QI 0 "general_operand" "=d") + (ne (cc0) (const_int 0)))] + "" + "* + cc_status = cc_prev_status; + OUTPUT_JUMP (\"sne %0\", \"fsneq %0\", \"sne %0\"); +") + +(define_insn "sgt" + [(set (match_operand:QI 0 "general_operand" "=d") + (gt (cc0) (const_int 0)))] + "" + "* + cc_status = cc_prev_status; + OUTPUT_JUMP (\"sgt %0\", \"fsgt %0\", \"and%.b %#0xc,%!\;sgt %0\"); +") + +(define_insn "sgtu" + [(set (match_operand:QI 0 "general_operand" "=d") + (gtu (cc0) (const_int 0)))] + "" + "* cc_status = cc_prev_status; + return \"shi %0\"; ") + +(define_insn "slt" + [(set (match_operand:QI 0 "general_operand" "=d") + (lt (cc0) (const_int 0)))] + "" + "* cc_status = cc_prev_status; + OUTPUT_JUMP (\"slt %0\", \"fslt %0\", \"smi %0\"); ") + +(define_insn "sltu" + [(set (match_operand:QI 0 "general_operand" "=d") + (ltu (cc0) (const_int 0)))] + "" + "* cc_status = cc_prev_status; + return \"scs %0\"; ") + +(define_insn "sge" + [(set (match_operand:QI 0 "general_operand" "=d") + (ge (cc0) (const_int 0)))] + "" + "* cc_status = cc_prev_status; + OUTPUT_JUMP (\"sge %0\", \"fsge %0\", \"spl %0\"); ") + +(define_insn "sgeu" + [(set (match_operand:QI 0 "general_operand" "=d") + (geu (cc0) (const_int 0)))] + "" + "* cc_status = cc_prev_status; + return \"scc %0\"; ") + +(define_insn "sle" + [(set (match_operand:QI 0 "general_operand" "=d") + (le (cc0) (const_int 0)))] + "" + "* + cc_status = cc_prev_status; + OUTPUT_JUMP (\"sle %0\", \"fsle %0\", \"and%.b %#0xc,%!\;sle %0\"); +") + +(define_insn "sleu" + [(set (match_operand:QI 0 "general_operand" "=d") + (leu (cc0) (const_int 0)))] + "" + "* cc_status = cc_prev_status; + return \"sls %0\"; ") + +;; Basic conditional jump instructions. + +(define_insn "beq" + [(set (pc) + (if_then_else (eq (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +{ + OUTPUT_JUMP (\"jeq %l0\", \"fbeq %l0\", \"jeq %l0\"); +}") + +(define_insn "bne" + [(set (pc) + (if_then_else (ne (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +{ + OUTPUT_JUMP (\"jne %l0\", \"fbneq %l0\", \"jne %l0\"); +}") + +(define_insn "bgt" + [(set (pc) + (if_then_else (gt (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* + OUTPUT_JUMP (\"jgt %l0\", \"fbgt %l0\", \"and%.b %#0xc,%!\;jgt %l0\"); +") + +(define_insn "bgtu" + [(set (pc) + (if_then_else (gtu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* + return \"jhi %l0\"; +") + +(define_insn "blt" + [(set (pc) + (if_then_else (lt (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* + OUTPUT_JUMP (\"jlt %l0\", \"fblt %l0\", \"jmi %l0\"); +") + +(define_insn "bltu" + [(set (pc) + (if_then_else (ltu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* + return \"jcs %l0\"; +") + +(define_insn "bge" + [(set (pc) + (if_then_else (ge (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* + OUTPUT_JUMP (\"jge %l0\", \"fbge %l0\", \"jpl %l0\"); +") + +(define_insn "bgeu" + [(set (pc) + (if_then_else (geu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* + return \"jcc %l0\"; +") + +(define_insn "ble" + [(set (pc) + (if_then_else (le (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* + OUTPUT_JUMP (\"jle %l0\", \"fble %l0\", \"and%.b %#0xc,%!\;jle %l0\"); +") + +(define_insn "bleu" + [(set (pc) + (if_then_else (leu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* + return \"jls %l0\"; +") + +;; Negated conditional jump instructions. + +(define_insn "" + [(set (pc) + (if_then_else (eq (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* +{ + OUTPUT_JUMP (\"jne %l0\", \"fbneq %l0\", \"jne %l0\"); +}") + +(define_insn "" + [(set (pc) + (if_then_else (ne (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* +{ + OUTPUT_JUMP (\"jeq %l0\", \"fbeq %l0\", \"jeq %l0\"); +}") + +(define_insn "" + [(set (pc) + (if_then_else (gt (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* + OUTPUT_JUMP (\"jle %l0\", \"fbngt %l0\", \"and%.b %#0xc,%!\;jle %l0\"); +") + +(define_insn "" + [(set (pc) + (if_then_else (gtu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* + return \"jls %l0\"; +") + +(define_insn "" + [(set (pc) + (if_then_else (lt (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* + OUTPUT_JUMP (\"jge %l0\", \"fbnlt %l0\", \"jpl %l0\"); +") + +(define_insn "" + [(set (pc) + (if_then_else (ltu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* + return \"jcc %l0\"; +") + +(define_insn "" + [(set (pc) + (if_then_else (ge (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* + OUTPUT_JUMP (\"jlt %l0\", \"fbnge %l0\", \"jmi %l0\"); +") + +(define_insn "" + [(set (pc) + (if_then_else (geu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* + return \"jcs %l0\"; +") + +(define_insn "" + [(set (pc) + (if_then_else (le (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* + OUTPUT_JUMP (\"jgt %l0\", \"fbnle %l0\", \"and%.b %#0xc,%!\;jgt %l0\"); +") + +(define_insn "" + [(set (pc) + (if_then_else (leu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* + return \"jhi %l0\"; +") + +;; Subroutines of "casesi". + +(define_expand "casesi_1" + [(set (match_operand:SI 3 "general_operand" "") + (plus:SI (match_operand:SI 0 "general_operand" "") + ;; Note operand 1 has been negated! + (match_operand:SI 1 "immediate_operand" ""))) + (set (cc0) (compare (match_operand:SI 2 "general_operand" "") + (match_dup 3))) + (set (pc) (if_then_else (ltu (cc0) (const_int 0)) + (label_ref (match_operand 4 "" "")) (pc)))] + "" + "") + +(define_expand "casesi_2" + [(set (match_operand:SI 0 "" "") (mem:HI (match_operand:SI 1 "" ""))) + ;; The USE here is so that at least one jump-insn will refer to the label, + ;; to keep it alive in jump_optimize. + (parallel [(set (pc) + (plus:SI (pc) (match_dup 0))) + (use (label_ref (match_operand 2 "" "")))])] + "" + "") + +;; Operand 0 is index (in bytes); operand 1 is minimum, operand 2 the maximum; +;; operand 3 is CODE_LABEL for the table; +;; operand 4 is the CODE_LABEL to go to if index out of range. +(define_expand "casesi" + ;; We don't use these for generating the RTL, but we must describe + ;; the operands here. + [(match_operand:SI 0 "general_operand" "") + (match_operand:SI 1 "immediate_operand" "") + (match_operand:SI 2 "general_operand" "") + (match_operand 3 "" "") + (match_operand 4 "" "")] + "" + " +{ + rtx table_elt_addr; + rtx index_diff; + + operands[1] = negate_rtx (SImode, operands[1]); + index_diff = gen_reg_rtx (SImode); + /* Emit the first few insns. */ + emit_insn (gen_casesi_1 (operands[0], operands[1], operands[2], + index_diff, operands[4])); + /* Construct a memory address. This may emit some insns. */ + table_elt_addr + = memory_address_noforce + (HImode, + gen_rtx (PLUS, Pmode, + gen_rtx (MULT, Pmode, index_diff, + gen_rtx (CONST_INT, VOIDmode, 2)), + gen_rtx (LABEL_REF, VOIDmode, operands[3]))); + /* Emit the last few insns. */ + emit_insn (gen_casesi_2 (gen_reg_rtx (HImode), table_elt_addr, operands[3])); + DONE; +}") + +;; Recognize one of the insns resulting from casesi_2. +(define_insn "" + [(set (pc) + (plus:SI (pc) (match_operand:HI 0 "general_operand" "r"))) + (use (label_ref (match_operand 1 "" "")))] + "" + "* + return \"jmp pc@(2:B)[%0:W:B]\"; +") + +;; Unconditional and other jump instructions +(define_insn "jump" + [(set (pc) + (label_ref (match_operand 0 "" "")))] + "" + "* + return \"jra %l0\"; +") + +(define_insn "" + [(set (pc) + (if_then_else + (ne (compare (plus:HI (match_operand:HI 0 "general_operand" "g") + (const_int -1)) + (const_int -1)) + (const_int 0)) + (label_ref (match_operand 1 "" "")) + (pc))) + (set (match_dup 0) + (plus:HI (match_dup 0) + (const_int -1)))] + "" + "* +{ + if (DATA_REG_P (operands[0])) + return \"dbra %0,%l1\"; + if (GET_CODE (operands[0]) == MEM) + { + return \"subq%.w %#1,%0\;jcc %l1\"; + } + return \"subq%.w %#1,%0\;cmp%.w %#-1,%0\;jne %l1\"; +}") + +(define_insn "" + [(set (pc) + (if_then_else + (ne (compare (plus:SI (match_operand:SI 0 "general_operand" "g") + (const_int -1)) + (const_int -1)) + (const_int 0)) + (label_ref (match_operand 1 "" "")) + (pc))) + (set (match_dup 0) + (plus:SI (match_dup 0) + (const_int -1)))] + "" + "* +{ + if (DATA_REG_P (operands[0])) + return \"dbra %0,%l1\;clr%.w %0\;subq%.l %#1,%0\;jcc %l1\"; + if (GET_CODE (operands[0]) == MEM) + return \"subq%.l %#1,%0\;jcc %l1\"; + return \"subq%.l %#1,%0\;cmp%.l %#-1,%0\;jne %l1\"; +}") + +;; dbra patterns that use REG_NOTES info generated by strength_reduce. + +(define_insn "" + [(set (pc) + (if_then_else + (ge (plus:SI (match_operand:SI 0 "general_operand" "g") + (const_int -1)) + (const_int 0)) + (label_ref (match_operand 1 "" "")) + (pc))) + (set (match_dup 0) + (plus:SI (match_dup 0) + (const_int -1)))] + "find_reg_note (insn, REG_NONNEG, 0)" + "* +{ + if (DATA_REG_P (operands[0])) + return \"dbra %0,%l1\;clrw %0\;subql %#1,%0\;jcc %l1\"; + if (GET_CODE (operands[0]) == MEM) + return \"subq%.l %#1,%0\;jcc %l1\"; + return \"subq%.l %#1,%0\;cmp%.l %#-1,%0\;jne %l1\"; +}") + +;; Call subroutine with no return value. +(define_insn "call" + [(call (match_operand:QI 0 "general_operand" "o") + (match_operand:SI 1 "general_operand" "g"))] + "" + "* +{ + rtx xoperands[2]; + int size = XINT(operands[1],0); + + if (size == 0) + output_asm_insn (\"sub%.l a0,a0\;jbsr %0\", operands); + else + { + xoperands[1] = gen_rtx (CONST_INT, VOIDmode, size/4); + output_asm_insn (\"mov%.l sp,a0\;pea %a1\", xoperands); + output_asm_insn (\"jbsr %0\", operands); + size = size + 4; + xoperands[1] = gen_rtx (CONST_INT, VOIDmode, size); + if (size <= 8) + output_asm_insn (\"addq%.l %1,sp\", xoperands); + else if (size < 0x8000) + output_asm_insn (\"add%.w %1,sp\", xoperands); + else + output_asm_insn (\"add%.l %1,sp\", xoperands); + } + return \"mov%.l a6@(-4),a0\"; +}") + +;; Call subroutine, returning value in operand 0 +;; (which must be a hard register). +(define_insn "call_value" + [(set (match_operand 0 "" "=rf") + (call (match_operand:QI 1 "general_operand" "o") + (match_operand:SI 2 "general_operand" "g")))] + "" + "* +{ + rtx xoperands[3]; + int size = XINT(operands[2],0); + + if (size == 0) + output_asm_insn(\"sub%.l a0,a0\;jbsr %1\", operands); + else + { + xoperands[2] = gen_rtx (CONST_INT, VOIDmode, size/4); + output_asm_insn (\"mov%.l sp,a0\;pea %a2\", xoperands); + output_asm_insn (\"jbsr %1\", operands); + size = size + 4; + xoperands[2] = gen_rtx (CONST_INT, VOIDmode, size); + if (size <= 8) + output_asm_insn (\"addq%.l %2,sp\", xoperands); + else if (size < 0x8000) + output_asm_insn (\"add%.w %2,sp\", xoperands); + else + output_asm_insn (\"add%.l %2,sp\", xoperands); + } + return \"mov%.l a6@(-4),a0\"; +}") + +(define_insn "nop" + [(const_int 0)] + "" + "nop") + +;; This should not be used unless the add/sub insns can't be. + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=a") + (match_operand:QI 1 "address_operand" "p"))] + "" + "lea %a1,%0") + +;; This is the first machine-dependent peephole optimization. +;; It is useful when a floating value is returned from a function call +;; and then is moved into an FP register. +;; But it is mainly intended to test the support for these optimizations. + +;Not applicable to Alliant -- floating results are returned in fp0 +;(define_peephole +; [(set (reg:SI 15) (plus:SI (reg:SI 15) (const_int 4))) +; (set (match_operand:DF 0 "register_operand" "f") +; (match_operand:DF 1 "register_operand" "ad"))] +; "FP_REG_P (operands[0]) && ! FP_REG_P (operands[1])" +; "* +;{ +; rtx xoperands[2]; +; xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1); +; output_asm_insn (\"mov%.l %1,%@\", xoperands); +; output_asm_insn (\"mov%.l %1,%-\", operands); +; return \"fmove%.d %+,%0\"; +;} +;") + + +;;- Local variables: +;;- mode:emacs-lisp +;;- comment-start: ";;- " +;;- comment-start-skip: ";+- *" +;;- eval: (set-syntax-table (copy-sequence (syntax-table))) +;;- eval: (modify-syntax-entry ?[ "(]") +;;- eval: (modify-syntax-entry ?] ")[") +;;- eval: (modify-syntax-entry ?{ "(}") +;;- eval: (modify-syntax-entry ?} "){") +;;- End: + diff --git a/gcc-1.40/config/convex.md b/gcc-1.40/config/convex.md new file mode 100644 index 0000000..97d874d --- /dev/null +++ b/gcc-1.40/config/convex.md @@ -0,0 +1,1266 @@ +;;- Machine description for GNU compiler +;;- Convex Version +;; Copyright (C) 1989 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 1, 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. + + +;;- Instruction patterns. When multiple patterns apply, +;;- the first one in the file is chosen. +;;- +;;- See file "rtl.def" for documentation on define_insn, match_*, et. al. +;;- +;;- cpp macro #define NOTICE_UPDATE_CC in file tm.h handles condition code +;;- updates for most instructions. + +;; Put tstsi first among test insns so it matches a CONST_INT operand. + +(define_insn "tstsi" + [(set (cc0) + (match_operand:SI 0 "register_operand" "r"))] + "" + "* return set_cmp (operands[0], const0_rtx, 'w');") + +(define_insn "tsthi" + [(set (cc0) + (match_operand:HI 0 "register_operand" "r"))] + "" + "* return set_cmp (operands[0], const0_rtx, 'h');") + +(define_expand "tstqi" + [(set (match_dup 1) + (sign_extend:SI (match_operand:QI 0 "register_operand" "r"))) + (set (cc0) + (match_dup 1))] + "" + "operands[1] = gen_reg_rtx (SImode);") + +(define_insn "tstdi" + [(set (cc0) + (match_operand:DI 0 "register_operand" "d")) + (clobber (reg:DI 1))] + "" + "* +{ + output_asm_insn (\"ld.l #0,s1\"); + return set_cmp (operands[0], gen_rtx (REG, DImode, 1), 'l'); +}") + +(define_expand "tstdf" + [(set (cc0) + (compare (match_operand:DF 0 "register_operand" "d") + (match_dup 1)))] + "" + "operands[1] = force_reg (DFmode, dconst0_rtx);") + +(define_insn "tstsf" + [(set (cc0) + (match_operand:SF 0 "register_operand" "d"))] + "" + "* return set_cmp (operands[0], fconst0_rtx, 's');") + +;; Put cmpsi first among compare insns so it matches two CONST_INT operands. + +(define_insn "cmpsi" + [(set (cc0) + (compare (match_operand:SI 0 "nonmemory_operand" "d,a,i,r") + (match_operand:SI 1 "nonmemory_operand" "d,a,r,i")))] + "" + "* return set_cmp (operands[0], operands[1], 'w');") + +(define_insn "cmphi" + [(set (cc0) + (compare (match_operand:HI 0 "nonmemory_operand" "d,a,r,i") + (match_operand:HI 1 "nonmemory_operand" "d,a,i,r")))] + "" + "* return set_cmp (operands[0], operands[1], 'h');") + +(define_insn "" + [(set (cc0) + (compare (sign_extend:SI (match_operand:QI 0 "register_operand" "d")) + (sign_extend:SI (match_operand:QI 1 "register_operand" "d"))))] + "" + "* return set_cmp (operands[0], operands[1], 'b');") + +(define_insn "cmpdi" + [(set (cc0) + (compare (match_operand:DI 0 "register_operand" "d") + (match_operand:DI 1 "register_operand" "d")))] + "" + "* return set_cmp (operands[0], operands[1], 'l');") + +(define_insn "cmpdf" + [(set (cc0) + (compare (match_operand:DF 0 "register_operand" "d") + (match_operand:DF 1 "register_operand" "d")))] + "" + "* return set_cmp (operands[0], operands[1], 'd');") + +(define_insn "cmpsf" + [(set (cc0) + (compare (match_operand:SF 0 "nonmemory_operand" "dF,d") + (match_operand:SF 1 "nonmemory_operand" "d,F")))] + "" + "* return set_cmp (operands[0], operands[1], 's');") + +(define_insn "movdf" + [(set (match_operand:DF 0 "general_operand" "=g,d") + (match_operand:DF 1 "general_operand" "d,gG"))] + "" + "* +{ + if (push_operand (operands[0], DFmode)) + return \"psh.l %1\"; + else if (GET_CODE (operands[0]) == MEM) + return \"st.l %1,%0\"; + else if (GET_CODE (operands[1]) == REG) + return \"mov %1,%0\"; + else if (GET_CODE (operands[1]) == CONST_DOUBLE && LD_D_P (operands[1])) + { + operands[1] = gen_rtx (CONST_INT, VOIDmode, + const_double_high_int (operands[1])); + return \"ld.d %1,%0\"; + } + else + return \"ld.l %1,%0\"; +}") + +(define_insn "movsf" + [(set (match_operand:SF 0 "general_operand" "=g,d") + (match_operand:SF 1 "general_operand" "d,gF"))] + "" + "* +{ + if (push_operand (operands[0], SFmode)) + return \"psh.w %1\"; + else if (GET_CODE (operands[0]) == MEM) + return \"st.s %1,%0\"; + else if (GET_CODE (operands[1]) == REG) + return \"mov.s %1,%0\"; + else + return \"ld.s %1,%0\"; +}") + +(define_insn "movdi" + [(set (match_operand:DI 0 "general_operand" "=g,d") + (match_operand:DI 1 "general_operand" "d,gG"))] + "" + "* +{ + if (push_operand (operands[0], DImode)) + return \"psh.l %1\"; + else if (GET_CODE (operands[0]) == MEM) + return \"st.l %1,%0\"; + else if (GET_CODE (operands[1]) == REG) + return \"mov %1,%0\"; + else if (GET_CODE (operands[1]) == CONST_DOUBLE && LD_D_P (operands[1])) + { + operands[1] = gen_rtx (CONST_INT, VOIDmode, + const_double_high_int (operands[1])); + return \"ld.d %1,%0\"; + } + else + return \"ld.l %1,%0\"; +}") + +;; Special case of movsi, needed to express A-reg preference. + +(define_insn "" + [(set (match_operand:SI 0 "push_operand" "=<") + (plus:SI (match_operand:SI 1 "register_operand" "a") + (match_operand:SI 2 "immediate_operand" "i")))] + "operands[1] != stack_pointer_rtx" + "pshea %a2(%1)") + +(define_insn "movsi" + [(set (match_operand:SI 0 "general_operand" "=g,r,<") + (match_operand:SI 1 "general_operand" "r,g,io"))] + "" + "* +{ + if (push_operand (operands[0], SImode)) + { + if (GET_CODE (operands[1]) == REG) + return \"psh.w %1\"; + else + return \"pshea %a1\"; + } + if (GET_CODE (operands[0]) == MEM) + return \"st.w %1,%0\"; + if (GET_CODE (operands[1]) != REG) + return \"ld.w %1,%0\"; + if (S_REG_P (operands[0]) && S_REG_P (operands[1])) + return \"mov.w %1,%0\"; + return \"mov %1,%0\"; +}") + +(define_insn "movhi" + [(set (match_operand:HI 0 "general_operand" "=g,r") + (match_operand:HI 1 "general_operand" "r,g"))] + "" + "* +{ + if (push_operand (operands[0], HImode)) + abort (); + else if (GET_CODE (operands[0]) == MEM) + return \"st.h %1,%0\"; + else if (GET_CODE (operands[1]) == REG) + { + if (S_REG_P (operands[0]) && S_REG_P (operands[1])) + return \"mov.w %1,%0\"; + else + return \"mov %1,%0\"; + } + else if (GET_CODE (operands[1]) == CONST_INT) + return \"ld.w %1,%0\"; + else + return \"ld.h %1,%0\"; +}") + +(define_insn "movqi" + [(set (match_operand:QI 0 "general_operand" "=g,r") + (match_operand:QI 1 "general_operand" "r,g"))] + "" + "* +{ + if (push_operand (operands[0], QImode)) + abort (); + else if (GET_CODE (operands[0]) == MEM) + return \"st.b %1,%0\"; + else if (GET_CODE (operands[1]) == REG) + { + if (S_REG_P (operands[0]) && S_REG_P (operands[1])) + return \"mov.w %1,%0\"; + else + return \"mov %1,%0\"; + } + else if (GET_CODE (operands[1]) == CONST_INT) + return \"ld.w %1,%0\"; + else + return \"ld.b %1,%0\"; +}") + +;; Extension and truncation insns. +;; Those for integer source operand +;; are ordered widest source type first. + +(define_insn "truncsiqi2" + [(set (match_operand:QI 0 "register_operand" "=d,a") + (truncate:QI (match_operand:SI 1 "register_operand" "d,a")))] + "" + "cvtw.b %1,%0") + +(define_insn "truncsihi2" + [(set (match_operand:HI 0 "register_operand" "=d,a") + (truncate:HI (match_operand:SI 1 "register_operand" "d,a")))] + "" + "cvtw.h %1,%0") + +(define_insn "trunchiqi2" + [(set (match_operand:QI 0 "register_operand" "=r") + (truncate:QI (match_operand:HI 1 "register_operand" "0")))] + "" + "") + +(define_insn "truncdisi2" + [(set (match_operand:SI 0 "register_operand" "=d") + (truncate:SI (match_operand:DI 1 "register_operand" "d")))] + "" + "cvtl.w %1,%0") + +(define_insn "extendsidi2" + [(set (match_operand:DI 0 "register_operand" "=d") + (sign_extend:DI (match_operand:SI 1 "register_operand" "d")))] + "" + "cvtw.l %1,%0") + +(define_insn "extendhisi2" + [(set (match_operand:SI 0 "register_operand" "=d,a") + (sign_extend:SI (match_operand:HI 1 "register_operand" "d,a")))] + "" + "cvth.w %1,%0") + +(define_insn "extendqihi2" + [(set (match_operand:HI 0 "register_operand" "=d,a") + (sign_extend:HI (match_operand:QI 1 "register_operand" "d,a")))] + "" + "cvtb.w %1,%0") + +(define_insn "extendqisi2" + [(set (match_operand:SI 0 "register_operand" "=d,a") + (sign_extend:SI (match_operand:QI 1 "register_operand" "d,a")))] + "" + "cvtb.w %1,%0") + +(define_insn "extendsfdf2" + [(set (match_operand:DF 0 "register_operand" "=d") + (float_extend:DF (match_operand:SF 1 "register_operand" "d")))] + "" + "cvts.d %1,%0") + +(define_insn "truncdfsf2" + [(set (match_operand:SF 0 "register_operand" "=d") + (float_truncate:SF (match_operand:DF 1 "register_operand" "d")))] + "" + "cvtd.s %1,%0") + +(define_insn "zero_extendhisi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (zero_extend:SI (match_operand:HI 1 "register_operand" "0")))] + "" + "and #0xffff,%0") + +(define_insn "zero_extendqihi2" + [(set (match_operand:HI 0 "register_operand" "=r") + (zero_extend:HI (match_operand:QI 1 "register_operand" "0")))] + "" + "and #0xff,%0") + +(define_insn "zero_extendqisi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (zero_extend:SI (match_operand:QI 1 "register_operand" "0")))] + "" + "and #0xff,%0") + +(define_insn "zero_extendsidi2" + [(set (match_operand:DI 0 "register_operand" "=d") + (zero_extend:DI (match_operand:SI 1 "register_operand" "0")))] + "" + "ld.u #0,%0") + +;; Fix-to-float conversion insns. +;; Note that the ones that start with SImode come first. +;; That is so that an operand that is a CONST_INT +;; (and therefore lacks a specific machine mode). +;; will be recognized as SImode (which is always valid) +;; rather than as QImode or HImode. + +(define_insn "floatsisf2" + [(set (match_operand:SF 0 "register_operand" "=d") + (float:SF (match_operand:SI 1 "register_operand" "d")))] + "" + "cvtw.s %1,%0") + +(define_insn "floatdisf2" + [(set (match_operand:SF 0 "register_operand" "=d") + (float:SF (match_operand:DI 1 "register_operand" "d")))] + "" + "cvtl.s %1,%0") + +(define_insn "floatsidf2" + [(set (match_operand:DF 0 "register_operand" "=d") + (float:DF (match_operand:SI 1 "register_operand" "d")))] + "TARGET_C2" + "cvtw.d %1,%0") + +(define_insn "floatdidf2" + [(set (match_operand:DF 0 "register_operand" "=d") + (float:DF (match_operand:DI 1 "register_operand" "d")))] + "" + "cvtl.d %1,%0") + +;; Float-to-fix conversion insns. + +(define_insn "fix_truncsfsi2" + [(set (match_operand:SI 0 "register_operand" "=d") + (fix:SI (fix:SF (match_operand:SF 1 "register_operand" "d"))))] + "" + "cvts.w %1,%0") + +(define_insn "fix_truncsfdi2" + [(set (match_operand:DI 0 "register_operand" "=d") + (fix:DI (fix:SF (match_operand:SF 1 "register_operand" "d"))))] + "" + "cvts.l %1,%0") + +(define_insn "fix_truncdfsi2" + [(set (match_operand:SI 0 "register_operand" "=d") + (fix:SI (fix:DF (match_operand:DF 1 "register_operand" "d"))))] + "" + "* +{ + if (TARGET_C2) + return \"cvtd.w %1,%0\"; + return \"cvtd.l %1,%0\"; +}") + +(define_insn "fix_truncdfdi2" + [(set (match_operand:DI 0 "register_operand" "=d") + (fix:DI (fix:DF (match_operand:DF 1 "register_operand" "d"))))] + "" + "cvtd.l %1,%0") + +;;- All kinds of add instructions. + +(define_insn "adddf3" + [(set (match_operand:DF 0 "register_operand" "=d") + (plus:DF (match_operand:DF 1 "register_operand" "%0") + (match_operand:DF 2 "register_operand" "d")))] + "" + "add.d %2,%0") + +(define_insn "addsf3" + [(set (match_operand:SF 0 "register_operand" "=d") + (plus:SF (match_operand:SF 1 "register_operand" "%0") + (match_operand:SF 2 "nonmemory_operand" "dF")))] + "" + "add.s %2,%0") + +(define_insn "adddi3" + [(set (match_operand:DI 0 "register_operand" "=d") + (plus:DI (match_operand:DI 1 "register_operand" "%0") + (match_operand:DI 2 "register_operand" "d")))] + "" + "add.l %2,%0") + +;; special case of addsi3, needed to specify an A reg for the destination +;; when the source is a sum involving FP or AP. + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=a") + (plus:SI (match_operand:SI 1 "register_operand" "%a") + (match_operand:SI 2 "immediate_operand" "i")))] + "operands[1] == frame_pointer_rtx || operands[1] == arg_pointer_rtx" + "ldea %a2(%1),%0") + +(define_insn "addsi3" + [(set (match_operand:SI 0 "register_operand" "=d,a,a") + (plus:SI (match_operand:SI 1 "nonmemory_operand" "%0,0,a") + (match_operand:SI 2 "nonmemory_operand" "di,ri,i")))] + "" + "* switch (which_alternative) +{ + case 0: + case 1: + return \"add.w %2,%0\"; + case 2: + if ((TARGET_C2 || A_REG_P (operands[0])) + && operands[1] != stack_pointer_rtx) + return \"ldea %a2(%1),%0\"; + else + return \"mov %1,%0\;add.w %2,%0\"; +}") + +(define_insn "addhi3" + [(set (match_operand:HI 0 "register_operand" "=d,a") + (plus:HI (match_operand:HI 1 "register_operand" "%0,0") + (match_operand:HI 2 "nonmemory_operand" "di,ai")))] + "" + "add.h %2,%0") + +(define_insn "addqi3" + [(set (match_operand:QI 0 "register_operand" "=d") + (plus:QI (match_operand:QI 1 "register_operand" "%0") + (match_operand:QI 2 "register_operand" "d")))] + "" + "add.b %2,%0") + +;;- All kinds of subtract instructions. + +(define_insn "subdf3" + [(set (match_operand:DF 0 "register_operand" "=d") + (minus:DF (match_operand:DF 1 "register_operand" "0") + (match_operand:DF 2 "register_operand" "d")))] + "" + "sub.d %2,%0") + +(define_insn "subsf3" + [(set (match_operand:SF 0 "register_operand" "=d") + (minus:SF (match_operand:SF 1 "register_operand" "0") + (match_operand:SF 2 "nonmemory_operand" "dF")))] + "" + "sub.s %2,%0") + +(define_insn "subdi3" + [(set (match_operand:DI 0 "register_operand" "=d") + (minus:DI (match_operand:DI 1 "register_operand" "0") + (match_operand:DI 2 "register_operand" "d")))] + "" + "sub.l %2,%0") + +(define_insn "subsi3" + [(set (match_operand:SI 0 "register_operand" "=d,a") + (minus:SI (match_operand:SI 1 "register_operand" "0,0") + (match_operand:SI 2 "nonmemory_operand" "di,ai")))] + "" + "sub.w %2,%0") + +(define_insn "subhi3" + [(set (match_operand:HI 0 "register_operand" "=d,a") + (minus:HI (match_operand:HI 1 "register_operand" "0,0") + (match_operand:HI 2 "nonmemory_operand" "di,ai")))] + "" + "sub.h %2,%0") + +(define_insn "subqi3" + [(set (match_operand:QI 0 "register_operand" "=d") + (minus:QI (match_operand:QI 1 "register_operand" "0") + (match_operand:QI 2 "register_operand" "d")))] + "" + "sub.b %2,%0") + +;;- Multiply instructions. + +(define_insn "muldf3" + [(set (match_operand:DF 0 "register_operand" "=d") + (mult:DF (match_operand:DF 1 "register_operand" "%0") + (match_operand:DF 2 "register_operand" "d")))] + "" + "mul.d %2,%0") + +(define_insn "mulsf3" + [(set (match_operand:SF 0 "register_operand" "=d") + (mult:SF (match_operand:SF 1 "register_operand" "%0") + (match_operand:SF 2 "nonmemory_operand" "dF")))] + "" + "mul.s %2,%0") + +(define_insn "muldi3" + [(set (match_operand:DI 0 "register_operand" "=d") + (mult:DI (match_operand:DI 1 "register_operand" "%0") + (match_operand:DI 2 "register_operand" "d")))] + "" + "mul.l %2,%0") + +(define_insn "mulsi3" + [(set (match_operand:SI 0 "register_operand" "=d,a") + (mult:SI (match_operand:SI 1 "register_operand" "%0,0") + (match_operand:SI 2 "nonmemory_operand" "di,ai")))] + "" + "mul.w %2,%0") + +(define_insn "mulhi3" + [(set (match_operand:HI 0 "register_operand" "=d,a") + (mult:HI (match_operand:HI 1 "register_operand" "%0,0") + (match_operand:HI 2 "nonmemory_operand" "di,ai")))] + "" + "mul.h %2,%0") + +(define_insn "mulqi3" + [(set (match_operand:QI 0 "register_operand" "=d") + (mult:QI (match_operand:QI 1 "register_operand" "%0") + (match_operand:QI 2 "register_operand" "d")))] + "" + "mul.b %2,%0") + +;;- Divide instructions. + +(define_insn "divdf3" + [(set (match_operand:DF 0 "register_operand" "=d") + (div:DF (match_operand:DF 1 "register_operand" "0") + (match_operand:DF 2 "register_operand" "d")))] + "" + "div.d %2,%0") + +(define_insn "divsf3" + [(set (match_operand:SF 0 "register_operand" "=d") + (div:SF (match_operand:SF 1 "register_operand" "0") + (match_operand:SF 2 "nonmemory_operand" "dF")))] + "" + "div.s %2,%0") + +(define_insn "divdi3" + [(set (match_operand:DI 0 "register_operand" "=d") + (div:DI (match_operand:DI 1 "register_operand" "0") + (match_operand:DI 2 "register_operand" "d")))] + "" + "div.l %2,%0") + +(define_insn "udivdi3" + [(set (match_operand:DI 0 "register_operand" "=d") + (udiv:DI (match_operand:DI 1 "register_operand" "d") + (match_operand:DI 2 "register_operand" "d")))] + "" + "psh.l %2\;psh.l %1\;callq udiv64\;pop.l %0\;add.w #8,sp") + +(define_insn "divsi3" + [(set (match_operand:SI 0 "register_operand" "=d,a") + (div:SI (match_operand:SI 1 "register_operand" "0,0") + (match_operand:SI 2 "nonmemory_operand" "di,ai")))] + "" + "div.w %2,%0") + +(define_insn "divhi3" + [(set (match_operand:HI 0 "register_operand" "=d,a") + (div:HI (match_operand:HI 1 "register_operand" "0,0") + (match_operand:HI 2 "nonmemory_operand" "di,ai")))] + "" + "div.h %2,%0") + +(define_insn "divqi3" + [(set (match_operand:QI 0 "register_operand" "=d") + (div:QI (match_operand:QI 1 "register_operand" "0") + (match_operand:QI 2 "register_operand" "d")))] + "" + "div.b %2,%0") + +;; - and, or, xor + +(define_insn "anddi3" + [(set (match_operand:DI 0 "register_operand" "=d") + (and:DI (match_operand:DI 1 "register_operand" "%0") + (match_operand:DI 2 "register_operand" "d")))] + "" + "and %2,%0") + +(define_insn "andsi3" + [(set (match_operand:SI 0 "register_operand" "=d,a") + (and:SI (match_operand:SI 1 "register_operand" "%0,0") + (match_operand:SI 2 "nonmemory_operand" "di,ai")))] + "" + "and %2,%0") + +(define_insn "andhi3" + [(set (match_operand:HI 0 "register_operand" "=d,a") + (and:HI (match_operand:HI 1 "register_operand" "%0,0") + (match_operand:HI 2 "nonmemory_operand" "di,ai")))] + "" + "and %2,%0") + +(define_insn "andqi3" + [(set (match_operand:QI 0 "register_operand" "=d,a") + (and:QI (match_operand:QI 1 "register_operand" "%0,0") + (match_operand:QI 2 "nonmemory_operand" "di,ai")))] + "" + "and %2,%0") + +;;- Bit set instructions. + +(define_insn "iordi3" + [(set (match_operand:DI 0 "register_operand" "=d") + (ior:DI (match_operand:DI 1 "register_operand" "%0") + (match_operand:DI 2 "register_operand" "d")))] + "" + "or %2,%0") + +(define_insn "iorsi3" + [(set (match_operand:SI 0 "register_operand" "=d,a") + (ior:SI (match_operand:SI 1 "register_operand" "%0,0") + (match_operand:SI 2 "nonmemory_operand" "di,ai")))] + "" + "or %2,%0") + +(define_insn "iorhi3" + [(set (match_operand:HI 0 "register_operand" "=d,a") + (ior:HI (match_operand:HI 1 "register_operand" "%0,0") + (match_operand:HI 2 "nonmemory_operand" "di,ai")))] + "" + "or %2,%0") + +(define_insn "iorqi3" + [(set (match_operand:QI 0 "register_operand" "=d,a") + (ior:QI (match_operand:QI 1 "register_operand" "%0,0") + (match_operand:QI 2 "nonmemory_operand" "di,ai")))] + "" + "or %2,%0") + +;;- xor instructions. + +(define_insn "xordi3" + [(set (match_operand:DI 0 "register_operand" "=d") + (xor:DI (match_operand:DI 1 "register_operand" "%0") + (match_operand:DI 2 "register_operand" "d")))] + "" + "xor %2,%0") + +(define_insn "xorsi3" + [(set (match_operand:SI 0 "register_operand" "=d,a") + (xor:SI (match_operand:SI 1 "register_operand" "%0,0") + (match_operand:SI 2 "nonmemory_operand" "di,ai")))] + "" + "xor %2,%0") + +(define_insn "xorhi3" + [(set (match_operand:HI 0 "register_operand" "=d,a") + (xor:HI (match_operand:HI 1 "register_operand" "%0,0") + (match_operand:HI 2 "nonmemory_operand" "di,ai")))] + "" + "xor %2,%0") + +(define_insn "xorqi3" + [(set (match_operand:QI 0 "register_operand" "=d,a") + (xor:QI (match_operand:QI 1 "register_operand" "%0,0") + (match_operand:QI 2 "nonmemory_operand" "di,ai")))] + "" + "xor %2,%0") + +(define_insn "negdf2" + [(set (match_operand:DF 0 "register_operand" "=d") + (neg:DF (match_operand:DF 1 "register_operand" "d")))] + "" + "neg.d %1,%0") + +(define_insn "negsf2" + [(set (match_operand:SF 0 "register_operand" "=d") + (neg:SF (match_operand:SF 1 "register_operand" "d")))] + "" + "neg.s %1,%0") + +(define_insn "negdi2" + [(set (match_operand:DI 0 "register_operand" "=d") + (neg:DI (match_operand:DI 1 "register_operand" "d")))] + "" + "neg.l %1,%0") + +(define_insn "negsi2" + [(set (match_operand:SI 0 "register_operand" "=d,a") + (neg:SI (match_operand:SI 1 "register_operand" "d,a")))] + "" + "neg.w %1,%0") + +(define_insn "neghi2" + [(set (match_operand:HI 0 "register_operand" "=d,a") + (neg:HI (match_operand:HI 1 "register_operand" "d,a")))] + "" + "neg.h %1,%0") + +(define_insn "negqi2" + [(set (match_operand:QI 0 "register_operand" "=d") + (neg:QI (match_operand:QI 1 "register_operand" "d")))] + "" + "neg.b %1,%0") + +(define_insn "one_cmpldi2" + [(set (match_operand:DI 0 "register_operand" "=d") + (not:DI (match_operand:DI 1 "register_operand" "d")))] + "" + "not %1,%0") + +(define_insn "one_cmplsi2" + [(set (match_operand:SI 0 "register_operand" "=d,a") + (not:SI (match_operand:SI 1 "register_operand" "d,a")))] + "" + "not %1,%0") + +(define_insn "one_cmplhi2" + [(set (match_operand:HI 0 "register_operand" "=d,a") + (not:HI (match_operand:HI 1 "register_operand" "d,a")))] + "" + "not %1,%0") + +(define_insn "one_cmplqi2" + [(set (match_operand:QI 0 "register_operand" "=d,a") + (not:QI (match_operand:QI 1 "register_operand" "d,a")))] + "" + "not %1,%0") + +;;- shifts +;; +;; Convex shift instructions are unsigned. +;; To make signed right shifts: +;; for SImode, sign extend to DImode and shift, works for 0..32 +;; for DImode, shift and then extend the sign, works for 0..63 +;; +;; It is very sad that DImode right shift 64 fails, but I don't see +;; any reasonable way to handle it. ANSI only requires up to 63. + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (ashift:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "immediate_operand" "i")))] + "INTVAL (operands[2]) >= 0" + "* +{ + if (operands[2] == const1_rtx) + return \"add.w %0,%0\"; + else if (TARGET_C2 && S_REG_P (operands[0])) + return \"shf.w %2,%0\"; + else + return \"shf %2,%0\"; +}") + +(define_insn "ashlsi3" + [(set (match_operand:SI 0 "register_operand" "=d") + (ashift:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "nonmemory_operand" "di")))] + "" + "* +{ + if (operands[2] == const1_rtx) + return \"add.w %0,%0\"; + else if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) >= 0) + return TARGET_C2 ? \"shf.w %2,%0\" : \"shf %2,%0\"; + else + return \"cvtw.l %0,%0\;shf %2,%0\"; +}") + +(define_expand "ashrsi3" + [(set (match_operand:SI 0 "register_operand" "=d") + (ashift:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "nonmemory_operand" "di")))] + "" + "operands[2] = negate_rtx (SImode, operands[2]);") + +(define_insn "lshlsi3" + [(set (match_operand:SI 0 "register_operand" "=d,a") + (lshift:SI (match_operand:SI 1 "register_operand" "0,0") + (match_operand:SI 2 "nonmemory_operand" "di,ai")))] + "" + "* +{ + if (operands[2] == const1_rtx) + return \"add.w %0,%0\"; + if (S_REG_P (operands[0])) + { + if (TARGET_C2) + return \"shf.w %2,%0\"; + else if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) >= 0) + return \"shf %2,%0\"; + else + return \"ld.u #0,%0\;shf %2,%0\"; + } + return \"shf %2,%0\"; +}") + +(define_expand "lshrsi3" + [(set (match_operand:SI 0 "register_operand" "=d") + (lshift:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "nonmemory_operand" "di")))] + "" + "operands[2] = negate_rtx (SImode, operands[2]);") + +;; signed a >> b is +;; ((a >> b) ^ signbit) - signbit +;; where signbit is (1 << 63) >> b + +(define_expand "ashldi3" + [(match_operand:DI 0 "register_operand" "=d") + (match_operand:DI 1 "register_operand" "0") + (match_operand:SI 2 "nonmemory_operand" "di") + (match_dup 3)] + "" + " +{ + if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) >= 0) + emit_insn (gen_rtx (SET, VOIDmode, operands[0], + gen_rtx (LSHIFT, DImode, operands[1], operands[2]))); + else if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) < 0) + { + int rshift = - INTVAL (operands[2]); + operands[3] = force_reg + (DImode, + immed_double_const (1 << (63 - rshift), 1 << (31 - rshift), DImode)); + emit_insn (gen_rtx (SET, VOIDmode, operands[0], + gen_rtx (LSHIFT, DImode, operands[1], operands[2]))); + emit_insn (gen_rtx (SET, VOIDmode, operands[0], + gen_rtx (XOR, DImode, operands[0], operands[3]))); + emit_insn (gen_rtx (SET, VOIDmode, operands[0], + gen_rtx (MINUS, DImode, operands[0], operands[3]))); + } + else + { + operands[3] = + force_reg (DImode, immed_double_const (0, 1 << 31, DImode)); + emit_insn (gen_rtx (SET, VOIDmode, operands[0], + gen_rtx (LSHIFT, DImode, operands[1], operands[2]))); + emit_insn (gen_rtx (SET, VOIDmode, operands[3], + gen_rtx (LSHIFT, DImode, operands[3], operands[2]))); + emit_insn (gen_rtx (SET, VOIDmode, operands[0], + gen_rtx (XOR, DImode, operands[0], operands[3]))); + emit_insn (gen_rtx (SET, VOIDmode, operands[0], + gen_rtx (MINUS, DImode, operands[0], operands[3]))); + } + DONE; +}") + +(define_expand "ashrdi3" + [(match_operand:DI 0 "register_operand" "=d") + (match_operand:DI 1 "register_operand" "0") + (match_operand:SI 2 "nonmemory_operand" "di")] + "" + " +{ + emit_insn (gen_ashldi3 (operands[0], operands[1], + negate_rtx (SImode, operands[2]))); + DONE; +}") + +(define_insn "lshldi3" + [(set (match_operand:DI 0 "register_operand" "=d") + (lshift:DI (match_operand:DI 1 "register_operand" "0") + (match_operand:SI 2 "nonmemory_operand" "di")))] + "" + "shf %2,%0") + +(define_expand "lshrdi3" + [(set (match_operand:DI 0 "register_operand" "=d") + (lshift:DI (match_operand:DI 1 "register_operand" "0") + (match_operand:SI 2 "nonmemory_operand" "di")))] + "" + "operands[2] = negate_rtx (SImode, operands[2]);") + +;; __builtin instructions + +(define_insn "sqrtdf2" + [(set (match_operand:DF 0 "register_operand" "=d") + (sqrt:DF (match_operand:DF 1 "register_operand" "0")))] + "TARGET_C2" + "sqrt.d %0") + +(define_insn "sqrtsf2" + [(set (match_operand:SF 0 "register_operand" "=d") + (sqrt:SF (match_operand:SF 1 "register_operand" "0")))] + "TARGET_C2" + "sqrt.s %0") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=d") + (minus:SI (ffs:SI (match_operand:SI 1 "register_operand" "d")) + (const_int 1)))] + "" + "tzc %1,%0\;le.w #32,%0\;jbrs.f .+6\;ld.w #-1,%0") + +(define_expand "ffssi2" + [(set (match_operand:SI 0 "register_operand" "=d") + (minus:SI (ffs:SI (match_operand:SI 1 "register_operand" "d")) + (const_int 1))) + (set (match_dup 0) + (plus:SI (match_dup 0) + (const_int 1)))] + "" + "") + +(define_insn "abssf2" + [(set (match_operand:SF 0 "register_operand" "=d") + (abs:SF (match_operand:SF 1 "register_operand" "0")))] + "" + "and #0x7fffffff,%0") + +(define_expand "absdf2" + [(set (subreg:DI (match_operand:DF 0 "register_operand" "=d") 0) + (and:DI (subreg:DI (match_operand:DF 1 "register_operand" "d") 0) + (match_dup 2)))] + "" + "operands[2] = force_reg (DImode, + immed_double_const (-1, 0x7fffffff, DImode));") + +(define_insn "jump" + [(set (pc) + (label_ref (match_operand 0 "" "")))] + "" + "jbr %l0") + +(define_insn "beq" + [(set (pc) + (if_then_else (eq (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* return gen_cmp (operands[0], \"eq\", 't'); ") + +(define_insn "bne" + [(set (pc) + (if_then_else (ne (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* return gen_cmp (operands[0], \"eq\", 'f'); ") + +(define_insn "bgt" + [(set (pc) + (if_then_else (gt (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* return gen_cmp (operands[0], \"le\", 'f'); ") + +(define_insn "bgtu" + [(set (pc) + (if_then_else (gtu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* return gen_cmp (operands[0], \"leu\", 'f'); ") + +(define_insn "blt" + [(set (pc) + (if_then_else (lt (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* return gen_cmp (operands[0], \"lt\", 't'); ") + +(define_insn "bltu" + [(set (pc) + (if_then_else (ltu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* return gen_cmp (operands[0], \"ltu\", 't'); ") + +(define_insn "bge" + [(set (pc) + (if_then_else (ge (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* return gen_cmp (operands[0], \"lt\", 'f'); ") + +(define_insn "bgeu" + [(set (pc) + (if_then_else (geu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* return gen_cmp (operands[0], \"ltu\", 'f'); ") + +(define_insn "ble" + [(set (pc) + (if_then_else (le (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* return gen_cmp (operands[0], \"le\", 't'); ") + +(define_insn "bleu" + [(set (pc) + (if_then_else (leu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* return gen_cmp (operands[0], \"leu\", 't'); ") + +(define_insn "" + [(set (pc) + (if_then_else (eq (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* return gen_cmp (operands[0], \"eq\", 'f'); ") + +(define_insn "" + [(set (pc) + (if_then_else (ne (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* return gen_cmp (operands[0], \"eq\", 't'); ") + +(define_insn "" + [(set (pc) + (if_then_else (gt (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* return gen_cmp (operands[0], \"le\", 't'); ") + +(define_insn "" + [(set (pc) + (if_then_else (gtu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* return gen_cmp (operands[0], \"leu\", 't'); ") + +(define_insn "" + [(set (pc) + (if_then_else (lt (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* return gen_cmp (operands[0], \"lt\", 'f'); ") + +(define_insn "" + [(set (pc) + (if_then_else (ltu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* return gen_cmp (operands[0], \"ltu\", 'f'); ") + +(define_insn "" + [(set (pc) + (if_then_else (ge (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* return gen_cmp (operands[0], \"lt\", 't'); ") + +(define_insn "" + [(set (pc) + (if_then_else (geu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* return gen_cmp (operands[0], \"ltu\", 't'); ") + +(define_insn "" + [(set (pc) + (if_then_else (le (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* return gen_cmp (operands[0], \"le\", 'f'); ") + +(define_insn "" + [(set (pc) + (if_then_else (leu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* return gen_cmp (operands[0], \"leu\", 'f'); ") + +;; - Calls +;; +;; arg count word may be omitted to save a push and let gcc try to +;; combine the arg list pop. RETURN_POPS_ARGS from tm.h decides this. + +(define_insn "call" + [(call (match_operand:QI 0 "general_operand" "g") + (match_operand:SI 1 "general_operand" "g"))] + "" + "* +{ + if (! RETURN_POPS_ARGS (ignoreme)) + { + if (operands[1] == const0_rtx) + return \"calls %0\"; + if (! reg_mentioned_p (arg_pointer_rtx, operands[0])) + return \"mov sp,ap\;calls %0\;ld.w 12(fp),ap\"; + operands[0] = XEXP (operands[0], 0); + return \"ld.w %0,a1\;mov sp,ap\;calls (a1)\;ld.w 12(fp),ap\"; + } + operands[1] = gen_rtx (CONST_INT, VOIDmode, (INTVAL (operands[1]) + 3)/ 4); + if (! reg_mentioned_p (arg_pointer_rtx, operands[0])) + return \"mov sp,ap\;pshea %a1\;calls %0\;ld.w 12(fp),ap\;add.w #4*%a1+4,sp\"; + operands[0] = XEXP (operands[0], 0); + return \"ld.w %0,a1\;mov sp,ap\;pshea %a1\;calls (a1)\;ld.w 12(fp),ap\;add.w #4*%a1+4,sp\"; +}") + +(define_insn "call_value" + [(set (match_operand 0 "" "=g") + (call (match_operand:QI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")))] + "" + "* +{ + if (! RETURN_POPS_ARGS (ignoreme)) + { + if (operands[2] == const0_rtx) + return \"calls %1\"; + if (! reg_mentioned_p (arg_pointer_rtx, operands[1])) + return \"mov sp,ap\;calls %1\;ld.w 12(fp),ap\"; + operands[1] = XEXP (operands[1], 0); + return \"ld.w %1,a1\;mov sp,ap\;calls (a1)\;ld.w 12(fp),ap\"; + } + operands[2] = gen_rtx (CONST_INT, VOIDmode, (INTVAL (operands[2]) + 3) / 4); + if (! reg_mentioned_p (arg_pointer_rtx, operands[1])) + return \"mov sp,ap\;pshea %a2\;calls %1\;ld.w 12(fp),ap\;add.w #4*%a2+4,sp\"; + operands[1] = XEXP (operands[1], 0); + return \"ld.w %1,a1\;mov sp,ap\;pshea %a2\;calls (a1)\;ld.w 12(fp),ap\;add.w #4*%a2+4,sp\"; +}") + +(define_insn "return" + [(return)] + "" + "rtn") + +(define_insn "nop" + [(const_int 0)] + "" + "nop") + +(define_insn "tablejump" + [(set (pc) (match_operand:SI 0 "address_operand" "p")) + (use (label_ref (match_operand 1 "" "")))] + "" + "jmp %a0") + +;; - fix up the code generated for bit field tests + +;; cc0 = (x >> k1) & k2 --> cc0 = x & (k2 << k1) +;; cc0 = (x << k1) & k2 --> cc0 = x & (k2 >> k1) +;; provided k2 and (k2 << k1) don't include the sign bit + +(define_peephole + [(set (match_operand:SI 0 "register_operand" "r") + (lshift:SI (match_dup 0) + (match_operand 1 "immediate_operand" "i"))) + (set (match_dup 0) + (and:SI (match_dup 0) + (match_operand 2 "immediate_operand" "i"))) + (set (cc0) (match_dup 0))] + "dead_or_set_p (insn, operands[0]) + && GET_CODE (operands[1]) == CONST_INT + && GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) >= 0 + && (INTVAL (operands[2]) << INTVAL (operands[1])) >= 0" + "* +{ + operands[2] = gen_rtx (CONST_INT, VOIDmode, + INTVAL (operands[2]) >> INTVAL (operands[1])); + output_asm_insn (\"and %2,%0\", operands); + return set_cmp (operands[0], const0_rtx, 'w'); +}") + +;; same as above where x is (y & 0xff...) caused by a zero extend + +(define_peephole + [(set (match_operand:SI 0 "register_operand" "r") + (zero_extend:SI (match_operand 1 "register_operand" "0"))) + (set (match_dup 0) + (lshift:SI (match_dup 0) + (match_operand 2 "immediate_operand" "i"))) + (set (match_dup 0) + (and:SI (match_dup 0) + (match_operand 3 "immediate_operand" "i"))) + (set (cc0) (match_dup 0))] + "dead_or_set_p (insn, operands[0]) + && REGNO (operands[0]) == REGNO (operands[1]) + && GET_CODE (operands[2]) == CONST_INT + && GET_CODE (operands[3]) == CONST_INT + && (INTVAL (operands[3]) << INTVAL (operands[2])) >= 0" + "* +{ + operands[3] = gen_rtx (CONST_INT, VOIDmode, + (INTVAL (operands[3]) >> INTVAL (operands[2])) & + ~((-1) << GET_MODE_BITSIZE (GET_MODE (operands[1])))); + output_asm_insn (\"and %3,%0\", operands); + return set_cmp (operands[0], const0_rtx, 'w'); +}") + +;;- Local variables: +;;- mode:emacs-lisp +;;- comment-start: ";;- " +;;- eval: (set-syntax-table (copy-sequence (syntax-table))) +;;- eval: (modify-syntax-entry ?[ "(]") +;;- eval: (modify-syntax-entry ?] ")[") +;;- eval: (modify-syntax-entry ?{ "(}") +;;- eval: (modify-syntax-entry ?} "){") +;;- End: + diff --git a/gcc-1.40/config/i386.md b/gcc-1.40/config/i386.md new file mode 100644 index 0000000..df467e3 --- /dev/null +++ b/gcc-1.40/config/i386.md @@ -0,0 +1,2021 @@ +;; GCC machine description for Intel 80386. +;; Copyright (C) 1988 Free Software Foundation, Inc. +;; Mostly by William Schelter. + +;; 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 1, 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. + + +;;- instruction definitions + +;;- @@The original PO technology requires these to be ordered by speed, +;;- @@ so that assigner will pick the fastest. + +;;- See file "rtl.def" for documentation on define_insn, match_*, et. al. + +;;- When naming insn's (operand 0 of define_insn) be careful about using +;;- names from other targets machine descriptions. + +;;- cpp macro #define NOTICE_UPDATE_CC in file tm.h handles condition code +;;- updates for most instructions. + +;;- Operand classes for the register allocator: +;;- 'a' for eax +;;- 'd' for edx +;;- 'c' for ecx +;;- 'b' for ebx +;;- 'f' for anything in FLOAT_REGS +;;- 'r' any (non-floating-point) register +;;- 'q' regs that allow byte operations (A, B, C and D) +;;- 'A' A and D registers + +;; the special asm out single letter directives following a '%' are: +;; 'z' mov%z1 would be movl, movw, or movb depending on the mode of operands[1] +;; 's' output a '*' +;; 'w' If the operand is a REG, it uses the mode size to determine the +;; printing of the reg + + +;; Put tstsi first among test insns so it matches a CONST_INT operand. + +(define_insn "tstsi" + [(set (cc0) + (match_operand:SI 0 "general_operand" "rm"))] + "" + "* +{ + operands[1] = const0_rtx; + if (REG_P (operands[0])) + return AS2 (test%L0,%0,%0); + return AS2 (cmp%L0,%1,%0); +}") + +(define_insn "tsthi" + [(set (cc0) + (match_operand:HI 0 "general_operand" "rm"))] + "" + "* +{ + operands[1] = const0_rtx; + if (REG_P (operands[0])) + return AS2 (test%W0,%0,%0); + return AS2 (cmp%W0,%1,%0); +}") + +(define_insn "tstqi" + [(set (cc0) + (match_operand:QI 0 "general_operand" "qm"))] + "" + "* +{ + operands[1] = const0_rtx; + if (REG_P (operands[0])) + return AS2 (test%B0,%0,%0); + return AS2 (cmp%B0,%1,%0); +}") + +(define_insn "tstsf" + [(set (cc0) + (match_operand:SF 0 "general_operand" "rm,f")) + (clobber (reg:SI 0))] + "TARGET_80387" + "* +{ + rtx xops[1]; + if (!FP_REG_P (operands[0])) + fp_push_sf (operands[0]); +/* fp_pop_level--; */ + xops[0] = FP_TOP; + cc_status.flags |= CC_IN_80387; + if (FP_REG_P (operands[0]) && ! top_dead_p (insn)) + output_asm_insn (\"ftst\;fnstsw %R0ax\;sahf\", xops); + else + output_asm_insn (\"ftst\;fstp %0(0)\;fnstsw %R0ax\;sahf\", xops); + RETCOM (testsf); +}") + +(define_insn "tstdf" + [(set (cc0) + (match_operand:DF 0 "general_operand" "rm,f")) + (clobber (reg:SI 0)) + ] + "TARGET_80387" + "* +{ + rtx xops[1]; + if (!FP_REG_P (operands[0])) + fp_push_df (operands[0]); +/* fp_pop_level--; */ + xops[0] = FP_TOP; + cc_status.flags |= CC_IN_80387; + if (FP_REG_P (operands[0]) && ! top_dead_p (insn)) + output_asm_insn (\"ftst\;fnstsw %R0ax\;sahf\", xops); + else + output_asm_insn (\"ftst\;fstp %0(0)\;fnstsw %R0ax\;sahf\", xops); + RETCOM (testdf); +}") + +;;- compare instructions + +;; Put cmpsi first among compare insns so it matches two CONST_INT operands. + +(define_insn "cmpsi" + [(set (cc0) + (compare (match_operand:SI 0 "general_operand" "mr,ri") + (match_operand:SI 1 "general_operand" "ri,mr")))] + "" + "* +{ + if (REG_P (operands[1]) + || (!REG_P (operands[0]) && GET_CODE (operands[0]) != MEM)) + { + cc_status.flags |= CC_REVERSED; + return AS2 (cmp%L0,%0,%1); + } + return AS2 (cmp%L0,%1,%0); +}") + +(define_insn "cmphi" + [(set (cc0) + (compare (match_operand:HI 0 "general_operand" "mr,ri") + (match_operand:HI 1 "general_operand" "ri,mr")))] + "" + "* +{ + if (REG_P (operands[1]) + || (!REG_P (operands[0]) && GET_CODE (operands[0]) != MEM)) + { + cc_status.flags |= CC_REVERSED; + return AS2 (cmp%W0,%0,%1); + } + return AS2 (cmp%W0,%1,%0); +}") + +(define_insn "cmpqi" + [(set (cc0) + (compare (match_operand:QI 0 "general_operand" "qn,mq") + (match_operand:QI 1 "general_operand" "qm,nq")))] + "" + "* +{ + if (REG_P (operands[1]) + || (!REG_P (operands[0]) && GET_CODE (operands[0]) != MEM)) + { + cc_status.flags |= CC_REVERSED; + return AS2 (cmp%B0,%0,%1); + } + return AS2 (cmp%B0,%1,%0); +}") + +(define_insn "cmpdf" + [(set (cc0) + (compare (match_operand:DF 0 "general_operand" "m,f*r,m,f,r,!*r") + (match_operand:DF 1 "general_operand" "m,m,f*r,r,f,*r"))) + (clobber (reg:SI 0))] + "TARGET_80387" + "* +{ + if (FP_REG_P (operands[0])) + { + rtx tem = operands[1]; + operands[1] = operands[0]; + operands[0] = tem; + cc_status.flags |= CC_REVERSED; + } + if (! FP_REG_P (operands[1])) + output_movdf (FP_TOP, operands[1]); + output_movdf (FP_TOP, operands[0]); +/* fp_pop_level--; + fp_pop_level--; */ + cc_status.flags |= CC_IN_80387; + return \"fcompp\;fnstsw %R0ax\;sahf\"; +}") + +(define_insn "cmpsf" + [(set (cc0) + (compare (match_operand:SF 0 "general_operand" "m,f*r,m,f,r,!*r") + (match_operand:SF 1 "general_operand" "m,m,f*r,r,f,*r"))) + (clobber (reg:SI 0))] + "TARGET_80387" + "* +{ + if (FP_REG_P (operands[0])) + { + rtx tem = operands[1]; + operands[1] = operands[0]; + operands[0] = tem; + cc_status.flags |= CC_REVERSED; + } + if (! FP_REG_P (operands[1])) + output_movsf (FP_TOP, operands[1]); + output_movsf (FP_TOP, operands[0]); +/* fp_pop_level--; + fp_pop_level--; */ + cc_status.flags |= CC_IN_80387; + return \"fcompp\;fnstsw %R0ax\;sahf\"; +}") + +;; logical compare +(define_insn "" + [(set (cc0) + (and:SI (match_operand:SI 0 "general_operand" "rm,ri") + (match_operand:SI 1 "general_operand" "ri,rm")))] + "" + "* +{ + if (CONSTANT_P (operands[1]) || GET_CODE (operands[0]) == MEM) + return AS2 (test%L0,%1,%0); + return AS2 (test%L0,%0,%1); +}") + +(define_insn "" + [(set (cc0) + (and:HI (match_operand:HI 0 "general_operand" "rm,ri") + (match_operand:HI 1 "general_operand" "ri,rm")))] + "" + "* +{ + if (CONSTANT_P (operands[1]) || GET_CODE (operands[0]) == MEM) + return AS2 (test%W0,%1,%0); + return AS2 (test%W0,%0,%1); +}") + +(define_insn "" + [(set (cc0) + (and:QI (match_operand:QI 0 "general_operand" "qm,qi") + (match_operand:QI 1 "general_operand" "qi,qm")))] + "" + "* +{ + if (CONSTANT_P (operands[1]) || GET_CODE (operands[0]) == MEM) + return AS2 (test%B0,%1,%0); + return AS2 (test%B0,%0,%1); +}") + +;; move instructions. +;; There is one for each machine mode, +;; and each is preceded by a corresponding push-insn pattern +;; (since pushes are not general_operands on the 386). + +(define_insn "" + [(set (match_operand:SI 0 "push_operand" "=<") + (match_operand:SI 1 "general_operand" "g"))] + "" + "push%L0 %1") + +;; General case of fullword move. +(define_insn "movsi" + [(set (match_operand:SI 0 "general_operand" "=g,r") + (match_operand:SI 1 "general_operand" "ri,m"))] + "" + "* +{ + rtx link; + if (operands[1] == const0_rtx && REG_P (operands[0])) + return \"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. */ + && ! XEXP (link, 0)->volatil + && GET_CODE (XEXP (link, 0)) != NOTE + /* Make sure cross jumping didn't happen here. */ + && no_labels_between_p (XEXP (link, 0), insn)) + /* Fastest way to change a 0 to a 1. */ + return \"inc%L0 %0\"; + return \"mov%L0 %1,%0\"; +}") + +(define_insn "" + [(set (match_operand:HI 0 "push_operand" "=<") + (match_operand:HI 1 "general_operand" "g"))] + "" + "push%W0 %1") + +(define_insn "movhi" + [(set (match_operand:HI 0 "general_operand" "=g,r") + (match_operand:HI 1 "general_operand" "ri,m"))] + "" + "* +{ + rtx link; + if (operands[1] == const0_rtx && REG_P (operands[0])) + return \"xor%W0 %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. */ + && ! XEXP (link, 0)->volatil + && GET_CODE (XEXP (link, 0)) != NOTE + /* Make sure cross jumping didn't happen here. */ + && no_labels_between_p (XEXP (link, 0), insn)) + /* Fastest way to change a 0 to a 1. */ + return \"inc%W0 %0\"; + return \"mov%W0 %1,%0\"; +}") + +;; emit_push_insn when it calls move_by_pieces +;; requires an insn to "push a byte". +;; But actually we use pushw, which has the effect of rounding +;; the amount pushed up to a halfword. +(define_insn "" + [(set (match_operand:QI 0 "push_operand" "=<") + (match_operand:QI 1 "general_operand" "q"))] + "" + "* +{ + operands[1] = gen_rtx (REG, HImode, REGNO (operands[1])); + return \"push%W0 %1\"; +}") + +(define_insn "movqi" + [(set (match_operand:QI 0 "general_operand" "=q,*r,m") + (match_operand:QI 1 "general_operand" "*g,q,qi"))] + "" + "* +{ + rtx link; + if (operands[1] == const0_rtx && REG_P (operands[0])) + return \"xor%B0 %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. */ + && ! XEXP (link, 0)->volatil + && GET_CODE (XEXP (link, 0)) != NOTE + /* Make sure cross jumping didn't happen here. */ + && no_labels_between_p (XEXP (link, 0), insn)) + /* Fastest way to change a 0 to a 1. */ + return \"inc%B0 %0\"; + /* If mov%B0 isn't allowed for one of these regs, use mov%W0. */ + if (NON_QI_REG_P (operands[0]) || NON_QI_REG_P (operands[1])) + return (AS2 (mov%W0,%w1,%w0)); + return (AS2 (mov%B0,%1,%0)); +}") + +; I suspect nothing can ever match this ??? +;(define_insn "" +; [(set (match_operand:SF 0 "general_operand" "rm") +; (match_operand:SF 1 "general_operand" "f")) +; (clobber (reg:SF 8))] +; "" +; "* +;{ +; output_asm_insn ("???", operands); +; fpop_sf (operands[0]); +; RETCOM (movsf_clobber); +;}") + +(define_insn "" + [(set (match_operand:SF 0 "push_operand" "=<,<") + (match_operand:SF 1 "general_operand" "gF,f"))] + "" + "* +{ + if (FP_REG_P (operands[1])) + { + rtx xops[3]; + xops[0] = AT_SP (SFmode); + xops[1] = gen_rtx (CONST_INT, VOIDmode, 4); + xops[2] = stack_pointer_rtx; +/* fp_pop_level--; */ + output_asm_insn (AS2 (sub%L0,%1,%2), xops); + if (top_dead_p (insn)) + output_asm_insn (\"fstp%S0 %0\", xops); + else + output_asm_insn (\"fst%S0 %0\", xops); + RET; + } + return \"push%L0 %1\"; +}") + +(define_insn "movsf" + ;; `rf' is duplicated in the second alternative + ;; to make sure an optional reload is generated + ;; for the memref in operand 0. Otherwise + ;; we could use too many hard regs. + [(set (match_operand:SF 0 "general_operand" "=rf,mrf,!rm") + (match_operand:SF 1 "general_operand" "mrf,rf,F"))] + "" + "* +{ + if (FP_REG_P (operands[1]) + && !FP_REG_P (operands[0]) + && !top_dead_p (insn)) + fp_store_sf (operands[0]); + else + output_movsf (operands[0], operands[1]); + RETCOM (movsf); +}") + +;;should change to handle the memory operands[1] without doing df push.. +(define_insn "" + [(set (match_operand:DF 0 "push_operand" "=<,<") + (match_operand:DF 1 "general_operand" "gF,f"))] + "" + "* +{ + if (FP_REG_P (operands[1])) + { + rtx xops[3]; + xops[0] = AT_SP (DFmode); + xops[1] = gen_rtx (CONST_INT, VOIDmode, 8); + xops[2] = stack_pointer_rtx; +/* fp_pop_level--; */ + output_asm_insn (AS2 (sub%L0,%1,%2), xops); + if (top_dead_p(insn)) + output_asm_insn (\"fstp%Q0 %0\", xops); + else + output_asm_insn (\"fst%Q0 %0\", xops); + RETCOM (pushdf); + } + else + return output_move_double (operands); +}") + +(define_insn "movdf" + [(set (match_operand:DF 0 "general_operand" "=rmf,&fr,!rm") + ;; `rf' is duplicated in the second alternative + ;; to make sure that optional reloads are generated + ;; for the memory reference in operand 1. + (match_operand:DF 1 "general_operand" "fr,mrf,F"))] + "" + "* +{ + if (FP_REG_P (operands[1]) + && ! FP_REG_P (operands[0]) + && ! top_dead_p (insn)) + fp_store_df (operands[0]); + else + output_movdf (operands[0], operands[1]); + RETCOM (movdf); +}") + +(define_insn "" + [(set (match_operand:DI 0 "push_operand" "=<") + (match_operand:DI 1 "general_operand" "roiF"))] + "" + "* +{ + return output_move_double (operands); +}") + +(define_insn "movdi" + [(set (match_operand:DI 0 "general_operand" "=&r,rm") + (match_operand:DI 1 "general_operand" "m,riF"))] + "" + "* +{ + return output_move_double (operands); +}") + +;; These go after the move instructions +;; because the move instructions are better (require no spilling) +;; when they can apply. But these go before the add and subtract insns +;; because it is often shorter to use these when both apply. + +;Lennart Augustsson +;says this pattern just makes slower code: +; pushl %ebp +; addl $-80,(%esp) +;instead of +; leal -80(%ebp),%eax +; pushl %eax +; +;(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")))] +; "" +; "* +;{ +; rtx xops[4]; +; xops[0] = operands[0]; +; xops[1] = operands[1]; +; xops[2] = operands[2]; +; 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; +;}") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=g") + (plus:SI (match_operand:SI 1 "general_operand" "0") + (const_int 1)))] + "" + "inc%L0 %0") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=g") + (plus:SI (match_operand:SI 1 "general_operand" "0") + (const_int -1)))] + "" + "dec%L0 %0") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=g") + (minus:SI (match_operand:SI 1 "general_operand" "0") + (const_int 1)))] + "" + "dec%L0 %0") + +(define_insn "" + [(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. */ + 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); + return AS2 (add%L0,%1,%0); + } + return \"lea%L0 %a1,%0\"; +}") + +;;- conversion instructions +;;- NONE + +;;- truncation instructions +(define_insn "truncsiqi2" + [(set (match_operand:QI 0 "general_operand" "=q,m") + (truncate:QI + (match_operand:SI 1 "general_operand" "qim,qn")))] + "" + "* +{ + if (CONSTANT_P (operands[1]) && GET_CODE (operands[1]) != CONST_INT) + return \"mov%L0 %1,%k0\"; + return \"mov%B0 %b1,%0\"; +}") + +(define_insn "trunchiqi2" + [(set (match_operand:QI 0 "general_operand" "=q,m") + (truncate:QI + (match_operand:HI 1 "general_operand" "qim,qn")))] + "" + "* +{ + if (CONSTANT_P (operands[1]) && GET_CODE (operands[1]) != CONST_INT) + return \"mov%W0 %1,%w0\"; + return \"mov%B0 %b1,%0\"; +}") + +(define_insn "truncsihi2" + [(set (match_operand:HI 0 "general_operand" "=r,m") + (truncate:HI + (match_operand:SI 1 "general_operand" "rim,rn")))] + "" + "* +{ + if (CONSTANT_P (operands[1]) && GET_CODE (operands[1]) != CONST_INT) + return \"mov%L0 %1,%k0\"; + return \"mov%W0 %w1,%0\"; +}") + +;;- zero extension instructions +;; Note that the one starting from HImode comes before those for QImode +;; so that a constant operand will match HImode, not QImode. + +(define_insn "zero_extendhisi2" + [(set (match_operand:SI 0 "general_operand" "=r") + (zero_extend:SI + (match_operand:HI 1 "general_operand" "rm")))] + "" + "movz%W0%L0 %1,%0") + +(define_insn "zero_extendqihi2" + [(set (match_operand:HI 0 "general_operand" "=r") + (zero_extend:HI + (match_operand:QI 1 "general_operand" "qm")))] + "" + "movz%B0%W0 %1,%0") + +(define_insn "zero_extendqisi2" + [(set (match_operand:SI 0 "general_operand" "=r") + (zero_extend:SI + (match_operand:QI 1 "general_operand" "qm")))] + "" + "movz%B0%L0 %1,%0") + +;;- sign extension instructions +;; Note that the one starting from HImode comes before those for QImode +;; so that a constant operand will match HImode, not QImode. + +/* +(define_insn "extendsidi2" + [(set (match_operand:DI 0 "general_operand" "=a") + (sign_extend:DI + (match_operand:SI 1 "general_operand" "a")))] + "" + "clq") +*/ + +;; Note that the i386 programmers' manual says that the opcodes +;; are named movsx..., but the assembler on Unix does not accept that. +;; 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 "general_operand" "rm")))] + "" + "movs%W0%L0 %1,%0") + +(define_insn "extendqihi2" + [(set (match_operand:HI 0 "general_operand" "=r") + (sign_extend:HI + (match_operand:QI 1 "general_operand" "qm")))] + "" + "movs%B0%W0 %1,%0") + +(define_insn "extendqisi2" + [(set (match_operand:SI 0 "general_operand" "=r") + (sign_extend:SI + (match_operand:QI 1 "general_operand" "qm")))] + "" + "movs%B0%L0 %1,%0" + ) + +;; Conversions between float and double. + +(define_insn "extendsfdf2" + [(set (match_operand:DF 0 "general_operand" "=fm,f,fm,fm") + (float_extend:DF + (match_operand:SF 1 "general_operand" "m,0,f,!*r")))] + "TARGET_80387" + "* +{ + if (FP_REG_P (operands[0])) + { + output_movsf (operands[0], operands[1]); + RET; + } + if (FP_REG_P (operands[1])) + { + if (top_dead_p (insn)) + fp_pop_df (operands[0]); + else + fp_store_df (operands[0]); + RET; + } + output_movsf (FP_TOP, operands[1]); + fp_pop_df (operands[0]); + RETCOM (extendsfdf2); +}") + +;; This cannot output into an f-reg because there is no way to be +;; sure of truncating in that case. +(define_insn "truncdfsf2" + [(set (match_operand:SF 0 "general_operand" "=m,!*r") + (float_truncate:SF + (match_operand:DF 1 "general_operand" "f,f")))] + "TARGET_80387" + "* +{ + if (top_dead_p (insn)) + fp_pop_sf (operands[0]); + else + fp_store_sf (operands[0]); + RETCOM (truncdfsf2); +}") + +;; Conversion between fixed point and floating point. +;; Note that among the fix-to-float insns +;; the ones that start with SImode come first. +;; That is so that an operand that is a CONST_INT +;; (and therefore lacks a specific machine mode). +;; will be recognized as SImode (which is always valid) +;; rather than as QImode or HImode. The 80387 would not know +;; what to do with the smaller sizes anyway. (I think). + +(define_insn "floatsisf2" + [(set (match_operand:SF 0 "general_operand" "=fm,fm") + (float:SF (match_operand:SI 1 "general_operand" "m,!*r")))] + "TARGET_80387" + "* +{ +/* fp_pop_level++; */ + + if (GET_CODE (operands[1]) != MEM) + { + rtx xops[2]; + output_asm_insn (\"push%L0 %1\", operands); + operands[1] = AT_SP (SImode); + output_asm_insn (\"fild%L0 %1\", operands); + xops[0] = stack_pointer_rtx; + xops[1] = gen_rtx (CONST_INT, VOIDmode, 4); + output_asm_insn (AS2 (add%L0,%1,%0), xops); + } + else + output_asm_insn (\"fild%L0 %1\", operands); + + if (! FP_REG_P (operands[0])) + { +/* fp_pop_level--; */ + return \"fstp%S0 %0\"; + } + RET; +}") + +(define_insn "floatsidf2" + [(set (match_operand:DF 0 "general_operand" "=fm,fm") + (float:DF (match_operand:SI 1 "general_operand" "m,!*r")))] + "TARGET_80387" + "* +{ +/* fp_pop_level++; */ + if (GET_CODE (operands[1]) != MEM) + { + rtx xops[2]; + output_asm_insn (\"push%L0 %1\", operands); + operands[1] = AT_SP (SImode); + output_asm_insn (\"fild%L0 %1\", operands); + xops[0] = stack_pointer_rtx; + xops[1] = gen_rtx (CONST_INT, VOIDmode, 4); + output_asm_insn (AS2 (add%L0,%1,%0), xops); + } + else + output_asm_insn (\"fild%L0 %1\", operands); + if (! FP_REG_P (operands[0])) + { +/* fp_pop_level--; */ + return \"fstp%Q0 %0\"; + } + RET; +}") + +;; Convert a float to a float whose value is an integer. +;; This is the first stage of converting it to an integer type. + +;; On the 387 truncating doub to an short integer shor can be performed: + +; fstcw -4(%esp) ;save cw +; movw -4(%esp),%ax +; orw $0x0c00,%ax ;set rounding to chop towards zero +; movw %ax,-2(%esp) ; +; fldcw -2(%esp) ; +; fldl doubl +; fistpl -12(%esp) ;store the round value +; fldcw -4(%esp) ;restore cw +; movl -12(%esp),%eax +; movw %ax,shor ; move the result into shor. + +;; but it is probably better to have a call, rather than waste this +;; space. The last instruction would have been a movl if were +;; going to an int instead of a short. +;; For the moment we will go with the soft float for these. + +/* These are incorrect since they don't set the rounding bits of CW flag. + The proper way to do that is to make the function prologue save the CW + and also construct the alternate CW value needed for these insns. + Then these insns can output two fldcw's, referring to fixed places in + the stack frame. + +;; Convert a float whose value is an integer +;; to an actual integer. Second stage of converting float to integer type. + +(define_insn "fix_truncsfqi2" + [(set (match_operand:QI 0 "general_operand" "=m,?*q") + (fix:QI (fix:SF (match_operand:SF 1 "general_operand" "f,f"))))] + "TARGET_80387" + "* +{ + fp_pop_int (operands[0]); + RET; +}") + +(define_insn "fix_truncsfhi2" + [(set (match_operand:HI 0 "general_operand" "=m,?*r") + (fix:HI (fix:SF (match_operand:SF 1 "general_operand" "f,f"))))] + "TARGET_80387" + "* +{ + fp_pop_int (operands[0]); + RET; +}") + +(define_insn "fix_truncsfsi2" + [(set (match_operand:SI 0 "general_operand" "=m,?*r") + (fix:SI (fix:SF (match_operand:SF 1 "general_operand" "f,f"))))] + "TARGET_80387" + "* +{ + fp_pop_int (operands[0]); + RET; +}") + +(define_insn "fix_truncdfqi2" + [(set (match_operand:QI 0 "general_operand" "=m,?*q") + (fix:QI (fix:DF (match_operand:DF 1 "general_operand" "f,f"))))] + + "TARGET_80387" + "* +{ + fp_pop_int (operands[0]); + RET; +}") + + +(define_insn "fix_truncdfhi2" + [(set (match_operand:HI 0 "general_operand" "=m,?*r") + (fix:HI (fix:DF (match_operand:DF 1 "general_operand" "f,f"))))] + "TARGET_80387" + "* +{ + fp_pop_int (operands[0]); + RET; +}") + + +(define_insn "fix_truncdfsi2" + [(set (match_operand:SI 0 "general_operand" "=m,?*r") + (fix:SI (fix:DF (match_operand:DF 1 "general_operand" "f,f"))))] + "TARGET_80387" + "* +{ + fp_pop_int (operands[0]); + RET; +}") +*/ + + +;;- add instructions +;;moved incl to above leal + +(define_insn "addsi3" + [(set (match_operand:SI 0 "general_operand" "=rm,r") + (plus:SI (match_operand:SI 1 "general_operand" "%0,0") + (match_operand:SI 2 "general_operand" "ri,rm")))] + "" + "add%L0 %2,%0") + +(define_insn "" + [(set (match_operand:HI 0 "general_operand" "=g") + (plus:HI (match_operand:HI 1 "general_operand" "0") + (const_int 1)))] + "" + "inc%W0 %0") + +(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")))] + "" + "add%W0 %2,%0") + +(define_insn "" + [(set (match_operand:QI 0 "general_operand" "=qm") + (plus:QI (match_operand:QI 1 "general_operand" "0") + (const_int 1)))] + "" + "inc%B0 %0") + +(define_insn "addqi3" + [(set (match_operand:QI 0 "general_operand" "=m,q") + (plus:QI (match_operand:QI 1 "general_operand" "%0,0") + (match_operand:QI 2 "general_operand" "qn,qmn")))] + "" + "add%B0 %2,%0") + +;;had "fmF,m" + +(define_insn "adddf3" + [(set (match_operand:DF 0 "general_operand" "=f,m,f") + (plus:DF (match_operand:DF 1 "general_operand" "%0,0,0") + (match_operand:DF 2 "general_operand" "m,!f,!*r")))] + "TARGET_80387" + "*FP_CALL (\"fadd%z0 %0\", \"fadd%z0 %0\", 2)") + +(define_insn "addsf3" + [(set (match_operand:SF 0 "general_operand" "=f,m,f") + (plus:SF (match_operand:SF 1 "general_operand" "%0,0,0") + (match_operand:SF 2 "general_operand" "m,!f,!*r")))] + "TARGET_80387" + "*FP_CALL (\"fadd%z0 %0\", \"fadd%z0 %0\", 2)") + +;;- subtract instructions + +;;moved decl above leal + +(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")))] + "" + "sub%L0 %2,%0") + +(define_insn "" + [(set (match_operand:HI 0 "general_operand" "=g") + (minus:HI (match_operand:HI 1 "general_operand" "0") + (const_int 1)))] + "" + "dec%W0 %0") + +(define_insn "subhi3" + [(set (match_operand:HI 0 "general_operand" "=rm,r") + (minus:HI (match_operand:HI 1 "general_operand" "0,0") + (match_operand:HI 2 "general_operand" "ri,rm")))] + "" + "sub%W0 %2,%0") + +(define_insn "" + [(set (match_operand:QI 0 "general_operand" "=qm") + (minus:QI (match_operand:QI 1 "general_operand" "0") + (const_int 1)))] + "" + "dec%B0 %0") + +(define_insn "subqi3" + [(set (match_operand:QI 0 "general_operand" "=m,q") + (minus:QI (match_operand:QI 1 "general_operand" "0,0") + (match_operand:QI 2 "general_operand" "qn,qmn")))] + "" + "sub%B0 %2,%0") + +(define_insn "subdf3" + [(set (match_operand:DF 0 "general_operand" "=f,m,f,f") + (minus:DF (match_operand:DF 1 "general_operand" "0,0,0,m") + (match_operand:DF 2 "general_operand" "m,!f,!*r,*0")))] + "TARGET_80387" + "*FP_CALL (\"fsub%z0 %0\", \"fsubr%z0 %0\", 2)") + + +(define_insn "subsf3" + [(set (match_operand:SF 0 "general_operand" "=f,m,f,f") + (minus:SF (match_operand:SF 1 "general_operand" "0,0,0,m") + (match_operand:SF 2 "general_operand" "m,!f,!*r,*0")))] + "TARGET_80387" + "*FP_CALL (\"fsub%z0 %0\", \"fsubr%z0 %0\", 2)") + +;;- 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")))] +; "" +; "mul%B0 %2,%0") + +(define_insn "mulhi3" + [(set (match_operand:HI 0 "general_operand" "=r,r") + (mult:SI (match_operand:HI 1 "general_operand" "%0,rm") + (match_operand:HI 2 "general_operand" "g,i")))] + "" + "* +{ + if (GET_CODE (operands[1]) == REG + && REGNO (operands[1]) == REGNO (operands[0]) + && (GET_CODE (operands[2]) == MEM + || GET_CODE (operands[2]) == REG)) + /* Assembler has weird restrictions. */ + return AS2 (imul%W0,%2,%0); + return AS3 (imul%W0,%2,%1,%0); +}") + +(define_insn "mulsi3" + [(set (match_operand:SI 0 "general_operand" "=r,r") + (mult:SI (match_operand:SI 1 "general_operand" "%0,rm") + (match_operand:SI 2 "general_operand" "g,i")))] + "" + "* +{ + if (GET_CODE (operands[1]) == REG + && REGNO (operands[1]) == REGNO (operands[0]) + && (GET_CODE (operands[2]) == MEM + || GET_CODE (operands[2]) == REG)) + /* Assembler has weird restrictions. */ + return AS2 (imul%L0,%2,%0); + return AS3 (imul%L0,%2,%1,%0); +}") + +;; Turned off due to possible assembler bug. +;(define_insn "umulqi3" +; [(set (match_operand:QI 0 "general_operand" "=a") +; (umult:QI (match_operand:QI 1 "general_operand" "%0") +; (match_operand:QI 2 "general_operand" "qm")))] +; "" +; "mul%B0 %2,%0") + +;(define_insn "umulqihi3" +; [(set (match_operand:HI 0 "general_operand" "=a") +; (umult:HI (match_operand:QI 1 "general_operand" "%0") +; (match_operand:QI 2 "general_operand" "qm")))] +; "" +; "mul%B0 %2,%0") + +(define_insn "umulhi3" + [(set (match_operand:HI 0 "general_operand" "=a") + (umult:SI (match_operand:HI 1 "general_operand" "%0") + (match_operand:HI 2 "general_operand" "rm"))) + (clobber (reg:HI 1))] + "" + "mul%W0 %2,%0") + +(define_insn "umulsi3" + [(set (match_operand:SI 0 "general_operand" "=a") + (umult:SI (match_operand:SI 1 "general_operand" "%0") + (match_operand:SI 2 "general_operand" "rm"))) + (clobber (reg:SI 1))] + "" + "mul%L0 %2,%0") + +(define_insn "muldf3" + [(set (match_operand:DF 0 "general_operand" "=f,m,f") + (mult:DF (match_operand:DF 1 "general_operand" "%0,0,0") + (match_operand:DF 2 "general_operand" "m,!f,!*r")))] + "TARGET_80387" + "*FP_CALL (\"fmul%z0 %0\", \"fmul%z0 %0\", 2) +") + +(define_insn "mulsf3" + [(set (match_operand:SF 0 "general_operand" "=f,m,f") + (mult:SF (match_operand:SF 1 "general_operand" "%0,0,0") + (match_operand:SF 2 "general_operand" "m,!f,!*r")))] + "TARGET_80387" + "*FP_CALL (\"fmul%z0 %0\", \"fmul%z0 %0\", 2) +") + +;;- divide instructions +(define_insn "divdf3" + [(set (match_operand:DF 0 "general_operand" "=f,m,f,f") + (div:DF (match_operand:DF 1 "general_operand" "0,0,0,m") + (match_operand:DF 2 "general_operand" "m,!f,!*r,*0")))] + "TARGET_80387" + "*FP_CALL (\"fdiv%z0 %0\", \"fdivr%z0 %0\", 2) +") + +(define_insn "divsf3" + [(set (match_operand:SF 0 "general_operand" "=f,m,f,f") + (div:SF (match_operand:SF 1 "general_operand" "0,0,0,m") + (match_operand:SF 2 "general_operand" "m,!f,!*r,*0")))] + "TARGET_80387" + "*FP_CALL (\"fdiv%z0 %0\", \"fdivr%z0 %0\", 2) +") + +;; Divide and Remainder instructions. + +;; Copy operands 1 and 2 to new registers, so that there's no +;; danger that put_var_into_stack will mess up the sharing match_dup needs. +;; CSE will get rid of the extra pseudo regs. +;; No problem if not optimizing, since then only `register' vars +;; will get pseudo regs, and they aren't allowed to have address taken. + +(define_expand "divmodsi4" + [(parallel [(set (match_operand:SI 0 "general_operand" "=a") + (div:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "rm"))) + (set (match_operand:SI 3 "general_operand" "=&d") + (mod:SI (match_dup 1) (match_dup 2)))])] + "" + " +{ + extern int optimize; + if (optimize) + { + if (GET_CODE (operands[1]) == REG && REG_USERVAR_P (operands[1])) + operands[1] = copy_to_mode_reg (SImode, operands[1]); + if (GET_CODE (operands[2]) == REG && REG_USERVAR_P (operands[2])) + operands[2] = copy_to_mode_reg (SImode, operands[2]); + } +}") + +(define_expand "udivmodsi4" + [(parallel [(set (match_operand:SI 0 "general_operand" "=a") + (udiv:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "rm"))) + (set (match_operand:SI 3 "general_operand" "=&d") + (umod:SI (match_dup 1) (match_dup 2)))])] + "" + " +{ + extern int optimize; + if (optimize) + { + if (GET_CODE (operands[1]) == REG && REG_USERVAR_P (operands[1])) + operands[1] = copy_to_mode_reg (SImode, operands[1]); + if (GET_CODE (operands[2]) == REG && REG_USERVAR_P (operands[2])) + operands[2] = copy_to_mode_reg (SImode, operands[2]); + } +}") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=a") + (div:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "rm"))) + (set (match_operand:SI 3 "general_operand" "=&d") + (mod:SI (match_dup 1) (match_dup 2)))] + "" + "cltd\;idiv%L0 %2") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=a") + (udiv:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "rm"))) + (set (match_operand:SI 3 "general_operand" "=&d") + (umod:SI (match_dup 1) (match_dup 2)))] + "" + "xor%L0 %3,%3\;div%L0 %2") + +/* +;;this should be a valid double division which we may want to add + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=a") + (udiv:DI (match_operand:DI 1 "general_operand" "a") + (match_operand:SI 2 "general_operand" "rm"))) + (set (match_operand:SI 3 "general_operand" "=d") + (umod:SI (match_dup 1) (match_dup 2)))] + "" + "div%L0 %2,%0") +*/ + +;;- and instructions + +;; 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. + +(define_insn "andsi3" + [(set (match_operand:SI 0 "general_operand" "=rm,r") + (and:SI (match_operand:SI 1 "general_operand" "%0,0") + (match_operand:SI 2 "general_operand" "ri,rm")))] + "" + "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") + (match_operand:HI 2 "general_operand" "ri,rm")))] + "" + "and%W0 %2,%0") + +(define_insn "andqi3" + [(set (match_operand:QI 0 "general_operand" "=m,q") + (and:QI (match_operand:QI 1 "general_operand" "%0,0") + (match_operand:QI 2 "general_operand" "qn,qmn")))] + "" + "and%B0 %2,%0") + +/* I am nervous about these two.. add them later.. +;I presume this means that we have something in say op0= eax which is small +;and we want to and it with memory so we can do this by just an +;andb m,%al and have success. +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=r") + (and:SI (zero_extend:SI (match_operand:HI 1 "general_operand" "rm")) + (match_operand:SI 2 "general_operand" "0")))] + "GET_CODE (operands[2]) == CONST_INT + && (unsigned int) INTVAL (operands[2]) < (1 << GET_MODE_BITSIZE (HImode))" + "and%W0 %1,%0") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=q") + (and:SI (zero_extend:SI (match_operand:QI 1 "general_operand" "qm")) + (match_operand:SI 2 "general_operand" "0")))] + "GET_CODE (operands[2]) == CONST_INT + && (unsigned int) INTVAL (operands[2]) < (1 << GET_MODE_BITSIZE (QImode))" + "and%L0 %1,%0") + +*/ + + + +;;- Bit set (inclusive or) instructions + +(define_insn "iorsi3" + [(set (match_operand:SI 0 "general_operand" "=rm,r") + (ior:SI (match_operand:SI 1 "general_operand" "%0,0") + (match_operand:SI 2 "general_operand" "ri,rm")))] + "" + "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") + (match_operand:HI 2 "general_operand" "ri,rm")))] + "" + "or%W0 %2,%0") + +(define_insn "iorqi3" + [(set (match_operand:QI 0 "general_operand" "=m,q") + (ior:QI (match_operand:QI 1 "general_operand" "%0,0") + (match_operand:QI 2 "general_operand" "qn,qmn")))] + "" + "or%B0 %2,%0") + +;;- xor instructions + +(define_insn "xorsi3" + [(set (match_operand:SI 0 "general_operand" "=rm,r") + (xor:SI (match_operand:SI 1 "general_operand" "%0,0") + (match_operand:SI 2 "general_operand" "ri,rm")))] + "" + "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") + (match_operand:HI 2 "general_operand" "ri,rm")))] + "" + "xor%W0 %2,%0") + +(define_insn "xorqi3" + [(set (match_operand:QI 0 "general_operand" "=qm") + (xor:QI (match_operand:QI 1 "general_operand" "%0") + (match_operand:QI 2 "general_operand" "qn")))] + "" + "xor%B0 %2,%0") + +;;- negation instructions +(define_insn "negsi2" + [(set (match_operand:SI 0 "general_operand" "=rm") + (neg:SI (match_operand:SI 1 "general_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")))] + "" + "neg%W0 %0") + +(define_insn "negqi2" + [(set (match_operand:QI 0 "general_operand" "=qm") + (neg:QI (match_operand:QI 1 "general_operand" "0")))] + "" + "neg%B0 %0") + +(define_insn "negsf2" + [(set (match_operand:SF 0 "general_operand" "=f,!m") + (neg:SF (match_operand:SF 1 "general_operand" "0,0")))] + "TARGET_80387" + "*FP_CALL1 (\"fchs\")") + +(define_insn "negdf2" + [(set (match_operand:DF 0 "general_operand" "=f,!m") + (neg:DF (match_operand:DF 1 "general_operand" "0,0")))] + "TARGET_80387" + "*FP_CALL1 (\"fchs\")") + +;; Absolute value instructions + +(define_insn "abssf2" + [(set (match_operand:SF 0 "general_operand" "=f,!m") + (abs:SF (match_operand:SF 1 "general_operand" "0,0")))] + "TARGET_80387" + "*FP_CALL1 (\"fabs\")") + +(define_insn "absdf2" + [(set (match_operand:DF 0 "general_operand" "=f,!m") + (abs:DF (match_operand:DF 1 "general_operand" "0,0")))] + "TARGET_80387" + "*FP_CALL1 (\"fabs\")") + +;;- one complement instructions +(define_insn "one_cmplsi2" + [(set (match_operand:SI 0 "general_operand" "=rm") + (not:SI (match_operand:SI 1 "general_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")))] + "" + "not%W0 %0") + +(define_insn "one_cmplqi2" + [(set (match_operand:QI 0 "general_operand" "=qm") + (not:QI (match_operand:QI 1 "general_operand" "0")))] + "" + "not%B0 %0") + +;;- arithmetic shift instructions + +(define_insn "ashlsi3" + [(set (match_operand:SI 0 "general_operand" "=rm") + (ashift:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "cI")))] + "" + "* +{ + if (REG_P (operands[2])) + return AS2 (sal%L0,%R0cl,%0); + else if (REG_P (operands[1]) && GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) == 1) + return AS2 (add%L0,%1,%1); + return AS2 (sal%L0,%2,%1); +}") + +(define_insn "ashlhi3" + [(set (match_operand:HI 0 "general_operand" "=rm") + (ashift:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "cI")))] + "" + "* +{ + if (REG_P (operands[2])) + return AS2 (sal%W0,%R0cl,%0); + else + return AS2 (sal%W0,%2,%1); +}") + +(define_insn "ashlqi3" + [(set (match_operand:QI 0 "general_operand" "=qm") + (ashift:QI (match_operand:QI 1 "general_operand" "0") + (match_operand:QI 2 "general_operand" "cI")))] + "" + "* +{ + if (REG_P (operands[2])) + return AS2 (sal%B0,%R0cl,%0); + else + return AS2 (sal%B0,%2,%1); +}") + +(define_insn "ashrsi3" + [(set (match_operand:SI 0 "general_operand" "=rm") + (ashiftrt:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "cI")))] + "" + "* +{ + if (REG_P (operands[2])) + return AS2 (sar%L0,%R0cl,%0); + else + return AS2 (sar%L0,%2,%0); +}") + +(define_insn "ashrhi3" + [(set (match_operand:HI 0 "general_operand" "=rm") + (ashiftrt:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "cI")))] + "" + "* +{ + if (REG_P (operands[2])) + return AS2 (sar%W0,%R0cl,%0); + else + return AS2 (sar%W0,%2,%0); +}") + +(define_insn "ashrqi3" + [(set (match_operand:QI 0 "general_operand" "=qm") + (ashiftrt:QI (match_operand:QI 1 "general_operand" "0") + (match_operand:QI 2 "general_operand" "cI")))] + "" + "* +{ + if (REG_P (operands[2])) + return AS2 (sar%B0,%R0cl,%0); + return + AS2 (sar%B0,%2,%1); +}") + +;;- logical shift instructions + +(define_insn "lshlsi3" + [(set (match_operand:SI 0 "general_operand" "=rm") + (lshift:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "cI")))] + "" + "* +{ + if (REG_P (operands[2])) + return AS2 (shl%L0,%R0cl,%0); + else + return AS2 (shl%L0,%2,%1); +}") + +(define_insn "lshlhi3" + [(set (match_operand:HI 0 "general_operand" "=rm") + (lshift:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "cI")))] + "" + "* +{ + if (REG_P (operands[2])) + return AS2 (shl%W0,%R0cl,%0); + else + return AS2 (shl%W0,%2,%1); +}") + +(define_insn "lshlqi3" + [(set (match_operand:QI 0 "general_operand" "=qm") + (lshift:QI (match_operand:QI 1 "general_operand" "0") + (match_operand:QI 2 "general_operand" "cI")))] + "" + "* +{ + if (REG_P (operands[2])) + return AS2 (shl%B0,%R0cl,%0); + else + return AS2 (shl%B0,%2,%1); +}") + +(define_insn "lshrsi3" + [(set (match_operand:SI 0 "general_operand" "=rm") + (lshiftrt:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "cI")))] + "" + "* +{ + if (REG_P (operands[2])) + return AS2 (shr%L0,%R0cl,%0); + else + return AS2 (shr%L0,%2,%1); +}") + +(define_insn "lshrhi3" + [(set (match_operand:HI 0 "general_operand" "=rm") + (lshiftrt:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "cI")))] + "" + "* +{ + if (REG_P (operands[2])) + return AS2 (shr%W0,%%cl,%0); + else + return AS2 (shr%W0,%2,%1); +}") + +(define_insn "lshrqi3" + [(set (match_operand:QI 0 "general_operand" "=qm") + (lshiftrt:QI (match_operand:QI 1 "general_operand" "0") + (match_operand:QI 2 "general_operand" "cI")))] + "" + "* +{ + if (REG_P (operands[2])) + return AS2 (shr%B0,%%cl,%0); + else + return AS2 (shr%B0,%2,%1); +}") + +;;- rotate instructions + +(define_insn "rotlsi3" + [(set (match_operand:SI 0 "general_operand" "=rm") + (rotate:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "cI")))] + "" + "* +{ + if (REG_P (operands[2])) + return AS2 (rol%L0,%%cl,%0); + else + return AS2 (rol%L0,%2,%1); +}") + +(define_insn "rotlhi3" + [(set (match_operand:HI 0 "general_operand" "=rm") + (rotate:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "cI")))] + "" + "* +{ + if (REG_P (operands[2])) + return AS2 (rol%W0,%%cl,%0); + else + return AS2 (rol%W0,%2,%1); +}") + +(define_insn "rotlqi3" + [(set (match_operand:QI 0 "general_operand" "=qm") + (rotate:QI (match_operand:QI 1 "general_operand" "0") + (match_operand:QI 2 "general_operand" "cI")))] + "" + "* +{ + if (REG_P (operands[2])) + return AS2 (rol%B0,%%cl,%0); + else + return AS2 (rol%B0,%2,%1); +}") + +(define_insn "rotrsi3" + [(set (match_operand:SI 0 "general_operand" "=rm") + (rotatert:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "cI")))] + "" + "* +{ + if (REG_P (operands[2])) + return AS2 (ror%L0,%%cl,%0); + else + return AS2 (ror%L0,%2,%1); +}") + +(define_insn "rotrhi3" + [(set (match_operand:HI 0 "general_operand" "=rm") + (rotatert:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "cI")))] + "" + "* +{ + if (REG_P (operands[2])) + return AS2 (ror%W0,%%cl,%0); + else + return AS2 (ror%W0,%2,%1); +}") + +(define_insn "rotrqi3" + [(set (match_operand:QI 0 "general_operand" "=qm") + (rotatert:QI (match_operand:QI 1 "general_operand" "0") + (match_operand:QI 2 "general_operand" "cI")))] + "" + "* +{ + if (REG_P (operands[2])) + return AS2 (ror%B0,%%cl,%0); + else + return AS2 (ror%B0,%2,%1); +}") + +;; Store-flag instructions. + +(define_insn "seq" + [(set (match_operand:QI 0 "general_operand" "=q") + (eq (cc0) (const_int 0)))] + "" + "* + cc_status = cc_prev_status; + return \"sete %0\"; +") + +(define_insn "sne" + [(set (match_operand:QI 0 "general_operand" "=q") + (ne (cc0) (const_int 0)))] + "" + "* + cc_status = cc_prev_status; + return \"setne %0\"; +") + +(define_insn "sgt" + [(set (match_operand:QI 0 "general_operand" "=q") + (gt (cc0) (const_int 0)))] + "" + "* + cc_status = cc_prev_status; + OUTPUT_JUMP (\"setg %0\", \"seta %0\", 0); +") + +(define_insn "sgtu" + [(set (match_operand:QI 0 "general_operand" "=q") + (gtu (cc0) (const_int 0)))] + "" + "* cc_status = cc_prev_status; + return \"seta %0\"; ") + +(define_insn "slt" + [(set (match_operand:QI 0 "general_operand" "=q") + (lt (cc0) (const_int 0)))] + "" + "* cc_status = cc_prev_status; + OUTPUT_JUMP (\"setl %0\", \"setb %0\", \"sets %0\"); ") + +(define_insn "sltu" + [(set (match_operand:QI 0 "general_operand" "=q") + (ltu (cc0) (const_int 0)))] + "" + "* cc_status = cc_prev_status; + return \"setb %0\"; ") + +(define_insn "sge" + [(set (match_operand:QI 0 "general_operand" "=q") + (ge (cc0) (const_int 0)))] + "" + "* cc_status = cc_prev_status; + OUTPUT_JUMP (\"setge %0\", \"setae %0\", \"setns %0\"); ") + +(define_insn "sgeu" + [(set (match_operand:QI 0 "general_operand" "=q") + (geu (cc0) (const_int 0)))] + "" + "* cc_status = cc_prev_status; + return \"setae %0\"; ") + +(define_insn "sle" + [(set (match_operand:QI 0 "general_operand" "=q") + (le (cc0) (const_int 0)))] + "" + "* + cc_status = cc_prev_status; + OUTPUT_JUMP (\"setle %0\", \"setbe %0\", 0); +") + +(define_insn "sleu" + [(set (match_operand:QI 0 "general_operand" "=q") + (leu (cc0) (const_int 0)))] + "" + "* cc_status = cc_prev_status; + return \"setbe %0\"; ") + +;; Basic conditional jump instructions. +;; We ignore the overflow flag for signed branch instructions. + +(define_insn "beq" + [(set (pc) + (if_then_else (eq (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "je %l0") + +(define_insn "bne" + [(set (pc) + (if_then_else (ne (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "jne %l0") + +(define_insn "bgt" + [(set (pc) + (if_then_else (gt (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "*OUTPUT_JUMP (\"jg %l0\", \"ja %l0\", 0)") + +(define_insn "bgtu" + [(set (pc) + (if_then_else (gtu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "ja %l0") + +;; There is no jump insn to check for `<' on IEEE floats. +;; Page 17-80 in the 80387 manual says jb, but that's wrong; +;; jb checks for `not >='. So swap the operands and do `>'. +(define_expand "blt" + [(set (pc) + (if_then_else (lt (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + " +{ + extern rtx sequence_stack; + rtx prev = XEXP (XEXP (sequence_stack, 1), 0); + rtx body = PATTERN (prev); + rtx comp; + if (GET_CODE (body) == SET) + comp = SET_SRC (body); + else + comp = SET_SRC (XVECEXP (body, 0, 0)); + + if (GET_CODE (comp) == COMPARE + ? GET_MODE_CLASS (GET_MODE (XEXP (comp, 0))) == MODE_FLOAT + : GET_MODE_CLASS (GET_MODE (comp)) == MODE_FLOAT) + { + if (GET_CODE (comp) == COMPARE) + { + rtx op0 = XEXP (comp, 0); + rtx op1 = XEXP (comp, 1); + XEXP (comp, 0) = op1; + XEXP (comp, 1) = op0; + } + else + { + rtx new = gen_rtx (COMPARE, VOIDmode, + CONST0_RTX (GET_MODE (comp)), comp); + if (GET_CODE (body) == SET) + SET_SRC (body) = new; + else + SET_SRC (XVECEXP (body, 0, 0)) = new; + } + emit_insn (gen_bgt (operands[0])); + DONE; + } +}") + +(define_insn "" + [(set (pc) + (if_then_else (lt (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "*OUTPUT_JUMP (\"jl %l0\", \"jb %l0\", \"js %l0\")") + +(define_insn "bltu" + [(set (pc) + (if_then_else (ltu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "jb %l0") + +(define_insn "bge" + [(set (pc) + (if_then_else (ge (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "*OUTPUT_JUMP (\"jge %l0\", \"jae %l0\", \"jns %l0\")") + +(define_insn "bgeu" + [(set (pc) + (if_then_else (geu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "jae %l0") + +;; See comment on `blt', above. +(define_expand "ble" + [(set (pc) + (if_then_else (le (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + " +{ + extern rtx sequence_stack; + rtx prev = XEXP (XEXP (sequence_stack, 1), 0); + rtx body = PATTERN (prev); + rtx comp; + if (GET_CODE (body) == SET) + comp = SET_SRC (body); + else + comp = SET_SRC (XVECEXP (body, 0, 0)); + + if (GET_CODE (comp) == COMPARE + ? GET_MODE_CLASS (GET_MODE (XEXP (comp, 0))) == MODE_FLOAT + : GET_MODE_CLASS (GET_MODE (comp)) == MODE_FLOAT) + { + if (GET_CODE (comp) == COMPARE) + { + rtx op0 = XEXP (comp, 0); + rtx op1 = XEXP (comp, 1); + XEXP (comp, 0) = op1; + XEXP (comp, 1) = op0; + } + else + { + rtx new = gen_rtx (COMPARE, VOIDmode, + CONST0_RTX (GET_MODE (comp)), comp); + if (GET_CODE (body) == SET) + SET_SRC (body) = new; + else + SET_SRC (XVECEXP (body, 0, 0)) = new; + } + emit_insn (gen_bge (operands[0])); + DONE; + } +}") + +(define_insn "" + [(set (pc) + (if_then_else (le (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "*OUTPUT_JUMP (\"jle %l0\", \"jbe %l0\", 0) ") + +(define_insn "bleu" + [(set (pc) + (if_then_else (leu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "jbe %l0") + +;; Negated conditional jump instructions. + +(define_insn "" + [(set (pc) + (if_then_else (eq (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "jne %l0") + +(define_insn "" + [(set (pc) + (if_then_else (ne (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "je %l0") + +(define_insn "" + [(set (pc) + (if_then_else (gt (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "*OUTPUT_JUMP (\"jle %l0\", \"jbe %l0\", 0) ") + +(define_insn "" + [(set (pc) + (if_then_else (gtu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "jbe %l0") + +(define_insn "" + [(set (pc) + (if_then_else (lt (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "*OUTPUT_JUMP (\"jge %l0\", \"jae %l0\", \"jns %l0\") +") + +(define_insn "" + [(set (pc) + (if_then_else (ltu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "jae %l0") + +(define_insn "" + [(set (pc) + (if_then_else (ge (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "*OUTPUT_JUMP (\"jl %l0\", \"jb %l0\", \"js %l0\")") + +(define_insn "" + [(set (pc) + (if_then_else (geu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "jb %l0") + +(define_insn "" + [(set (pc) + (if_then_else (le (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "*OUTPUT_JUMP (\"jg %l0\", \"ja %l0\", 0)") + +(define_insn "" + [(set (pc) + (if_then_else (leu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "ja %l0") + +;; Unconditional and other jump instructions +(define_insn "jump" + [(set (pc) + (label_ref (match_operand 0 "" "")))] + "" + "jmp %l0") + +(define_insn "tablejump" + [(set (pc) (match_operand:SI 0 "general_operand" "rm")) + (use (label_ref (match_operand 1 "" "")))] + "" + "* +{ + CC_STATUS_INIT; + + return \"jmp %*%0\"; +}") + +/* +(define_insn "" + [(set (pc) + (if_then_else + (ne (compare (minus:HI (match_operand:HI 0 "general_operand" "c") + (const_int 1)) + (const_int -1)) + (const_int 0)) + (label_ref (match_operand 1 "" "g")) + (pc))) + (set (match_dup 0) + (minus:HI (match_dup 0) + (const_int 1)))] + "" + "loop %l1") + +(define_insn "" + [(set (pc) + (if_then_else + (ne (compare (const_int -1) + (minus:SI (match_operand:SI 0 "general_operand" "c") + (const_int 1))) + (const_int 0)) + (label_ref (match_operand 1 "" "g")) + (pc))) + (set (match_dup 0) + (minus:SI (match_dup 0) + (const_int 1)))] + "" + "loop %l1") +*/ + +;; Call subroutine returning no value. +(define_insn "call" + [(call (match_operand:QI 0 "indirect_operand" "m") + (match_operand:SI 1 "general_operand" "g"))] + ;; Operand 1 not really used on the m68000. + "" + "* +{ + if (GET_CODE (operands[0]) == MEM + && ! CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) + { + operands[0] = XEXP (operands[0], 0); + return \"call %*%0\"; + } + else + return \"call %0\"; +}") + +;; Call subroutine, returning value in operand 0 +;; (which must be a hard register). +(define_insn "call_value" + [(set (match_operand 0 "" "=rf") + (call (match_operand:QI 1 "indirect_operand" "m") + (match_operand:SI 2 "general_operand" "g")))] + ;; Operand 2 not really used on the m68000. + "" + "* +{ + if (GET_CODE (operands[1]) == MEM + && ! CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) + { + operands[1] = XEXP (operands[1], 0); + output_asm_insn (\"call %*%1\", operands); + } + else + output_asm_insn (\"call %1\", operands); + + if (GET_MODE (operands[0]) == DFmode + || GET_MODE (operands[0]) == SFmode) + { +/* fp_pop_level++; */ + /* pop if reg dead */ + if (!FP_REG_P (operands[0])) + abort (); + if (top_dead_p (insn)) + { + POP_ONE_FP; + } + } + RET; +}") + +(define_insn "nop" + [(const_int 0)] + "" + "nop") + +;;- Local variables: +;;- mode:emacs-lisp +;;- comment-start: ";;- " +;;- eval: (set-syntax-table (copy-sequence (syntax-table))) +;;- eval: (modify-syntax-entry ?[ "(]") +;;- eval: (modify-syntax-entry ?] ")[") +;;- eval: (modify-syntax-entry ?{ "(}") +;;- eval: (modify-syntax-entry ?} "){") +;;- End: diff --git a/gcc-1.40/config/i860.md b/gcc-1.40/config/i860.md new file mode 100644 index 0000000..5752a58 --- /dev/null +++ b/gcc-1.40/config/i860.md @@ -0,0 +1,2046 @@ +;;- Machine description for Intel 860 chip for GNU C compiler +;; Copyright (C) 1989 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 1, 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. + + +;;- See file "rtl.def" for documentation on define_insn, match_*, et. al. + +;;- cpp macro #define NOTICE_UPDATE_CC in file tm.h handles condition code +;;- updates for most instructions. + +;;- Operand classes for the register allocator: + +/* Bit-test instructions. */ + +(define_insn "" + [(set (cc0) (eq (and:SI (match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "logic_operand" "rL")) + (const_int 0)))] + "" + "* +{ + cc_status.flags |= CC_ONLY_EQ; + return \"and %1,%0,r0\"; +}") + +(define_insn "" + [(set (cc0) (ne (and:SI (match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "logic_operand" "rL")) + (const_int 0)))] + "" + "* +{ + cc_status.flags |= CC_NEGATED; + cc_status.flags |= CC_ONLY_EQ; + return \"and %1,%0,r0\"; +}") + +(define_insn "" + [(set (cc0) (eq (and:SI (match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "immediate_operand" "i")) + (const_int 0)))] + "GET_CODE (operands[1]) == CONST_INT && (INTVAL (operands[1]) & 0xffff) == 0" + "* +{ + cc_status.flags |= CC_ONLY_EQ; + return \"andh h%%%1,%0,r0\"; +}") + +(define_insn "" + [(set (cc0) (ne (and:SI (match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "immediate_operand" "i")) + (const_int 0)))] + "GET_CODE (operands[1]) == CONST_INT && (INTVAL (operands[1]) & 0xffff) == 0" + "* +{ + cc_status.flags |= CC_NEGATED; + cc_status.flags |= CC_ONLY_EQ; + return \"andh h%%%1,%0,r0\"; +}") + +(define_insn "" + [(set (cc0) (eq (ashiftrt:SI + (sign_extend:SI + (ashift:QI (match_operand:QI 0 "register_operand" "r") + (match_operand:QI 1 "logic_int" "n"))) + (match_operand:SI 2 "logic_int" "n")) + (const_int 0)))] + "" + "* +{ + int width = 8 - INTVAL (operands[2]); + int pos = 8 - width - INTVAL (operands[1]); + operands[2] = gen_rtx (CONST_INT, VOIDmode, + ~((-1) << width) << pos); + return \"and %2,%0,r0\"; +}") + +;; Compare instructions. +;; This controls RTL generation and register allocation. + +;; Put cmpsi first among compare insns so it matches two CONST_INT operands. + +(define_insn "cmpeqsi" + [(set (cc0) (eq (match_operand:SI 0 "logic_operand" "r,rL") + (match_operand:SI 1 "logic_operand" "L,r")))] + "" + "* +{ + cc_status.flags &= ~ CC_CONDITION_MASK; + cc_status.flags |= CC_ONLY_EQ; + if (REG_P (operands[0])) + return \"xor %1,%0,r0\"; + return \"xor %0,%1,r0\"; +}") + +(define_insn "cmpltsi" + [(set (cc0) (lt (match_operand:SI 0 "arith_operand" "r,rI") + (match_operand:SI 1 "arith_operand" "I,r")))] + "" + "* +{ + cc_status.flags &= ~ CC_CONDITION_MASK; + cc_status.flags |= CC_ONLY_LT; + if (REG_P (operands[1])) + return \"subs %0,%1,r0\"; + cc_status.flags |= CC_REVERSED; + operands[1] = gen_rtx (CONST_INT, VOIDmode, - INTVAL (operands[1])); + return \"adds %1,%0,r0\"; +}") + +(define_insn "cmpgtsi" + [(set (cc0) (gt (match_operand:SI 0 "arith_operand" "r,rI") + (match_operand:SI 1 "arith_operand" "I,r")))] + "" + "* +{ + cc_status.flags &= ~ CC_CONDITION_MASK; + cc_status.flags |= CC_ONLY_LT; + if (REG_P (operands[0])) + return \"subs %1,%0,r0\"; + cc_status.flags |= CC_REVERSED; + operands[0] = gen_rtx (CONST_INT, VOIDmode, - INTVAL (operands[0])); + return \"adds %0,%1,r0\"; +}") + +(define_insn "cmpgeusi" + [(set (cc0) (geu (match_operand:SI 0 "arith_operand" "r,rI") + (match_operand:SI 1 "arith_operand" "I,r")))] + "" + "* +{ + cc_status.flags &= ~ CC_CONDITION_MASK; + cc_status.flags |= CC_ONLY_LEU; + if (REG_P (operands[1])) + return \"subu %0,%1,r0\"; + cc_status.flags |= CC_REVERSED; + operands[1] = gen_rtx (CONST_INT, VOIDmode, - INTVAL (operands[1])); + return \"addu %1,%0,r0\"; +}") + +(define_insn "cmpleusi" + [(set (cc0) (leu (match_operand:SI 0 "arith_operand" "r,rI") + (match_operand:SI 1 "arith_operand" "I,r")))] + "" + "* +{ + cc_status.flags &= ~ CC_CONDITION_MASK; + cc_status.flags |= CC_ONLY_LEU; + if (REG_P (operands[0])) + return \"subu %1,%0,r0\"; + cc_status.flags |= CC_REVERSED; + operands[0] = gen_rtx (CONST_INT, VOIDmode, - INTVAL (operands[0])); + return \"addu %0,%1,r0\"; +}") + +(define_insn "cmpeqsf" + [(set (cc0) (eq (match_operand:SF 0 "reg_or_0_operand" "fG") + (match_operand:SF 1 "reg_or_0_operand" "fG")))] + "" + "* +{ + cc_status.flags &= ~ CC_CONDITION_MASK; + cc_status.flags |= CC_ONLY_EQ; + return \"pfeq.ss %r1,%r0,f0\"; +}") + +(define_insn "cmpltsf" + [(set (cc0) (lt (match_operand:SF 0 "reg_or_0_operand" "fG") + (match_operand:SF 1 "reg_or_0_operand" "fG")))] + "" + "* +{ + cc_status.flags &= ~ CC_CONDITION_MASK; + cc_status.flags |= CC_ONLY_LT; + return \"pfgt.ss %r1,%r0,f0\"; +}") + +(define_insn "cmpgtsf" + [(set (cc0) (gt (match_operand:SF 0 "reg_or_0_operand" "fG") + (match_operand:SF 1 "reg_or_0_operand" "fG")))] + "" + "* +{ + cc_status.flags &= ~ CC_CONDITION_MASK; + cc_status.flags |= CC_ONLY_LT; + return \"pfgt.ss %r0,%r1,f0\"; +}") + +(define_insn "cmplesf" + [(set (cc0) (le (match_operand:SF 0 "reg_or_0_operand" "fG") + (match_operand:SF 1 "reg_or_0_operand" "fG")))] + "" + "* +{ + cc_status.flags &= ~ CC_CONDITION_MASK; + cc_status.flags |= CC_ONLY_LE; + return \"pfle.ss %r1,%r0,f0\"; +}") + +(define_insn "cmpgesf" + [(set (cc0) (ge (match_operand:SF 0 "reg_or_0_operand" "fG") + (match_operand:SF 1 "reg_or_0_operand" "fG")))] + "" + "* +{ + cc_status.flags &= ~ CC_CONDITION_MASK; + cc_status.flags |= CC_ONLY_LE; + return \"pfle.ss %r0,%r1,f0\"; +}") + +(define_insn "cmpeqdf" + [(set (cc0) (eq (match_operand:DF 0 "reg_or_0_operand" "fG") + (match_operand:DF 1 "reg_or_0_operand" "fG")))] + "" + "* +{ + cc_status.flags &= ~ CC_CONDITION_MASK; + cc_status.flags |= CC_ONLY_EQ; + return \"pfeq.dd %r1,%r0,f0\"; +}") + +(define_insn "cmpltdf" + [(set (cc0) (lt (match_operand:DF 0 "reg_or_0_operand" "fG") + (match_operand:DF 1 "reg_or_0_operand" "fG")))] + "" + "* +{ + cc_status.flags &= ~ CC_CONDITION_MASK; + cc_status.flags |= CC_ONLY_LT; + return \"pfgt.dd %r1,%r0,f0\"; +}") + +(define_insn "cmpgtdf" + [(set (cc0) (gt (match_operand:DF 0 "reg_or_0_operand" "fG") + (match_operand:DF 1 "reg_or_0_operand" "fG")))] + "" + "* +{ + cc_status.flags &= ~ CC_CONDITION_MASK; + cc_status.flags |= CC_ONLY_LT; + return \"pfgt.dd %r0,%r1,f0\"; +}") + +(define_insn "cmpledf" + [(set (cc0) (le (match_operand:DF 0 "reg_or_0_operand" "fG") + (match_operand:DF 1 "reg_or_0_operand" "fG")))] + "" + "* +{ + cc_status.flags &= ~ CC_CONDITION_MASK; + cc_status.flags |= CC_ONLY_LE; + return \"pfle.dd %r1,%r0,f0\"; +}") + +(define_insn "cmpgedf" + [(set (cc0) (ge (match_operand:DF 0 "reg_or_0_operand" "fG") + (match_operand:DF 1 "reg_or_0_operand" "fG")))] + "" + "* +{ + cc_status.flags &= ~ CC_CONDITION_MASK; + cc_status.flags |= CC_ONLY_LE; + return \"pfle.dd %r0,%r1,f0\"; +}") + +(define_insn "" + [(set (cc0) (eq (zero_extend:SI (match_operand:HI 0 "load_operand" "m")) + (match_operand:SI 1 "small_int" "I")))] + "INTVAL (operands[1]) >= 0" + "ld.s %0,r31\;xor %1,r31,r0") + +(define_insn "" + [(set (cc0) (eq (match_operand:SI 0 "small_int" "I") + (zero_extend:SI (match_operand:HI 1 "load_operand" "m"))))] + "INTVAL (operands[0]) >= 0" + "ld.s %1,r31\;xor %0,r31,r0") + +;; Define the real conditional branch instructions. + +(define_insn "cbranch" + [(set (pc) (if_then_else (cc0) (label_ref (match_operand 0 "" "")) (pc)))] + "" + "* +{ + if (cc_prev_status.flags & CC_NEGATED) + return \"bnc %l0\"; + else + return \"bc %l0\"; +}") + +(define_insn "inverse_cbranch" + [(set (pc) (if_then_else (cc0) (pc) (label_ref (match_operand 0 "" ""))))] + "" + "* +{ + if (cc_prev_status.flags & CC_NEGATED) + return \"bc %l0\"; + else + return \"bnc %l0\"; +}") + +;; Other conditional branches, made by combining. + +(define_insn "" + [(set (pc) (if_then_else (eq (match_operand:SI 0 "bte_operand" "%rK") + (match_operand:SI 1 "bte_operand" "rJ")) + (label_ref (match_operand 2 "" "")) + (pc)))] + "GET_CODE (operands[0]) == REG || GET_CODE (operands[1]) == REG" + "bte %0,%r1,%2") + +(define_insn "" + [(set (pc) (if_then_else (eq (match_operand:SI 0 "bte_operand" "%rK") + (match_operand:SI 1 "bte_operand" "rJ")) + (pc) + (label_ref (match_operand 2 "" ""))))] + "GET_CODE (operands[0]) == REG || GET_CODE (operands[1]) == REG" + "btne %0,%r1,%2") + +;; Optimize fetching an unsigned half word and comparing against constant. +;; No need to zero-extend. + +(define_insn "" + [(set (pc) (if_then_else (eq (zero_extend:SI (match_operand:HI 0 "load_operand" "m")) + (match_operand:SI 1 "immediate_operand" "K")) + (label_ref (match_operand 2 "" "")) + (pc)))] + "GET_CODE (operands[1]) == CONST_INT + && INTVAL (operands[1]) < 0x10 && INTVAL (operands[1]) >= 0" + "ld.s %0,r31\;bte %1,r31,%2") + +(define_insn "" + [(set (pc) (if_then_else (eq (match_operand:SI 0 "immediate_operand" "K") + (zero_extend:SI (match_operand:HI 1 "load_operand" "m"))) + (label_ref (match_operand 2 "" "")) + (pc)))] + "GET_CODE (operands[0]) == CONST_INT + && INTVAL (operands[0]) < 0x10 && INTVAL (operands[0]) >= 0" + "ld.s %1,r31\;bte %0,r31,%2") + +(define_insn "" + [(set (pc) (if_then_else (eq (zero_extend:SI (match_operand:HI 0 "load_operand" "m")) + (match_operand:SI 1 "immediate_operand" "K")) + (pc) + (label_ref (match_operand 2 "" ""))))] + "GET_CODE (operands[1]) == CONST_INT + && INTVAL (operands[1]) < 0x10 && INTVAL (operands[1]) >= 0" + "ld.s %0,r31\;btne %1,r31,%2") + +(define_insn "" + [(set (pc) (if_then_else (eq (match_operand:SI 0 "immediate_operand" "K") + (zero_extend:SI (match_operand:HI 1 "load_operand" "m"))) + (pc) + (label_ref (match_operand 2 "" ""))))] + "GET_CODE (operands[0]) == CONST_INT + && INTVAL (operands[0]) < 0x10 && INTVAL (operands[0]) >= 0" + "ld.s %1,r31\;btne %0,r31,%2") + +(define_insn "" + [(set (pc) (if_then_else (eq (zero_extend:SI (match_operand:QI 0 "load_operand" "m")) + (match_operand:SI 1 "immediate_operand" "K")) + (label_ref (match_operand 2 "" "")) + (pc)))] + "GET_CODE (operands[1]) == CONST_INT + && INTVAL (operands[1]) < 0x10 && INTVAL (operands[1]) >= 0" + "ld.b %0,r31\;bte %1,r31,%2") + +(define_insn "" + [(set (pc) (if_then_else (eq (match_operand:SI 0 "immediate_operand" "K") + (zero_extend:SI (match_operand:QI 1 "load_operand" "m"))) + (label_ref (match_operand 2 "" "")) + (pc)))] + "GET_CODE (operands[0]) == CONST_INT + && INTVAL (operands[0]) < 0x10 && INTVAL (operands[0]) >= 0" + "ld.b %1,r31\;bte %0,r31,%2") + +(define_insn "" + [(set (pc) (if_then_else (eq (zero_extend:SI (match_operand:QI 0 "load_operand" "m")) + (match_operand:SI 1 "immediate_operand" "K")) + (pc) + (label_ref (match_operand 2 "" ""))))] + "GET_CODE (operands[1]) == CONST_INT + && INTVAL (operands[1]) < 0x10 && INTVAL (operands[1]) >= 0" + "ld.b %0,r31\;btne %1,r31,%2") + +(define_insn "" + [(set (pc) (if_then_else (eq (match_operand:SI 0 "immediate_operand" "K") + (zero_extend:SI (match_operand:QI 1 "load_operand" "m"))) + (pc) + (label_ref (match_operand 2 "" ""))))] + "GET_CODE (operands[0]) == CONST_INT + && INTVAL (operands[0]) < 0x10 && INTVAL (operands[0]) >= 0" + "ld.b %1,r31\;btne %0,r31,%2") + +;; Generation of conditionals. + +;; The first step is the emission of a standard-looking compare insn. +;; Then a standard-named conditional branch pattern is run. +;; That branch pattern looks back at the compare insn and deletes it. +;; It then emits a machine-specific compare insn and a branch-if-true +;; or a branch-if-false. + +;; These patterns have `abort' because they are supposed to be deleted +;; in that fashion. + +(define_insn "cmpsi" + [(set (cc0) (compare (match_operand:SI 0 "compare_operand" "") + (match_operand:SI 1 "compare_operand" "")))] + "" + "* abort ();") + +(define_insn "cmpsf" + [(set (cc0) (compare (match_operand:SF 0 "register_operand" "") + (match_operand:SF 1 "register_operand" "")))] + "" + "* abort ();") + +(define_insn "cmpdf" + [(set (cc0) (compare (match_operand:DF 0 "register_operand" "") + (match_operand:DF 1 "register_operand" "")))] + "" + "* abort ();") + +;; These are the standard-named conditional branch patterns. +;; Detailed comments are found in the first one only. + +(define_expand "beq" + [(set (pc) + (if_then_else (eq (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + " +{ + rtx label = operands[0]; + enum insn_code code; + rtx prev; + + /* Get out of the sequence just started for us. */ + + end_sequence (); + prev = get_last_insn (); + + /* Examine the preceding compare insn, and get rid of it. */ + + code = recog_memoized (prev); + insn_extract (prev); + NEXT_INSN (PREV_INSN (prev)) = 0; + set_last_insn (PREV_INSN (prev)); + + /* Now once again start a sequence for our new instructions. */ + + start_sequence (); + + /* Emit a single-condition compare insn according to + the type of operands and the condition to be tested. */ + + if (code == CODE_FOR_cmpsi) + emit_insn (gen_cmpeqsi (recog_operand[0], recog_operand[1])); + else if (code == CODE_FOR_cmpsf) + emit_insn (gen_cmpeqsf (recog_operand[0], recog_operand[1])); + else if (code == CODE_FOR_cmpdf) + emit_insn (gen_cmpeqdf (recog_operand[0], recog_operand[1])); + else + abort (); + + /* Emit branch-if-true. */ + + emit_jump_insn (gen_cbranch (label)); + + DONE; +}") + +(define_expand "bne" + [(set (pc) + (if_then_else (ne (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + " +{ + rtx label = operands[0]; + enum insn_code code; + rtx prev; + + end_sequence (); + prev = get_last_insn (); + + code = recog_memoized (prev); + insn_extract (prev); + NEXT_INSN (PREV_INSN (prev)) = 0; + set_last_insn (PREV_INSN (prev)); + start_sequence (); + + if (code == CODE_FOR_cmpsi) + emit_insn (gen_cmpeqsi (recog_operand[0], recog_operand[1])); + else if (code == CODE_FOR_cmpsf) + emit_insn (gen_cmpeqsf (recog_operand[0], recog_operand[1])); + else if (code == CODE_FOR_cmpdf) + emit_insn (gen_cmpeqdf (recog_operand[0], recog_operand[1])); + else + abort (); + emit_jump_insn (gen_inverse_cbranch (label)); + + DONE; +}") + +(define_expand "bgt" + [(set (pc) + (if_then_else (gt (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + " +{ + rtx label = operands[0]; + enum insn_code code; + rtx prev; + + end_sequence (); + prev = get_last_insn (); + + code = recog_memoized (prev); + insn_extract (prev); + NEXT_INSN (PREV_INSN (prev)) = 0; + set_last_insn (PREV_INSN (prev)); + start_sequence (); + + if (code == CODE_FOR_cmpsi) + emit_insn (gen_cmpgtsi (recog_operand[0], recog_operand[1])); + else if (code == CODE_FOR_cmpsf) + emit_insn (gen_cmpgtsf (recog_operand[0], recog_operand[1])); + else if (code == CODE_FOR_cmpdf) + emit_insn (gen_cmpgtdf (recog_operand[0], recog_operand[1])); + else + abort (); + emit_jump_insn (gen_cbranch (label)); + DONE; +}") + +(define_expand "blt" + [(set (pc) + (if_then_else (lt (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + " +{ + rtx label = operands[0]; + enum insn_code code; + rtx prev; + + end_sequence (); + prev = get_last_insn (); + + code = recog_memoized (prev); + insn_extract (prev); + NEXT_INSN (PREV_INSN (prev)) = 0; + set_last_insn (PREV_INSN (prev)); + start_sequence (); + + if (code == CODE_FOR_cmpsi) + emit_insn (gen_cmpltsi (recog_operand[0], recog_operand[1])); + else if (code == CODE_FOR_cmpsf) + emit_insn (gen_cmpltsf (recog_operand[0], recog_operand[1])); + else if (code == CODE_FOR_cmpdf) + emit_insn (gen_cmpltdf (recog_operand[0], recog_operand[1])); + else + abort (); + emit_jump_insn (gen_cbranch (label)); + DONE; +}") + +(define_expand "ble" + [(set (pc) + (if_then_else (le (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + " +{ + rtx label = operands[0]; + enum insn_code code; + rtx prev; + + end_sequence (); + prev = get_last_insn (); + + code = recog_memoized (prev); + insn_extract (prev); + NEXT_INSN (PREV_INSN (prev)) = 0; + set_last_insn (PREV_INSN (prev)); + start_sequence (); + + if (code == CODE_FOR_cmpsi) + { + emit_insn (gen_cmpgtsi (recog_operand[0], recog_operand[1])); + emit_jump_insn (gen_inverse_cbranch (label)); + } + else + { + if (code == CODE_FOR_cmpsf) + emit_insn (gen_cmplesf (recog_operand[0], recog_operand[1])); + else if (code == CODE_FOR_cmpdf) + emit_insn (gen_cmpledf (recog_operand[0], recog_operand[1])); + else + abort (); + emit_jump_insn (gen_cbranch (label)); + } + DONE; +}") + +(define_expand "bge" + [(set (pc) + (if_then_else (ge (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + " +{ + rtx label = operands[0]; + enum insn_code code; + rtx prev; + + end_sequence (); + prev = get_last_insn (); + + code = recog_memoized (prev); + insn_extract (prev); + NEXT_INSN (PREV_INSN (prev)) = 0; + set_last_insn (PREV_INSN (prev)); + start_sequence (); + + if (code == CODE_FOR_cmpsi) + { + emit_insn (gen_cmpltsi (recog_operand[0], recog_operand[1])); + emit_jump_insn (gen_inverse_cbranch (label)); + } + else + { + if (code == CODE_FOR_cmpsf) + emit_insn (gen_cmpgesf (recog_operand[0], recog_operand[1])); + else if (code == CODE_FOR_cmpdf) + emit_insn (gen_cmpgedf (recog_operand[0], recog_operand[1])); + else + abort (); + emit_jump_insn (gen_cbranch (label)); + } + DONE; +}") + +(define_expand "bgtu" + [(set (pc) + (if_then_else (gtu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + " +{ + rtx label = operands[0]; + enum insn_code code; + rtx prev; + + end_sequence (); + prev = get_last_insn (); + + code = recog_memoized (prev); + insn_extract (prev); + NEXT_INSN (PREV_INSN (prev)) = 0; + set_last_insn (PREV_INSN (prev)); + start_sequence (); + + if (code == CODE_FOR_cmpsi) + emit_insn (gen_cmpleusi (recog_operand[0], recog_operand[1])); + else + abort (); + emit_jump_insn (gen_inverse_cbranch (label)); + DONE; +}") + +(define_expand "bltu" + [(set (pc) + (if_then_else (ltu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + " +{ + rtx label = operands[0]; + enum insn_code code; + rtx prev; + + end_sequence (); + prev = get_last_insn (); + + code = recog_memoized (prev); + insn_extract (prev); + NEXT_INSN (PREV_INSN (prev)) = 0; + set_last_insn (PREV_INSN (prev)); + start_sequence (); + + if (code == CODE_FOR_cmpsi) + emit_insn (gen_cmpgeusi (recog_operand[0], recog_operand[1])); + else + abort (); + emit_jump_insn (gen_inverse_cbranch (label)); + DONE; +}") + +(define_expand "bgeu" + [(set (pc) + (if_then_else (geu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + " +{ + rtx label = operands[0]; + enum insn_code code; + rtx prev; + + end_sequence (); + prev = get_last_insn (); + + code = recog_memoized (prev); + insn_extract (prev); + NEXT_INSN (PREV_INSN (prev)) = 0; + set_last_insn (PREV_INSN (prev)); + start_sequence (); + + if (code == CODE_FOR_cmpsi) + emit_insn (gen_cmpgeusi (recog_operand[0], recog_operand[1])); + else + abort (); + emit_jump_insn (gen_cbranch (label)); + DONE; +}") + +(define_expand "bleu" + [(set (pc) + (if_then_else (leu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + " +{ + rtx label = operands[0]; + enum insn_code code; + rtx prev; + + end_sequence (); + prev = get_last_insn (); + + code = recog_memoized (prev); + insn_extract (prev); + NEXT_INSN (PREV_INSN (prev)) = 0; + set_last_insn (PREV_INSN (prev)); + start_sequence (); + + if (code == CODE_FOR_cmpsi) + emit_insn (gen_cmpleusi (recog_operand[0], recog_operand[1])); + else + abort (); + emit_jump_insn (gen_cbranch (label)); + DONE; +}") + +;; Move instructions + +(define_insn "movsi" + [(set (match_operand:SI 0 "general_operand" "=r,m,f") + (match_operand:SI 1 "general_operand" "rmif,rfJ,rmfJ"))] + "" + "* +{ + if (GET_CODE (operands[0]) == MEM) + { + if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) + return output_store (operands); + if (FP_REG_P (operands[1])) + return \"fst.l %1,%0\"; + return \"st.l %r1,%0\"; + } + if (GET_CODE (operands[1]) == MEM) + { + if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) + return output_load (operands); + if (FP_REG_P (operands[0])) + return \"fld.l %1,%0\"; + return \"ld.l %1,%0\"; + } + if (FP_REG_P (operands[1]) && FP_REG_P (operands[0])) + return \"fmov.ss %1,%0\"; + if (FP_REG_P (operands[1])) + return \"fxfr %1,%0\"; + if (FP_REG_P (operands[0]) && operands[1] == const0_rtx) + return \"fmov.ss f0,%0\"; + if (FP_REG_P (operands[0])) + return \"ixfr %1,%0\"; + return \"mov %1,%0\"; +}") + +(define_insn "movhi" + [(set (match_operand:HI 0 "general_operand" "=r,m,!*f,!r") + (match_operand:HI 1 "general_operand" "rmi,rJ,rJ*f,*f"))] + "" + "* +{ + if (GET_CODE (operands[0]) == MEM) + { + if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) + return output_store (operands); + return \"st.s %r1,%0\"; + } + if (GET_CODE (operands[1]) == MEM) + { + if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) + return output_load (operands); + return \"ld.s %1,%0\"; + } + if (FP_REG_P (operands[1]) && FP_REG_P (operands[0])) + return \"fmov.ss %1,%0\"; + if (FP_REG_P (operands[1])) + return \"fxfr %1,%0\"; + if (FP_REG_P (operands[0]) && operands[1] == const0_rtx) + return \"fmov.ss f0,%0\"; + if (FP_REG_P (operands[0])) + return \"ixfr %1,%0\"; + return \"mov %1,%0\"; +}") + +(define_insn "movqi" + [(set (match_operand:QI 0 "general_operand" "=r,m,!*f,!r") + (match_operand:QI 1 "general_operand" "rmi,rJ,rJ*f,*f"))] + "" + "* +{ + if (GET_CODE (operands[0]) == MEM) + { + if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) + return output_store (operands); + return \"st.b %r1,%0\"; + } + if (GET_CODE (operands[1]) == MEM) + { + if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) + return output_load (operands); + return \"ld.b %1,%0\"; + } + if (FP_REG_P (operands[1]) && FP_REG_P (operands[0])) + return \"fmov.ss %1,%0\"; + if (FP_REG_P (operands[1])) + return \"fxfr %1,%0\"; + if (FP_REG_P (operands[0]) && operands[1] == const0_rtx) + return \"fmov.ss f0,%0\"; + if (FP_REG_P (operands[0])) + return \"ixfr %1,%0\"; + return \"mov %1,%0\"; +}") + +;; The definition of this insn does not really explain what it does, +;; but it should suffice +;; that anything generated as this insn will be recognized as one +;; and that it won't successfully combine with anything. +(define_expand "movstrsi" + [(parallel [(set (mem:BLK (match_operand:BLK 0 "general_operand" "")) + (mem:BLK (match_operand:BLK 1 "general_operand" ""))) + (use (match_operand:SI 2 "nonmemory_operand" "")) + (use (match_operand:SI 3 "immediate_operand" "")) + (clobber (match_dup 4)) + (clobber (match_dup 5)) + (clobber (match_dup 6)) + (clobber (match_dup 0)) + (clobber (match_dup 1))])] + "" + " +{ + operands[0] = copy_to_mode_reg (SImode, XEXP (operands[0], 0)); + operands[1] = copy_to_mode_reg (SImode, XEXP (operands[1], 0)); + operands[4] = gen_reg_rtx (SImode); + operands[5] = gen_reg_rtx (SImode); + operands[6] = gen_reg_rtx (SImode); +}") + +(define_insn "" + [(set (mem:BLK (match_operand:SI 0 "register_operand" "r")) + (mem:BLK (match_operand:SI 1 "register_operand" "r"))) + (use (match_operand:SI 2 "nonmemory_operand" "rn")) + (use (match_operand:SI 3 "immediate_operand" "i")) + (clobber (match_operand:SI 4 "register_operand" "=r")) + (clobber (match_operand:SI 5 "register_operand" "=r")) + (clobber (match_operand:SI 6 "register_operand" "=r")) + (clobber (match_dup 0)) + (clobber (match_dup 1))] + "" + "* return output_block_move (operands);") + +;; Floating point move insns + +;; 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 "" + [(set (match_operand:DF 0 "general_operand" "=r,f,o") + (match_operand:DF 1 "" "mG,m,G"))] + "GET_CODE (operands[1]) == CONST_DOUBLE" + "* +{ + if (FP_REG_P (operands[0])) + return output_fp_move_double (operands); + if (operands[1] == dconst0_rtx && GET_CODE (operands[0]) == REG) + { + operands[1] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); + return \"mov r0,%0\;mov r0,%1\"; + } + if (operands[1] == dconst0_rtx && GET_CODE (operands[0]) == MEM) + { + if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) + { + if (! ((cc_prev_status.flags & CC_KNOW_HI_R31) + && (cc_prev_status.flags & CC_HI_R31_ADJ) + && XEXP (operands[0], 0) == cc_prev_status.mdep)) + { + cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ; + cc_status.mdep = XEXP (operands[0], 0); + output_asm_insn (\"orh ha%%%m0,r0,r31\", operands); + } + return \"st.l r0,l%%%m0(r31)\;st.l r0,l%%%m0+4(r31)\"; + } + operands[1] = adj_offsettable_operand (operands[0], 4); + return \"st.l r0,%0\;st.l r0,%1\"; + } + return output_move_double (operands); +}") + +(define_insn "movdf" + [(set (match_operand:DF 0 "general_operand" "=*rm,&*r,?f,?*rm") + (match_operand:DF 1 "general_operand" "*r,m,*rfmG,f"))] + "" + "* +{ + if (GET_CODE (operands[0]) == MEM + && CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) + return output_store (operands); + if (GET_CODE (operands[1]) == MEM + && CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) + return output_load (operands); + + /* Note that the only CONST_DOUBLE that should be possible is 0. */ + if (FP_REG_P (operands[0]) || FP_REG_P (operands[1]) + || GET_CODE (operands[1]) == CONST_DOUBLE) + return output_fp_move_double (operands); + return output_move_double (operands); +}") + +(define_insn "movdi" + [(set (match_operand:DI 0 "general_operand" "=rm,&r,?f,?rm") + (match_operand:DI 1 "general_operand" "r,miF,rfmG,fG"))] + "" + "* +{ + if (GET_CODE (operands[0]) == MEM + && CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) + return output_store (operands); + if (GET_CODE (operands[1]) == MEM + && CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) + return output_load (operands); + + if (FP_REG_P (operands[0]) && operands[1] == dconst0_rtx) + return \"fmov.dd f0,%0\"; + + if (FP_REG_P (operands[0]) || FP_REG_P (operands[1])) + return output_fp_move_double (operands); + return output_move_double (operands); +}") + +;; The alternative m/r is separate from m/f +;; so that an f-reg won't be used as a reload reg between m and F. +;; The first alternative is separate from the second for the same reason. +(define_insn "movsf" + [(set (match_operand:SF 0 "general_operand" "=*rf,*rf,*r,m,m") + (match_operand:SF 1 "general_operand" "*r,fmG,F,*r,fG"))] + "" + "* +{ + if (GET_CODE (operands[0]) == MEM + && CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) + return output_store (operands); + if (GET_CODE (operands[1]) == MEM + && CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) + return output_load (operands); + if (FP_REG_P (operands[0])) + { + if (FP_REG_P (operands[1])) + return \"fmov.ss %1,%0\"; + if (GET_CODE (operands[1]) == REG) + return \"ixfr %1,%0\"; + if (operands[1] == fconst0_rtx) + return \"fmov.ss f0,%0\"; + if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) + { + cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ; + cc_status.mdep = XEXP (operands[1], 0); + return \"orh ha%%%m1,r0,r31\;fld.l l%%%m1(r31),%0\"; + } + return \"fld.l %1,%0\"; + } + if (FP_REG_P (operands[1]) || GET_CODE (operands[1]) == CONST_DOUBLE) + { + if (GET_CODE (operands[0]) == REG && FP_REG_P (operands[1])) + return \"fxfr %1,%0\"; + if (GET_CODE (operands[0]) == REG) + return \"mov %1,%0\"; + /* Now operand 0 must be memory. + If operand 1 is CONST_DOUBLE, its value must be 0. */ + if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) + { + if (! ((cc_prev_status.flags & CC_KNOW_HI_R31) + && (cc_prev_status.flags & CC_HI_R31_ADJ) + && XEXP (operands[0], 0) == cc_prev_status.mdep)) + { + cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ; + cc_status.mdep = XEXP (operands[0], 0); + output_asm_insn (\"orh ha%%%m0,r0,r31\", operands); + } + return \"fst.l %r1,l%%%m0(r31)\"; + } + return \"fst.l %r1,%0\"; + } + if (GET_CODE (operands[0]) == MEM) + return \"st.l %r1,%0\"; + if (GET_CODE (operands[1]) == MEM) + return \"ld.l %1,%0\"; + if (operands[1] == fconst0_rtx) + return \"mov r0,%0\"; + return \"mov %1,%0\"; +}") + +;; Special load insns for REG+REG addresses. +;; Such addresses are not "legitimate" because st rejects them. + +(define_insn "" + [(set (match_operand:DF 0 "register_operand" "=rf") + (match_operand:DF 1 "indexed_operand" "m"))] + "" + "* +{ + if (FP_REG_P (operands[0])) + return output_fp_move_double (operands); + return output_move_double (operands); +}") + +(define_insn "" + [(set (match_operand:SF 0 "register_operand" "=rf") + (match_operand:SF 1 "indexed_operand" "m"))] + "" + "* +{ + if (FP_REG_P (operands[0])) + return \"fld.l %1,%0\"; + return \"ld.l %1,%0\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=rf") + (match_operand:SI 1 "indexed_operand" "m"))] + "" + "* +{ + if (FP_REG_P (operands[0])) + return \"fld.l %1,%0\"; + return \"ld.l %1,%0\"; +}") + +(define_insn "" + [(set (match_operand:HI 0 "register_operand" "=r") + (match_operand:HI 1 "indexed_operand" "m"))] + "" + "ld.s %1,%0") + +(define_insn "" + [(set (match_operand:QI 0 "register_operand" "=r") + (match_operand:QI 1 "indexed_operand" "m"))] + "" + "ld.b %1,%0") + +;; Likewise for floating-point store insns. + +(define_insn "" + [(set (match_operand:DF 0 "indexed_operand" "=m") + (match_operand:DF 1 "register_operand" "f"))] + "" + "fst.d %1,%0") + +(define_insn "" + [(set (match_operand:SF 0 "indexed_operand" "=m") + (match_operand:SF 1 "register_operand" "f"))] + "" + "fst.l %1,%0") + +;;- truncation instructions +(define_insn "truncsiqi2" + [(set (match_operand:QI 0 "general_operand" "=g") + (truncate:QI + (match_operand:SI 1 "register_operand" "r")))] + "" + "* +{ + if (GET_CODE (operands[0]) == MEM) + if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) + { + if (! ((cc_prev_status.flags & CC_KNOW_HI_R31) + && (cc_prev_status.flags & CC_HI_R31_ADJ) + && XEXP (operands[0], 0) == cc_prev_status.mdep)) + { + cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ; + cc_status.mdep = XEXP (operands[0], 0); + output_asm_insn (\"orh ha%%%m0,r0,r31\", operands); + } + return \"st.b %1,l%%%m0(r31)\"; + } + else + return \"st.b %1,%0\"; + return \"mov %1,%0\"; +}") + +(define_insn "trunchiqi2" + [(set (match_operand:QI 0 "general_operand" "=g") + (truncate:QI + (match_operand:HI 1 "register_operand" "r")))] + "" + "* +{ + if (GET_CODE (operands[0]) == MEM) + if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) + { + if (! ((cc_prev_status.flags & CC_KNOW_HI_R31) + && (cc_prev_status.flags & CC_HI_R31_ADJ) + && XEXP (operands[0], 0) == cc_prev_status.mdep)) + { + cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ; + cc_status.mdep = XEXP (operands[0], 0); + output_asm_insn (\"orh ha%%%m0,r0,r31\", operands); + } + return \"st.b %1,l%%%m0(r31)\"; + } + else + return \"st.b %1,%0\"; + return \"mov %1,%0\"; +}") + +(define_insn "truncsihi2" + [(set (match_operand:HI 0 "general_operand" "=g") + (truncate:HI + (match_operand:SI 1 "register_operand" "r")))] + "" + "* +{ + if (GET_CODE (operands[0]) == MEM) + if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) + { + if (! ((cc_prev_status.flags & CC_KNOW_HI_R31) + && (cc_prev_status.flags & CC_HI_R31_ADJ) + && XEXP (operands[0], 0) == cc_prev_status.mdep)) + { + cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ; + cc_status.mdep = XEXP (operands[0], 0); + output_asm_insn (\"orh ha%%%m0,r0,r31\", operands); + } + return \"st.s %1,l%%%m0(r31)\"; + } + else + return \"st.s %1,%0\"; + return \"mov %1,%0\"; +}") + +;;- zero extension instructions + +;; Note that the one starting from HImode comes before those for QImode +;; so that a constant operand will match HImode, not QImode. + +(define_insn "zero_extendhisi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (zero_extend:SI + (match_operand:HI 1 "register_operand" "r")))] + "" + "and 0xffff,%1,%0") + +(define_insn "zero_extendqihi2" + [(set (match_operand:HI 0 "register_operand" "=r") + (zero_extend:HI + (match_operand:QI 1 "register_operand" "r")))] + "" + "and 0xff,%1,%0") + +(define_insn "zero_extendqisi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (zero_extend:SI + (match_operand:QI 1 "register_operand" "r")))] + "" + "and 0xff,%1,%0") + +;;- sign extension instructions +;; Note that the one starting from HImode comes before those for QImode +;; so that a constant operand will match HImode, not QImode. + +(define_insn "extendhisi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (sign_extend:SI + (match_operand:HI 1 "general_operand" "mr")))] + "" + "* +{ + if (REG_P (operands[1])) + return \"shl 16,%1,%0\;shra 16,%0,%0\"; + if (GET_CODE (operands[1]) == CONST_INT) + abort (); + if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) + { + cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ; + cc_status.mdep = XEXP (operands[1], 0); + return \"orh ha%%%m1,r0,r31\;ld.s l%%%m1(r31),%0\"; + } + else + return \"ld.s %1,%0\"; +}") + +(define_insn "extendqihi2" + [(set (match_operand:HI 0 "register_operand" "=r") + (sign_extend:HI + (match_operand:QI 1 "general_operand" "mr")))] + "" + "* +{ + if (REG_P (operands[1])) + return \"shl 24,%1,%0\;shra 24,%0,%0\"; + if (GET_CODE (operands[1]) == CONST_INT) + abort (); + if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) + { + cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ; + cc_status.mdep = XEXP (operands[1], 0); + return \"orh ha%%%m1,r0,r31\;ld.b l%%%m1(r31),%0\"; + } + else + return \"ld.b %1,%0\"; +}") + +(define_insn "extendqisi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (sign_extend:SI + (match_operand:QI 1 "general_operand" "mr")))] + "" + "* +{ + if (REG_P (operands[1])) + return \"shl 24,%1,%0\;shra 24,%0,%0\"; + if (GET_CODE (operands[1]) == CONST_INT) + abort (); + if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) + { + cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ; + cc_status.mdep = XEXP (operands[1], 0); + return \"orh ha%%%m1,r0,r31\;ld.b l%%%m1(r31),%0\"; + } + else + return \"ld.b %1,%0\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (sign_extend:SI + (match_operand:HI 1 "indexed_operand" "m")))] + "" + "ld.s %1,%0") + +(define_insn "" + [(set (match_operand:HI 0 "register_operand" "=r") + (sign_extend:HI + (match_operand:QI 1 "indexed_operand" "m")))] + "" + "ld.b %1,%0") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (sign_extend:SI + (match_operand:QI 1 "indexed_operand" "m")))] + "" + "ld.b %1,%0") + +;; Signed bitfield extractions come out looking like +;; (shiftrt (sign_extend (shift )) ) +;; which we expand poorly as four shift insns. +;; These patters yeild two shifts: +;; (shiftrt (shift ) ) +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (ashiftrt:SI + (sign_extend:SI + (match_operand:QI 1 "register_operand" "r")) + (match_operand:SI 2 "logic_int" "n")))] + "INTVAL (operands[2]) < 8" + "* +{ + return \"shl 24,%1,%0\;shra 24+%2,%0,%0\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (ashiftrt:SI + (sign_extend:SI + (subreg:QI (ashift:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "logic_int" "n")) 0)) + (match_operand:SI 3 "logic_int" "n")))] + "INTVAL (operands[3]) < 8" + "* +{ + return \"shl 0x18+%2,%1,%0\;shra 0x18+%3,%0,%0\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (ashiftrt:SI + (sign_extend:SI + (ashift:QI (match_operand:QI 1 "register_operand" "r") + (match_operand:QI 2 "logic_int" "n"))) + (match_operand:SI 3 "logic_int" "n")))] + "INTVAL (operands[3]) < 8" + "* +{ + return \"shl 0x18+%2,%1,%0\;shra 0x18+%3,%0,%0\"; +}") + +;; Special patterns for optimizing bit-field instructions. + +;; First two patterns are for bitfields that came from memory +;; testing only the high bit. They work with old combiner. + +(define_insn "" + [(set (cc0) + (eq (zero_extend:SI (subreg:QI (lshiftrt:SI (match_operand:SI 0 "register_operand" "r") + (const_int 7)) 0)) + (const_int 0)))] + "" + "and 128,%0,r0") + +(define_insn "" + [(set (cc0) + (eq (sign_extend:SI (subreg:QI (ashiftrt:SI (match_operand:SI 0 "register_operand" "r") + (const_int 7)) 0)) + (const_int 0)))] + "" + "and 128,%0,r0") + +;; next two patterns are good for bitfields coming from memory +;; (via pseudo-register) or from a register, though this optimization +;; is only good for values contained wholly within the bottom 13 bits +(define_insn "" + [(set (cc0) + (eq + (and:SI (lshiftrt:SI (match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "logic_int" "n")) + (match_operand:SI 2 "logic_int" "n")) + (const_int 0)))] + "LOGIC_INTVAL (INTVAL (operands[2]) << INTVAL (operands[1]))" + "* +{ + operands[2] = gen_rtx (CONST_INT, VOIDmode, + (INTVAL (operands[2]) << INTVAL (operands[1]))); + return \"and %2,%0,r0\"; +}") + +(define_insn "" + [(set (cc0) + (eq + (and:SI (ashiftrt:SI (match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "logic_int" "n")) + (match_operand:SI 2 "logic_int" "n")) + (const_int 0)))] + "LOGIC_INTVAL (INTVAL (operands[2]) << INTVAL (operands[1]))" + "* +{ + operands[2] = gen_rtx (CONST_INT, VOIDmode, + (INTVAL (operands[2]) << INTVAL (operands[1]))); + return \"and %2,%0,r0\"; +}") + +;; Conversions between float and double. + +(define_insn "extendsfdf2" + [(set (match_operand:DF 0 "register_operand" "=f") + (float_extend:DF + (match_operand:SF 1 "register_operand" "f")))] + "" + "fmov.sd %1,%0") + +(define_insn "truncdfsf2" + [(set (match_operand:SF 0 "register_operand" "=f") + (float_truncate:SF + (match_operand:DF 1 "register_operand" "f")))] + "" + "fmov.ds %1,%0") + +;; Conversion between fixed point and floating point. +;; Note that among the fix-to-float insns +;; the ones that start with SImode come first. +;; That is so that an operand that is a CONST_INT +;; (and therefore lacks a specific machine mode). +;; will be recognized as SImode (which is always valid) +;; rather than as QImode or HImode. + +(define_expand "floatsidf2" + [(set (match_dup 2) (match_dup 3)) + (set (match_dup 4) (xor:SI (match_operand:SI 1 "register_operand" "") + (const_int -2147483648))) + (set (subreg:SI (match_dup 5) 0) (match_dup 4)) + (set (subreg:SI (match_dup 5) 1) (subreg:SI (match_dup 2) 1)) + (set (match_operand:DF 0 "register_operand" "") + (minus:DF (match_dup 5) (match_dup 2)))] + "" + " +{ + /* Generate desired value, in float format of host machine. */ + double d = (double) (1 << 30) * ((double) (1 << 22) + (double) (1 << 1)); + operands[2] = gen_reg_rtx (DFmode); + operands[3] = immed_double_const (d, DFmode); + operands[4] = gen_reg_rtx (SImode); + operands[5] = gen_reg_rtx (DFmode); +}") + +;; Floating to fixed conversion. + +(define_expand "fix_truncdfsi2" + ;; This first insn produces a double-word value + ;; in which only the low word is valid. + [(set (match_dup 2) + (fix:DI (fix:DF (match_operand:DF 1 "register_operand" "f")))) + (set (match_operand:SI 0 "register_operand" "=f") + (subreg:SI (match_dup 2) 0))] + "" + " +{ + operands[2] = gen_reg_rtx (DImode); +}") + +;; Recognize the first insn generated above. +;; This RTL looks like a fix_truncdfdi2 insn, +;; but we dont call it that, because only 32 bits +;; of the result are valid. +;; This pattern will work for the intended purposes +;; as long as we do not have any fixdfdi2 or fix_truncdfdi2. +(define_insn "" + [(set (match_operand:DI 0 "register_operand" "=f") + (fix:DI (fix:DF (match_operand:DF 1 "register_operand" "f"))))] + "" + "ftrunc.dd %1,%0") + +(define_expand "fix_truncsfsi2" + ;; This first insn produces a double-word value + ;; in which only the low word is valid. + [(set (match_dup 2) + (fix:DI (fix:SF (match_operand:SF 1 "register_operand" "f")))) + (set (match_operand:SI 0 "register_operand" "=f") + (subreg:SI (match_dup 2) 0))] + "" + " +{ + operands[2] = gen_reg_rtx (DImode); +}") + +;; Recognize the first insn generated above. +;; This RTL looks like a fix_truncsfdi2 insn, +;; but we dont call it that, because only 32 bits +;; of the result are valid. +;; This pattern will work for the intended purposes +;; as long as we do not have any fixsfdi2 or fix_truncsfdi2. +(define_insn "" + [(set (match_operand:DI 0 "register_operand" "=f") + (fix:DI (fix:SF (match_operand:SF 1 "register_operand" "f"))))] + "" + "ftrunc.sd %1,%0") + +;;- arithmetic instructions + +(define_insn "addsi3" + [(set (match_operand:SI 0 "register_operand" "=r,*f") + (plus:SI (match_operand:SI 1 "nonmemory_operand" "%r,*f") + (match_operand:SI 2 "nonmemory_operand" "rn,*f")))] + "" + "* +{ + if (which_alternative == 1) + return \"fiadd.ss %2,%1,%0\"; + if (REG_P (operands[2])) + return \"addu %2,%1,%0\"; + if (SMALL_INT (operands[2])) + return \"addu %2,%1,%0\"; + cc_status.flags &= ~CC_KNOW_HI_R31; + return \"orh h%%%2,r0,r31\;or l%%%2,r31,r31\;addu %1,r31,%0\"; +}") + +(define_insn "adddi3" + [(set (match_operand:DI 0 "register_operand" "=f") + (plus:DI (match_operand:DI 1 "register_operand" "%f") + (match_operand:DI 2 "register_operand" "f")))] + "" + "fiadd.dd %1,%2,%0") + +(define_insn "subsi3" + [(set (match_operand:SI 0 "register_operand" "=r,r,*f") + (minus:SI (match_operand:SI 1 "register_operand" "r,I,*f") + (match_operand:SI 2 "nonmemory_operand" "rn,r,*f")))] + "" + "* +{ + if (which_alternative == 2) + return \"fisub.ss %1,%2,%0\"; + if (REG_P (operands[2])) + return \"subu %1,%2,%0\"; + if (SMALL_INT (operands[2]) && INTVAL (operands[2]) != -0x10000) + { + operands[2] = gen_rtx (CONST_INT, VOIDmode, - INTVAL (operands[2])); + return \"addu %2,%1,%0\"; + } + cc_status.flags &= ~CC_KNOW_HI_R31; + return \"orh h%%%2,r0,r31\;or l%%%2,r31,r31\;sub %1,r31,%0\"; +}") + +(define_insn "subdi3" + [(set (match_operand:DI 0 "register_operand" "=f") + (minus:DI (match_operand:DI 1 "register_operand" "%f") + (match_operand:DI 2 "register_operand" "f")))] + "" + "fisub.dd %1,%2,%0") + +(define_expand "mulsi3" + [(set (subreg:SI (match_dup 4) 0) (match_operand:SI 1 "general_operand" "")) + (set (subreg:SI (match_dup 5) 0) (match_operand:SI 2 "general_operand" "")) + (clobber (match_dup 3)) + (set (subreg:SI (match_dup 3) 0) + (mult:SI (subreg:SI (match_dup 4) 0) (subreg:SI (match_dup 5) 0))) + (set (match_operand:SI 0 "register_operand" "") (subreg:SI (match_dup 3) 0))] + "" + " +{ + operands[3] = gen_reg_rtx (DImode); + operands[4] = gen_reg_rtx (DImode); + operands[5] = gen_reg_rtx (DImode); +}") + +(define_insn "" + [(set (subreg:SI (match_operand:DI 0 "register_operand" "=f") 0) + (mult:SI (subreg:SI (match_operand:DI 1 "register_operand" "f") 0) + (subreg:SI (match_operand:DI 2 "register_operand" "f") 0)))] + "" + "fmlow.dd %2,%1,%0") + +;;- and instructions (with compliment also) +(define_insn "andsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (and:SI (match_operand:SI 1 "nonmemory_operand" "%r") + (match_operand:SI 2 "nonmemory_operand" "rn")))] + "" + "* +{ + rtx xop[3]; + + if (REG_P (operands[2]) || LOGIC_INT (operands[2])) + return \"and %2,%1,%0\"; + if ((INTVAL (operands[2]) & 0xffff) == 0) + { + operands[2] = gen_rtx (CONST_INT, VOIDmode, + (unsigned) INTVAL (operands[2]) >> 16); + return \"andh %2,%1,%0\"; + } + xop[0] = operands[0]; + xop[1] = operands[1]; + xop[2] = gen_rtx (CONST_INT, VOIDmode, ~INTVAL (operands[2]) & 0xffff); + output_asm_insn (\"andnot %2,%1,%0\", xop); + operands[2] = gen_rtx (CONST_INT, VOIDmode, + ~(unsigned) INTVAL (operands[2]) >> 16); + return \"andnoth %2,%0,%0\"; +}") + +(define_insn "andcbsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (and:SI (match_operand:SI 1 "register_operand" "r") + (not:SI (match_operand:SI 2 "register_operand" "rn"))))] + "" + "* +{ + rtx xop[3]; + + if (REG_P (operands[2]) || LOGIC_INT (operands[2])) + return \"andnot %2,%1,%0\"; + if ((INTVAL (operands[2]) & 0xffff) == 0) + { + operands[2] = gen_rtx (CONST_INT, VOIDmode, + (unsigned) INTVAL (operands[2]) >> 16); + return \"andnoth %2,%1,%0\"; + } + xop[0] = operands[0]; + xop[1] = operands[1]; + xop[2] = gen_rtx (CONST_INT, VOIDmode, (INTVAL (operands[2]) & 0xffff)); + output_asm_insn (\"andnot %2,%1,%0\", xop); + operands[2] = gen_rtx (CONST_INT, VOIDmode, + (unsigned) INTVAL (operands[2]) >> 16); + return \"andnoth %2,%0,%0\"; +}") + +(define_insn "iorsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (ior:SI (match_operand:SI 1 "nonmemory_operand" "%r") + (match_operand:SI 2 "nonmemory_operand" "rn")))] + "" + "* +{ + rtx xop[3]; + + if (REG_P (operands[2]) || LOGIC_INT (operands[2])) + return \"or %2,%1,%0\"; + if ((INTVAL (operands[2]) & 0xffff) == 0) + { + operands[2] = gen_rtx (CONST_INT, VOIDmode, + (unsigned) INTVAL (operands[2]) >> 16); + return \"orh %2,%1,%0\"; + } + xop[0] = operands[0]; + xop[1] = operands[1]; + xop[2] = gen_rtx (CONST_INT, VOIDmode, (INTVAL (operands[2]) & 0xffff)); + output_asm_insn (\"or %2,%1,%0\", xop); + operands[2] = gen_rtx (CONST_INT, VOIDmode, + (unsigned) INTVAL (operands[2]) >> 16); + return \"orh %2,%0,%0\"; +}") + +(define_insn "xorsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (xor:SI (match_operand:SI 1 "nonmemory_operand" "%r") + (match_operand:SI 2 "nonmemory_operand" "rn")))] + "" + "* +{ + rtx xop[3]; + + if (REG_P (operands[2]) || LOGIC_INT (operands[2])) + return \"xor %2,%1,%0\"; + if ((INTVAL (operands[2]) & 0xffff) == 0) + { + operands[2] = gen_rtx (CONST_INT, VOIDmode, + (unsigned) INTVAL (operands[2]) >> 16); + return \"xorh %2,%1,%0\"; + } + xop[0] = operands[0]; + xop[1] = operands[1]; + xop[2] = gen_rtx (CONST_INT, VOIDmode, (INTVAL (operands[2]) & 0xffff)); + output_asm_insn (\"xor %2,%1,%0\", xop); + operands[2] = gen_rtx (CONST_INT, VOIDmode, + (unsigned) INTVAL (operands[2]) >> 16); + return \"xorh %2,%0,%0\"; +}") + +(define_insn "negsi2" + [(set (match_operand:SI 0 "general_operand" "=r") + (neg:SI (match_operand:SI 1 "arith_operand" "rI")))] + "" + "subu r0,%1,%0") + +(define_insn "one_cmplsi2" + [(set (match_operand:SI 0 "general_operand" "=r") + (not:SI (match_operand:SI 1 "arith_operand" "r")))] + "" + "subu -1,%1,%0") + +;; Floating point arithmetic instructions. + +(define_insn "adddf3" + [(set (match_operand:DF 0 "register_operand" "=f") + (plus:DF (match_operand:DF 1 "register_operand" "f") + (match_operand:DF 2 "register_operand" "f")))] + "" + "fadd.dd %1,%2,%0") + +(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")))] + "" + "fadd.ss %1,%2,%0") + +(define_insn "subdf3" + [(set (match_operand:DF 0 "register_operand" "=f") + (minus:DF (match_operand:DF 1 "register_operand" "f") + (match_operand:DF 2 "register_operand" "f")))] + "" + "fsub.dd %1,%2,%0") + +(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")))] + "" + "fsub.ss %1,%2,%0") + +(define_insn "muldf3" + [(set (match_operand:DF 0 "register_operand" "=f") + (mult:DF (match_operand:DF 1 "register_operand" "f") + (match_operand:DF 2 "register_operand" "f")))] + "" + "fmul.dd %1,%2,%0") + +(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")))] + "" + "fmul.ss %1,%2,%0") + +(define_insn "negdf2" + [(set (match_operand:DF 0 "register_operand" "=f") + (neg:DF (match_operand:DF 1 "register_operand" "f")))] + "" + "fsub.dd f0,%1,%0") + +(define_insn "negsf2" + [(set (match_operand:SF 0 "register_operand" "=f") + (neg:SF (match_operand:SF 1 "register_operand" "f")))] + "" + "fsub.ss f0,%1,%0") + +;; Shift instructions + +;; Optimized special case of shifting. +;; Must precede the general case. + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (ashiftrt:SI (match_operand:SI 1 "memory_operand" "m") + (const_int 24)))] + "" + "* +{ + if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) + { + cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ; + cc_status.mdep = XEXP (operands[1], 0); + return \"orh ha%%%m1,r0,r31\;ld.b l%%%m1(r31),%0\"; + } + return \"ld.b %1,%0\"; +}") + + +;;- 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 "nonmemory_operand" "rn")))] + "" + "* +{ + if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) >= 32) + return \"mov r0,%0\"; + return \"shl %2,%1,%0\"; +}") + +(define_insn "ashlhi3" + [(set (match_operand:HI 0 "register_operand" "=r") + (ashift:HI (match_operand:HI 1 "register_operand" "r") + (match_operand:HI 2 "nonmemory_operand" "rn")))] + "" + "* +{ + if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) >= 16) + return \"mov r0,%0\"; + return \"shl %2,%1,%0\"; +}") + +(define_insn "ashlqi3" + [(set (match_operand:QI 0 "register_operand" "=r") + (ashift:QI (match_operand:QI 1 "register_operand" "r") + (match_operand:QI 2 "nonmemory_operand" "rn")))] + "" + "* +{ + if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) >= 8) + return \"mov r0,%0\"; + return \"shl %2,%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 "nonmemory_operand" "rn")))] + "" + "* +{ + if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) >= 32) + return \"shra 31,%1,%0\"; + return \"shra %2,%1,%0\"; +}") + +(define_insn "lshrsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (lshiftrt:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "nonmemory_operand" "rn")))] + "" + "* +{ + if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) >= 32) + return \"mov r0,%0\"; + return \"shr %2,%1,%0\"; +}") + +;; Unconditional and other jump instructions + +(define_insn "jump" + [(set (pc) (label_ref (match_operand 0 "" "")))] + "" + "* +{ + return \"br %l0\;nop\"; +}") + +;; Here are two simple peepholes which fill the delay slot of +;; an unconditional branch. + +(define_peephole + [(set (match_operand:SI 0 "register_operand" "=rf") + (match_operand:SI 1 "single_insn_src_p" "p")) + (set (pc) (label_ref (match_operand 2 "" "")))] + "" + "* return output_delayed_branch (\"br %l2\", operands, insn);") + +(define_peephole + [(set (match_operand:SI 0 "memory_operand" "=m") + (match_operand:SI 1 "reg_or_0_operand" "rfJ")) + (set (pc) (label_ref (match_operand 2 "" "")))] + "" + "* return output_delayed_branch (\"br %l2\", operands, insn);") + +(define_insn "tablejump" + [(set (pc) (match_operand:SI 0 "register_operand" "r")) + (use (label_ref (match_operand 1 "" "")))] + "" + "bri %0\;nop") + +(define_peephole + [(set (match_operand:SI 0 "memory_operand" "=m") + (match_operand:SI 1 "reg_or_0_operand" "rfJ")) + (set (pc) (match_operand:SI 2 "register_operand" "r")) + (use (label_ref (match_operand 3 "" "")))] + "" + "* return output_delayed_branch (\"bri %2\", operands, insn);") + +;;- jump to subroutine +(define_expand "call" + [(call (match_operand:SI 0 "memory_operand" "m") + (match_operand 1 "" "i"))] + ;; operand[2] is next_arg_register + "" + " +{ + if (INTVAL (operands[1]) > 0) + { + emit_move_insn (arg_pointer_rtx, stack_pointer_rtx); + emit_insn (gen_rtx (USE, VOIDmode, arg_pointer_rtx)); + } +}") + +;;- jump to subroutine +(define_insn "" + [(call (match_operand:SI 0 "memory_operand" "m") + (match_operand 1 "" "i"))] + ;; operand[2] is next_arg_register + "" + "* +{ + /* strip the MEM. */ + operands[0] = XEXP (operands[0], 0); + CC_STATUS_INIT; + if (GET_CODE (operands[0]) == REG) + return \"calli %0\;nop\"; + return \"call %0\;nop\"; +}") + +(define_peephole + [(set (match_operand:SI 0 "register_operand" "=rf") + (match_operand:SI 1 "single_insn_src_p" "p")) + (call (match_operand:SI 2 "memory_operand" "m") + (match_operand 3 "" "i"))] + ;;- Don't use operand 1 for most machines. + "! reg_mentioned_p (operands[0], operands[2])" + "* +{ + /* strip the MEM. */ + operands[2] = XEXP (operands[2], 0); + if (GET_CODE (operands[2]) == REG) + return output_delayed_branch (\"calli %2\", operands, insn); + return output_delayed_branch (\"call %2\", operands, insn); +}") + +(define_peephole + [(set (match_operand:SI 0 "memory_operand" "=m") + (match_operand:SI 1 "reg_or_0_operand" "rfJ")) + (call (match_operand:SI 2 "memory_operand" "m") + (match_operand 3 "" "i"))] + ;;- Don't use operand 1 for most machines. + "" + "* +{ + /* strip the MEM. */ + operands[2] = XEXP (operands[2], 0); + if (GET_CODE (operands[2]) == REG) + return output_delayed_branch (\"calli %2\", operands, insn); + return output_delayed_branch (\"call %2\", operands, insn); +}") + +(define_expand "call_value" + [(set (match_operand 0 "register_operand" "=rf") + (call (match_operand:SI 1 "memory_operand" "m") + (match_operand 2 "" "i")))] + ;; operand 3 is next_arg_register + "" + " +{ + if (INTVAL (operands[2]) > 0) + { + emit_move_insn (arg_pointer_rtx, stack_pointer_rtx); + emit_insn (gen_rtx (USE, VOIDmode, arg_pointer_rtx)); + } +}") + +(define_insn "" + [(set (match_operand 0 "register_operand" "=rf") + (call (match_operand:SI 1 "memory_operand" "m") + (match_operand 2 "" "i")))] + ;; operand 3 is next_arg_register + "" + "* +{ + /* strip the MEM. */ + operands[1] = XEXP (operands[1], 0); + CC_STATUS_INIT; + if (GET_CODE (operands[1]) == REG) + return \"calli %1\;nop\"; + return \"call %1\;nop\"; +}") + +(define_peephole + [(set (match_operand:SI 0 "register_operand" "=rf") + (match_operand:SI 1 "single_insn_src_p" "p")) + (set (match_operand 2 "" "=rf") + (call (match_operand:SI 3 "memory_operand" "m") + (match_operand 4 "" "i")))] + ;;- Don't use operand 4 for most machines. + "! reg_mentioned_p (operands[0], operands[3])" + "* +{ + /* strip the MEM. */ + operands[3] = XEXP (operands[3], 0); + if (GET_CODE (operands[3]) == REG) + return output_delayed_branch (\"calli %3\", operands, insn); + return output_delayed_branch (\"call %3\", operands, insn); +}") + +(define_peephole + [(set (match_operand:SI 0 "memory_operand" "=m") + (match_operand:SI 1 "reg_or_0_operand" "rJf")) + (set (match_operand 2 "" "=rf") + (call (match_operand:SI 3 "memory_operand" "m") + (match_operand 4 "" "i")))] + ;;- Don't use operand 4 for most machines. + "" + "* +{ + /* strip the MEM. */ + operands[3] = XEXP (operands[3], 0); + if (GET_CODE (operands[3]) == REG) + return output_delayed_branch (\"calli %3\", operands, insn); + return output_delayed_branch (\"call %3\", operands, insn); +}") + +(define_insn "nop" + [(const_int 0)] + "" + "nop") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (mem:SI (plus:SI (match_operand:SI 1 "register_operand" "r") + (label_ref (match_operand 2 "" "")))))] + "" + "* +{ + cc_status.flags = 0; + return \"mov %l2,r31\;ld.l r31(%1),%0\"; +}") + +(define_peephole + [(set (match_operand:SI 0 "register_operand" "=rf") + (match_operand:SI 1 "single_insn_src_p" "p")) + (set (pc) (match_operand:SI 2 "register_operand" "r")) + (use (label_ref (match_operand 3 "" "")))] + "REGNO (operands[0]) != REGNO (operands[2])" + "* return output_delayed_branch (\"bri %2\", operands, insn);") + +;;- Local variables: +;;- mode:emacs-lisp +;;- comment-start: ";;- " +;;- eval: (set-syntax-table (copy-sequence (syntax-table))) +;;- eval: (modify-syntax-entry ?[ "(]") +;;- eval: (modify-syntax-entry ?] ")[") +;;- eval: (modify-syntax-entry ?{ "(}") +;;- eval: (modify-syntax-entry ?} "){") +;;- End: + diff --git a/gcc-1.40/config/m68k.md b/gcc-1.40/config/m68k.md new file mode 100644 index 0000000..c241ab4 --- /dev/null +++ b/gcc-1.40/config/m68k.md @@ -0,0 +1,4156 @@ +;;- Machine description for GNU compiler +;;- Motorola 68000 Version +;; Copyright (C) 1987, 1988 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 1, 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. + + +;;- instruction definitions + +;;- @@The original PO technology requires these to be ordered by speed, +;;- @@ so that assigner will pick the fastest. + +;;- See file "rtl.def" for documentation on define_insn, match_*, et. al. + +;;- When naming insn's (operand 0 of define_insn) be careful about using +;;- names from other targets machine descriptions. + +;;- cpp macro #define NOTICE_UPDATE_CC in file tm.h handles condition code +;;- updates for most instructions. + +;;- Operand classes for the register allocator: +;;- 'a' one of the address registers can be used. +;;- 'd' one of the data registers can be used. +;;- 'f' one of the m68881 registers can be used +;;- 'r' either a data or an address register can be used. +;;- 'x' if one of the Sun FPA registers +;;- 'y' if one of the Low Sun FPA registers (fpa0-fpa15). + +;;- Immediate Floating point operator constraints +;;- 'G' a floating point constant that is *NOT* one of the standard +;; 68881 constant values (to force calling output_move_const_double +;; to get it from rom if it is a 68881 constant). +;;- 'H' one of the standard FPA constant values +;; +;; See the functions standard_XXX_constant_p in output-m68k.c for more +;; info. + +;;- Immediate integer operand constraints: +;;- 'I' 1 .. 8 +;;- 'J' -32768 .. 32767 +;;- 'K' -128 .. 127 +;;- 'L' -8 .. -1 + +;;- FPA port explanation: + +;;- Usage of the Sun FPA and the 68881 together + +;;- The current port of gcc to the sun fpa disallows use of the m68881 +;;- instructions completely if code is targetted for the fpa. This is +;;- for the following reasons: + +;;- 1) Expressing the preference hierarchy (ie. use the fpa if you +;;- can, the 68881 otherwise, and data registers only if you are +;;- forced to it) is a bitch with the current constraint scheme, +;;- especially since it would have to work for any combination of +;;- -mfpa, -m68881. + +;;- 2) There are no instructions to move between the two types of +;;- registers; the stack must be used as an intermediary. + +;;- It could indeed be done; I think the best way would be to have +;;- seperate patterns for TARGET_FPA (which implies a 68881), +;;- TARGET_68881, and no floating point co-processor. Use +;;- define_expands for all of the named instruction patterns, and +;;- include code in the FPA instruction to deal with the 68881 with +;;- preferences specifically set to favor the fpa. Some of this has +;;- already been done: +;;- +;;- 1) Separation of most of the patterns out into a TARGET_FPA +;;- case and a TARGET_68881 case (the exceptions are the patterns +;;- which would need one define_expand and three define_insn's under +;;- it (with alot of duplicate code between them) to replace the +;;- current single define_insn. These are mov{[ds]f,[ds]i} and the +;;- first two patterns in the md. +;;- +;;- Some would still have to be done: +;;- +;;- 1) Add code to the fpa patterns which correspond to 68881 +;;- patterns to deal with the 68881 case (including preferences!). +;;- What you might actually do here is combine the fpa and 68881 code +;;- back together into one pattern for those instructions where it's +;;- absolutely necessary and save yourself some duplicate code. I'm +;;- not completely sure as to whether you could get away with doing +;;- this only for the mov* insns, or if you'd have to do it for all +;;- named insns. +;;- 2) Add code to the mov{[ds]f,[ds]i} instructions to handle +;;- moving between fpa regs and 68881 regs. + +;;- Since the fpa is more powerful than the 68881 and also has more +;;- registers, and since I think the reultant md would be medium ugly +;;- (lot's of duplicate code, ugly constraint strings), I elected not +;;- to do this change. + +;;- Another reason why someone *might* want to do the change is to +;;- control which register classes are accessed in a slightly cleaner +;;- way than I have. See the blurb on CONDITIONAL_REGISTER_USAGE in +;;- the internals manual. + +;;- Yet another reason why someone might want to do this change is to +;;- allow use of some of the 68881 insns which have no equivalent on +;;- the fpa. The sqrt instruction comes fairly quickly to mind. + +;;- If this is ever done, don't forget to change tm-sun3.h so that +;;- it *will* define __HAVE_68881__ when the FPA is in use. + +;;- Condition code hack + +;;- When a floating point compare is done in the fpa, the resulting +;;- condition codes are left in the fpastatus register. The values in +;;- this register must be moved into the 68000 cc register before any +;;- jump is executed. Once this has been done, regular jump +;;- instructions are fine (ie. floating point jumps are not necessary. +;;- They are only done if the cc is in the 68881). + +;;- The instructions that move the fpastatus register to the 68000 +;;- register clobber a data register (the move cannot be done direct). +;;- These instructions might be bundled either with the compare +;;- instruction, or the branch instruction. If we were using both the +;;- fpa and the 68881 together, we would wish to only mark the +;;- register clobbered if we were doing the compare in the fpa, but I +;;- think that that decision (whether to clobber the register or not) +;;- must be done before register allocation (makes sense) and hence we +;;- can't know if the floating point compare will be done in the fpa +;;- or the fp. So whenever we are asked for code that uses the fpa, +;;- we will mark a data register as clobbered. This is reasonable, as +;;- almost all floating point compare operations done with fpa code +;;- enabled will be done in the fpa. It's even more reasonable since +;;- we decided to make the 68881 and the fpa mutually exclusive. + +;;- We place to code to move the fpastatus register inside of a +;;- define_expand so that we can do it conditionally based on whether +;;- we are tagetting an fpa or not. + +;;- This still leaves us with the question of where we wish to put the +;;- code to move the fpastatus reg. If we put it in the compare +;;- instruction, we can restrict the clobbering of the register to +;;- floating point compares, but we can't take advantage of floating +;;- point subtracts & etc. that alter the fpastatus register. If we +;;- put it in the branch instruction, all branches compiled with fpa +;;- code enabled will clobber a data register, but we will be able to +;;- take advantage of fpa subtracts. This balance favors putting the +;;- code in with the compare instruction. + +;;- Note that if some enterprising hacker should decide to switch +;;- this, he'll need to modify the code in NOTICE_UPDATE_CC. + +;;- Usage of the top 16 fpa registers + +;;- The only locations which we may transfer fpa registers 16-31 from +;;- or to are the fpa registers 0-15. (68000 registers and memory +;;- locations are impossible). This causes problems in gcc, which +;;- assumes that mov?? instructions require no additional registers +;;- (see section 11.7) and since floating point moves *must* be +;;- supported into general registers (see section 12.3 under +;;- HARD_REGNO_OK_FOR_MODE_P) from anywhere. + +;;- My solution was to reserve fpa0 for moves into or out of these top +;;- 16 registers and to disparage the choice to reload into or out of +;;- these registers as much as I could. That alternative is always +;;- last in the list, so it will not be used unless all else fails. I +;;- will note that according to my current information, sun's compiler +;;- doesn't use these top 16 registers at all. + +;;- There is another possible way to do it. I *believe* that if you +;;- make absolutely sure that the code will not be exectued in the +;;- reload pass, you can support the mov?? names with define_expands +;;- which require new registers. This may be possible by the +;;- appropriate juggling of constraints. I may come back to this later. + +;;- Usage of constant RAM + +;;- This has been handled correctly (I believe) but the way I've done +;;- it could use a little explanation. The constant RAM can only be +;;- accessed when the instruction is in "command register" mode. +;;- "command register" mode means that no accessing of memory or the +;;- 68000 registers is being done. This can be expressed easily in +;;- constraints, so generally the mode of the instruction is +;;- determined by a branch off of which_alternative. In outputing +;;- instructions, a 'w' means to output an access to the constant ram +;;- (if the arg is CONST_DOUBLE and is one of the available +;;- constants), and 'x' means to output a register pair (if the arg is +;;- a 68000 register) and a 'y' is the combination of the above two +;;- processies. You use a 'y' in two operand DF instructions where you +;;- *know* the other operand is an fpa register, you use an 'x' in DF +;;- instructions where the arg might be a 68000 register and the +;;- instruction is *not* in "command register" mode, and you use a 'w' +;;- in two situations: 1) The instruction *is* in command register +;;- mode (and hence won't be accessing 68000 registers), or 2) The +;;- instruction is a two operand SF instruction where you know the +;;- other operand is an fpa register. + +;;- Optimization issues + +;;- I actually think that I've included all of the fpa instructions +;;- that should be included. Note that if someone is interested in +;;- doing serious floating point work on the sun fpa, I would advise +;;- the use of the "asm" instruction in gcc to allow you to use the +;;- sin, cos, and exponential functions on the fpa board. + +;;- END FPA Explanation Section. + + +;;- Some of these insn's are composites of several m68000 op codes. +;;- The assembler (or final @@??) insures that the appropriate one is +;;- selected. + +(define_insn "" + [(set (match_operand:DF 0 "push_operand" "=m") + (match_operand:DF 1 "general_operand" "ro<>fyF"))] + "" + "* +{ + if (FP_REG_P (operands[1])) + return \"fmove%.d %f1,%0\"; + if (FPA_REG_P (operands[1])) + return \"fpmove%.d %1, %x0\"; + return output_move_double (operands); +}") + +(define_insn "" + [(set (match_operand:DI 0 "push_operand" "=m") + (match_operand:DI 1 "general_operand" "ro<>Fy"))] + "" + "* +{ + return output_move_double (operands); +}") + +;; Put tstsi first among test insns so it matches a CONST_INT operand. + +(define_insn "tstsi" + [(set (cc0) + (match_operand:SI 0 "general_operand" "rm"))] + "" + "* +{ +#ifdef ISI_OV + /* ISI's assembler fails to handle tstl a0. */ + if (! ADDRESS_REG_P (operands[0])) +#else + if (TARGET_68020 || ! ADDRESS_REG_P (operands[0])) +#endif + return \"tst%.l %0\"; + /* If you think that the 68020 does not support tstl a0, + reread page B-167 of the 68020 manual more carefully. */ + /* On an address reg, cmpw may replace cmpl. */ +#ifdef HPUX_ASM + return \"cmp%.w %0,%#0\"; +#else + return \"cmp%.w %#0,%0\"; +#endif +}") + +(define_insn "tsthi" + [(set (cc0) + (match_operand:HI 0 "general_operand" "rm"))] + "" + "* +{ +#ifdef ISI_OV + if (! ADDRESS_REG_P (operands[0])) +#else + if (TARGET_68020 || ! ADDRESS_REG_P (operands[0])) +#endif + return \"tst%.w %0\"; +#ifdef HPUX_ASM + return \"cmp%.w %0,%#0\"; +#else + return \"cmp%.w %#0,%0\"; +#endif +}") + +(define_insn "tstqi" + [(set (cc0) + (match_operand:QI 0 "general_operand" "dm"))] + "" + "tst%.b %0") + +(define_expand "tstsf" + [(set (cc0) + (match_operand:SF 0 "general_operand" ""))] + "TARGET_68881 || TARGET_FPA" + " +{ + if (TARGET_FPA) + { + emit_insn (gen_rtx (PARALLEL, VOIDmode, + gen_rtvec (2, + gen_rtx (SET, VOIDmode, + cc0_rtx, operands[0]), + gen_rtx (CLOBBER, VOIDmode, + gen_reg_rtx (SImode))))); + DONE; + } +}") + +(define_insn "" + [(set (cc0) + (match_operand:SF 0 "general_operand" "xmdF")) + (clobber (match_operand:SI 1 "general_operand" "d"))] + "TARGET_FPA" + "fptst%.s %x0\;fpmove fpastatus,%1\;movw %1,cc") + +(define_insn "" + [(set (cc0) + (match_operand:SF 0 "general_operand" "fdm"))] + "TARGET_68881" + "* +{ + cc_status.flags = CC_IN_68881; + if (FP_REG_P (operands[0])) + return \"ftst%.x %0\"; + return \"ftst%.s %0\"; +}") + +(define_expand "tstdf" + [(set (cc0) + (match_operand:DF 0 "general_operand" ""))] + "TARGET_68881 || TARGET_FPA" + " +{ + if (TARGET_FPA) + { + emit_insn (gen_rtx (PARALLEL, VOIDmode, + gen_rtvec (2, gen_rtx (SET, VOIDmode, + cc0_rtx, operands[0]), + gen_rtx (CLOBBER, VOIDmode, + gen_reg_rtx (SImode))))); + DONE; + } +}") + +(define_insn "" + [(set (cc0) + (match_operand:DF 0 "general_operand" "xrmF")) + (clobber (match_operand:SI 1 "general_operand" "d"))] + "TARGET_FPA" + "fptst%.d %x0\;fpmove fpastatus,%1\;movw %1,cc") + +(define_insn "" + [(set (cc0) + (match_operand:DF 0 "general_operand" "fm"))] + "TARGET_68881" + "* +{ + cc_status.flags = CC_IN_68881; + if (FP_REG_P (operands[0])) + return \"ftst%.x %0\"; + return \"ftst%.d %0\"; +}") + +;; compare instructions. + +;; Put cmpsi first among compare insns so it matches two CONST_INT operands. + +;; A composite of the cmp, cmpa, & cmpi m68000 op codes. +(define_insn "cmpsi" + [(set (cc0) + (compare (match_operand:SI 0 "general_operand" "rKs,mr,>") + (match_operand:SI 1 "general_operand" "mr,Ksr,>")))] + "" + "* +{ + if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM) + return \"cmpm%.l %1,%0\"; + if (REG_P (operands[1]) + || (!REG_P (operands[0]) && GET_CODE (operands[0]) != MEM)) + { cc_status.flags |= CC_REVERSED; +#ifdef HPUX_ASM + return \"cmp%.l %d1,%d0\"; +#else + return \"cmp%.l %d0,%d1\"; +#endif + } +#ifdef HPUX_ASM + return \"cmp%.l %d0,%d1\"; +#else + return \"cmp%.l %d1,%d0\"; +#endif +}") + +(define_insn "cmphi" + [(set (cc0) + (compare (match_operand:HI 0 "general_operand" "rnm,d,n,m") + (match_operand:HI 1 "general_operand" "d,rnm,m,n")))] + "" + "* +{ + if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM) + return \"cmpm%.w %1,%0\"; + if ((REG_P (operands[1]) && !ADDRESS_REG_P (operands[1])) + || (!REG_P (operands[0]) && GET_CODE (operands[0]) != MEM)) + { cc_status.flags |= CC_REVERSED; +#ifdef HPUX_ASM + return \"cmp%.w %d1,%d0\"; +#else + return \"cmp%.w %d0,%d1\"; +#endif + } +#ifdef HPUX_ASM + return \"cmp%.w %d0,%d1\"; +#else + return \"cmp%.w %d1,%d0\"; +#endif +}") + +(define_insn "cmpqi" + [(set (cc0) + (compare (match_operand:QI 0 "general_operand" "dn,md,>") + (match_operand:QI 1 "general_operand" "dm,nd,>")))] + "" + "* +{ + if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM) + return \"cmpm%.b %1,%0\"; + if (REG_P (operands[1]) + || (!REG_P (operands[0]) && GET_CODE (operands[0]) != MEM)) + { cc_status.flags |= CC_REVERSED; +#ifdef HPUX_ASM + return \"cmp%.b %d1,%d0\"; +#else + return \"cmp%.b %d0,%d1\"; +#endif + } +#ifdef HPUX_ASM + return \"cmp%.b %d0,%d1\"; +#else + return \"cmp%.b %d1,%d0\"; +#endif +}") + +(define_expand "cmpdf" + [(set (cc0) + (compare (match_operand:DF 0 "general_operand" "") + (match_operand:DF 1 "general_operand" "")))] + "TARGET_68881 || TARGET_FPA" + " +{ + if (TARGET_FPA) + { + rtx set = gen_rtx (SET, VOIDmode, cc0_rtx, + gen_rtx (COMPARE, VOIDmode, operands[0], operands[1])); + emit_insn (gen_rtx (PARALLEL, VOIDmode, + gen_rtvec (2, set, + gen_rtx (CLOBBER, VOIDmode, + gen_reg_rtx (SImode))))); + DONE; + } +}") + +(define_insn "" + [(set (cc0) + (compare (match_operand:DF 0 "general_operand" "x,y") + (match_operand:DF 1 "general_operand" "xH,rmF"))) + (clobber (match_operand:SI 2 "general_operand" "d,d"))] + "TARGET_FPA" + "fpcmp%.d %y1,%0\;fpmove fpastatus,%2\;movw %2,cc") + +(define_insn "" + [(set (cc0) + (compare (match_operand:DF 0 "general_operand" "f,mG") + (match_operand:DF 1 "general_operand" "fmG,f")))] + "TARGET_68881" + "* +{ + cc_status.flags = CC_IN_68881; +#ifdef HPUX_ASM + if (REG_P (operands[0])) + { + if (REG_P (operands[1])) + return \"fcmp%.x %0,%1\"; + else + return \"fcmp%.d %0,%f1\"; + } + cc_status.flags |= CC_REVERSED; + return \"fcmp%.d %1,%f0\"; +#else + if (REG_P (operands[0])) + { + if (REG_P (operands[1])) + return \"fcmp%.x %1,%0\"; + else + return \"fcmp%.d %f1,%0\"; + } + cc_status.flags |= CC_REVERSED; + return \"fcmp%.d %f0,%1\"; +#endif +}") + +(define_expand "cmpsf" + [(set (cc0) + (compare (match_operand:SF 0 "general_operand" "") + (match_operand:SF 1 "general_operand" "")))] + "TARGET_68881 || TARGET_FPA" + " +{ + if (TARGET_FPA) + { + rtx set = gen_rtx (SET, VOIDmode, cc0_rtx, + gen_rtx (COMPARE, VOIDmode, operands[0], operands[1])); + emit_insn (gen_rtx (PARALLEL, VOIDmode, + gen_rtvec (2, set, + gen_rtx (CLOBBER, VOIDmode, + gen_reg_rtx(SImode))))); + DONE; + } +}") + +(define_insn "" + [(set (cc0) + (compare (match_operand:SF 0 "general_operand" "x,y") + (match_operand:SF 1 "general_operand" "xH,rmF"))) + (clobber (match_operand:SI 2 "general_operand" "d,d"))] + "TARGET_FPA" + "fpcmp%.s %w1,%x0\;fpmove fpastatus,%2\;movw %2,cc") + +(define_insn "" + [(set (cc0) + (compare (match_operand:SF 0 "general_operand" "f,mdG") + (match_operand:SF 1 "general_operand" "fmdG,f")))] + "TARGET_68881" + "* +{ + cc_status.flags = CC_IN_68881; +#ifdef HPUX_ASM + if (FP_REG_P (operands[0])) + { + if (FP_REG_P (operands[1])) + return \"fcmp%.x %0,%1\"; + else + return \"fcmp%.s %0,%f1\"; + } + cc_status.flags |= CC_REVERSED; + return \"fcmp%.s %1,%f0\"; +#else + if (FP_REG_P (operands[0])) + { + if (FP_REG_P (operands[1])) + return \"fcmp%.x %1,%0\"; + else + return \"fcmp%.s %f1,%0\"; + } + cc_status.flags |= CC_REVERSED; + return \"fcmp%.s %f0,%1\"; +#endif +}") + +;; Recognizers for btst instructions. + +(define_insn "" + [(set (cc0) (zero_extract (match_operand:QI 0 "nonimmediate_operand" "do") + (const_int 1) + (minus:SI (const_int 7) + (match_operand:SI 1 "general_operand" "di"))))] + "" + "* { return output_btst (operands, operands[1], operands[0], insn, 7); }") + +(define_insn "" + [(set (cc0) (zero_extract (match_operand:SI 0 "nonimmediate_operand" "d") + (const_int 1) + (minus:SI (const_int 31) + (match_operand:SI 1 "general_operand" "di"))))] + "" + "* { return output_btst (operands, operands[1], operands[0], insn, 31); }") + +;; The following two patterns are like the previous two +;; except that they use the fact that bit-number operands +;; are automatically masked to 3 or 5 bits. + +(define_insn "" + [(set (cc0) (zero_extract (match_operand:QI 0 "nonimmediate_operand" "do") + (const_int 1) + (minus:SI (const_int 7) + (and:SI + (match_operand:SI 1 "general_operand" "d") + (const_int 7)))))] + "" + "* { return output_btst (operands, operands[1], operands[0], insn, 7); }") + +(define_insn "" + [(set (cc0) (zero_extract (match_operand:SI 0 "nonimmediate_operand" "d") + (const_int 1) + (minus:SI (const_int 31) + (and:SI + (match_operand:SI 1 "general_operand" "d") + (const_int 31)))))] + "" + "* { return output_btst (operands, operands[1], operands[0], insn, 31); }") + +;; Nonoffsettable mem refs are ok in this one pattern +;; since we don't try to adjust them. +(define_insn "" + [(set (cc0) (zero_extract (match_operand:QI 0 "nonimmediate_operand" "md") + (const_int 1) + (match_operand:SI 1 "general_operand" "i")))] + "GET_CODE (operands[1]) == CONST_INT + && (unsigned) INTVAL (operands[1]) < 8" + "* +{ + operands[1] = gen_rtx (CONST_INT, VOIDmode, 7 - INTVAL (operands[1])); + return output_btst (operands, operands[1], operands[0], insn, 7); +}") + +(define_insn "" + ;; The constraint "o,d" here means that a nonoffsettable memref + ;; will match the first alternative, and its address will be reloaded. + ;; Copying the memory contents into a reg would be incorrect if the + ;; bit position is over 7. + [(set (cc0) (zero_extract (match_operand:HI 0 "nonimmediate_operand" "o,d") + (const_int 1) + (match_operand:SI 1 "general_operand" "i,i")))] + "GET_CODE (operands[1]) == CONST_INT" + "* +{ + if (GET_CODE (operands[0]) == MEM) + { + operands[0] = adj_offsettable_operand (operands[0], + INTVAL (operands[1]) / 8); + operands[1] = gen_rtx (CONST_INT, VOIDmode, + 7 - INTVAL (operands[1]) % 8); + return output_btst (operands, operands[1], operands[0], insn, 7); + } + operands[1] = gen_rtx (CONST_INT, VOIDmode, + 15 - INTVAL (operands[1])); + return output_btst (operands, operands[1], operands[0], insn, 15); +}") + +(define_insn "" + [(set (cc0) (zero_extract (match_operand:SI 0 "nonimmediate_operand" "do") + (const_int 1) + (match_operand:SI 1 "general_operand" "i")))] + "GET_CODE (operands[1]) == CONST_INT" + "* +{ + if (GET_CODE (operands[0]) == MEM) + { + operands[0] = adj_offsettable_operand (operands[0], + INTVAL (operands[1]) / 8); + operands[1] = gen_rtx (CONST_INT, VOIDmode, + 7 - INTVAL (operands[1]) % 8); + return output_btst (operands, operands[1], operands[0], insn, 7); + } + operands[1] = gen_rtx (CONST_INT, VOIDmode, + 31 - INTVAL (operands[1])); + return output_btst (operands, operands[1], operands[0], insn, 31); +}") + +(define_insn "" + [(set (cc0) (subreg:SI (lshiftrt:QI (match_operand:QI 0 "nonimmediate_operand" "dm") + (const_int 7)) + 0))] + "" + "* +{ + cc_status.flags = CC_Z_IN_NOT_N | CC_NOT_NEGATIVE; + return \"tst%.b %0\"; +}") + +(define_insn "" + [(set (cc0) (and:SI (sign_extend:SI (sign_extend:HI (match_operand:QI 0 "nonimmediate_operand" "dm"))) + (match_operand:SI 1 "general_operand" "i")))] + "(GET_CODE (operands[1]) == CONST_INT + && (unsigned) INTVAL (operands[1]) < 0x100 + && exact_log2 (INTVAL (operands[1])) >= 0)" + "* +{ register int log = exact_log2 (INTVAL (operands[1])); + operands[1] = gen_rtx (CONST_INT, VOIDmode, log); + return output_btst (operands, operands[1], operands[0], insn, 7); +}") + +;; move instructions + +;; A special case in which it is not desirable +;; to reload the constant into a data register. +(define_insn "" + [(set (match_operand:SI 0 "push_operand" "=m") + (match_operand:SI 1 "general_operand" "J"))] + "GET_CODE (operands[1]) == CONST_INT + && INTVAL (operands[1]) >= -0x8000 + && INTVAL (operands[1]) < 0x8000" + "* +{ + if (operands[1] == const0_rtx) + return \"clr%.l %0\"; + return \"pea %a1\"; +}") + +;This is never used. +;(define_insn "swapsi" +; [(set (match_operand:SI 0 "general_operand" "r") +; (match_operand:SI 1 "general_operand" "r")) +; (set (match_dup 1) (match_dup 0))] +; "" +; "exg %1,%0") + +;; Special case of fullword move when source is zero. +;; The reason this is special is to avoid loading a zero +;; into a data reg with moveq in order to store it elsewhere. + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=g") + (const_int 0))] + ;; clr insns on 68000 read before writing. + ;; This isn't so on the 68010, but we have no alternative for it. + "(TARGET_68020 + || !(GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0])))" + "* +{ + if (ADDRESS_REG_P (operands[0])) + return \"sub%.l %0,%0\"; + /* moveq is faster on the 68000. */ + if (DATA_REG_P (operands[0]) && !TARGET_68020) +#ifdef MOTOROLA + return \"moveq%.l %#0,%0\"; +#else + return \"moveq %#0,%0\"; +#endif + return \"clr%.l %0\"; +}") + +;; General case of fullword move. The register constraints +;; force integer constants in range for a moveq to be reloaded +;; if they are headed for memory. +(define_insn "movsi" + ;; Notes: make sure no alternative allows g vs g. + ;; We don't allow f-regs since fixed point cannot go in them. + ;; We do allow y and x regs since fixed point is allowed in them. + [(set (match_operand:SI 0 "general_operand" "=g,da,y,!*x*r*m") + (match_operand:SI 1 "general_operand" "daymKs,i,g,*x*r*m"))] + "" + "* +{ + if (which_alternative == 3) + return \"fpmove%.l %x1,fpa0\;fpmove%.l fpa0,%x0\"; + if (FPA_REG_P (operands[1]) || FPA_REG_P (operands[0])) + return \"fpmove%.l %x1,%x0\"; + if (GET_CODE (operands[1]) == CONST_INT) + { + if (operands[1] == const0_rtx + && (DATA_REG_P (operands[0]) + || GET_CODE (operands[0]) == MEM) + /* clr insns on 68000 read before writing. + This isn't so on the 68010, but we have no alternative for it. */ + && (TARGET_68020 + || !(GET_CODE (operands[0]) == MEM + && MEM_VOLATILE_P (operands[0])))) + return \"clr%.l %0\"; + else if (DATA_REG_P (operands[0]) + && INTVAL (operands[1]) < 128 + && INTVAL (operands[1]) >= -128) + { +#ifdef MOTOROLA + return \"moveq%.l %1,%0\"; +#else + return \"moveq %1,%0\"; +#endif + } + else if (ADDRESS_REG_P (operands[0]) + && INTVAL (operands[1]) < 0x8000 + && INTVAL (operands[1]) >= -0x8000) + return \"move%.w %1,%0\"; + else if (push_operand (operands[0], SImode) + && INTVAL (operands[1]) < 0x8000 + && INTVAL (operands[1]) >= -0x8000) + return \"pea %a1\"; + } + else if ((GET_CODE (operands[1]) == SYMBOL_REF + || GET_CODE (operands[1]) == CONST) + && push_operand (operands[0], SImode)) + return \"pea %a1\"; + else if ((GET_CODE (operands[1]) == SYMBOL_REF + || GET_CODE (operands[1]) == CONST) + && ADDRESS_REG_P (operands[0])) + return \"lea %a1,%0\"; + return \"move%.l %1,%0\"; +}") + +(define_insn "movhi" + [(set (match_operand:HI 0 "general_operand" "=g") + (match_operand:HI 1 "general_operand" "g"))] + "" + "* +{ + if (GET_CODE (operands[1]) == CONST_INT) + { + if (operands[1] == const0_rtx + && (DATA_REG_P (operands[0]) + || GET_CODE (operands[0]) == MEM) + /* clr insns on 68000 read before writing. + This isn't so on the 68010, but we have no alternative for it. */ + && (TARGET_68020 + || !(GET_CODE (operands[0]) == MEM + && MEM_VOLATILE_P (operands[0])))) + return \"clr%.w %0\"; + else if (DATA_REG_P (operands[0]) + && INTVAL (operands[1]) < 128 + && INTVAL (operands[1]) >= -128) + { +#ifdef MOTOROLA + return \"moveq%.l %1,%0\"; +#else + return \"moveq %1,%0\"; +#endif + } + else if (INTVAL (operands[1]) < 0x8000 + && INTVAL (operands[1]) >= -0x8000) + return \"move%.w %1,%0\"; + } + else if (CONSTANT_P (operands[1])) + return \"move%.l %1,%0\"; +#ifndef SONY_ASM + /* Recognize the insn before a tablejump, one that refers + to a table of offsets. Such an insn will need to refer + to a label on the insn. So output one. Use the label-number + of the table of offsets to generate this label. */ + if (GET_CODE (operands[1]) == MEM + && GET_CODE (XEXP (operands[1], 0)) == PLUS + && (GET_CODE (XEXP (XEXP (operands[1], 0), 0)) == LABEL_REF + || GET_CODE (XEXP (XEXP (operands[1], 0), 1)) == LABEL_REF) + && GET_CODE (XEXP (XEXP (operands[1], 0), 0)) != PLUS + && GET_CODE (XEXP (XEXP (operands[1], 0), 1)) != PLUS) + { + rtx labelref; + if (GET_CODE (XEXP (XEXP (operands[1], 0), 0)) == LABEL_REF) + labelref = XEXP (XEXP (operands[1], 0), 0); + else + labelref = XEXP (XEXP (operands[1], 0), 1); +#if defined (MOTOROLA) && ! defined (SGS_3B1) +#ifdef SGS + fprintf (asm_out_file, \"\\tset %s%d,.+2\\n\", \"LI\", + CODE_LABEL_NUMBER (XEXP (labelref, 0))); +#else /* not SGS */ + fprintf (asm_out_file, \"\\t.set %s%d,.+2\\n\", \"LI\", + CODE_LABEL_NUMBER (XEXP (labelref, 0))); +#endif /* not SGS */ +#else /* SGS_3B1 or not MOTOROLA */ + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, \"LI\", + CODE_LABEL_NUMBER (XEXP (labelref, 0))); + /* For sake of 3b1, set flag saying we need to define the symbol + LD%n (with value L%n-LI%n) at the end of the switch table. */ + RTX_INTEGRATED_P (next_real_insn (XEXP (labelref, 0))) = 1; +#endif /* SGS_3B1 or not MOTOROLA */ + } +#endif /* SONY_ASM */ + return \"move%.w %1,%0\"; +}") + +(define_insn "movstricthi" + [(set (strict_low_part (match_operand:HI 0 "general_operand" "+dm")) + (match_operand:HI 1 "general_operand" "rmn"))] + "" + "* +{ + if (GET_CODE (operands[1]) == CONST_INT) + { + if (operands[1] == const0_rtx + && (DATA_REG_P (operands[0]) + || GET_CODE (operands[0]) == MEM) + /* clr insns on 68000 read before writing. + This isn't so on the 68010, but we have no alternative for it. */ + && (TARGET_68020 + || !(GET_CODE (operands[0]) == MEM + && MEM_VOLATILE_P (operands[0])))) + return \"clr%.w %0\"; + } + return \"move%.w %1,%0\"; +}") + +(define_insn "movqi" + [(set (match_operand:QI 0 "general_operand" "=d,*a,m,m,?*a") + (match_operand:QI 1 "general_operand" "dmi*a,d*a,dmi,?*a,m"))] + "" + "* +{ + rtx xoperands[4]; + if (ADDRESS_REG_P (operands[0]) && GET_CODE (operands[1]) == MEM) + { + xoperands[1] = operands[1]; + xoperands[2] + = gen_rtx (MEM, QImode, + gen_rtx (PLUS, VOIDmode, stack_pointer_rtx, const1_rtx)); + xoperands[3] = stack_pointer_rtx; + /* Just pushing a byte puts it in the high byte of the halfword. */ + /* We must put it in the low half, the second byte. */ + output_asm_insn (\"subq%.w %#2,%3\;move%.b %1,%2\", xoperands); + return \"move%.w %+,%0\"; + } + if (ADDRESS_REG_P (operands[1]) && GET_CODE (operands[0]) == MEM) + { + xoperands[0] = operands[0]; + xoperands[1] = operands[1]; + xoperands[2] + = gen_rtx (MEM, QImode, + gen_rtx (PLUS, VOIDmode, stack_pointer_rtx, const1_rtx)); + xoperands[3] = stack_pointer_rtx; + output_asm_insn (\"move%.w %1,%-\;move%.b %2,%0\;addq%.w %#2,%3\", xoperands); + return \"\"; + } + /* clr and st insns on 68000 read before writing. + This isn't so on the 68010, but we have no alternative for it. */ + if (TARGET_68020 + || !(GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0]))) + { + if (operands[1] == const0_rtx) + return \"clr%.b %0\"; + if (GET_CODE (operands[1]) == CONST_INT + && INTVAL (operands[1]) == -1) + { + CC_STATUS_INIT; + return \"st %0\"; + } + } + if (GET_CODE (operands[1]) != CONST_INT && CONSTANT_P (operands[1])) + return \"move%.l %1,%0\"; + if (ADDRESS_REG_P (operands[0]) || ADDRESS_REG_P (operands[1])) + return \"move%.w %1,%0\"; + return \"move%.b %1,%0\"; +}") + +(define_insn "movstrictqi" + [(set (strict_low_part (match_operand:QI 0 "general_operand" "+dm")) + (match_operand:QI 1 "general_operand" "dmn"))] + "" + "* +{ + if (operands[1] == const0_rtx + /* clr insns on 68000 read before writing. + This isn't so on the 68010, but we have no alternative for it. */ + && (TARGET_68020 + || !(GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0])))) + return \"clr%.b %0\"; + return \"move%.b %1,%0\"; +}") + +(define_insn "movsf" + [(set (match_operand:SF 0 "general_operand" "=rmf,x,y,rm,!x,!rm") + (match_operand:SF 1 "general_operand" "rmfF,xH,rmF,y,rm,x"))] +; [(set (match_operand:SF 0 "general_operand" "=rmf") +; (match_operand:SF 1 "general_operand" "rmfF"))] + "" + "* +{ + if (which_alternative >= 4) + return \"fpmove%.s %1,fpa0\;fpmove%.s fpa0,%0\"; + if (FPA_REG_P (operands[0])) + { + if (FPA_REG_P (operands[1])) + return \"fpmove%.s %x1,%x0\"; + else if (GET_CODE (operands[1]) == CONST_DOUBLE) + return output_move_const_single (operands); + else if (FP_REG_P (operands[1])) + return \"fmove%.s %1,sp@-\;fpmove%.d sp@+, %0\"; + return \"fpmove%.s %x1,%x0\"; + } + if (FPA_REG_P (operands[1])) + { + if (FP_REG_P (operands[0])) + return \"fpmove%.s %x1,sp@-\;fmove%.s sp@+,%0\"; + else + return \"fpmove%.s %x1,%x0\"; + } + if (FP_REG_P (operands[0])) + { + if (FP_REG_P (operands[1])) + return \"fmove%.x %1,%0\"; + else if (ADDRESS_REG_P (operands[1])) + return \"move%.l %1,%-\;fmove%.s %+,%0\"; + else if (GET_CODE (operands[1]) == CONST_DOUBLE) + return output_move_const_single (operands); + return \"fmove%.s %f1,%0\"; + } + if (FP_REG_P (operands[1])) + { + if (ADDRESS_REG_P (operands[0])) + return \"fmove%.s %1,%-\;move%.l %+,%0\"; + return \"fmove%.s %f1,%0\"; + } + return \"move%.l %1,%0\"; +}") + +(define_insn "movdf" + [(set (match_operand:DF 0 "general_operand" "=rm,&rf,&rof<>,y,rm,x,!x,!rm") + (match_operand:DF 1 "general_operand" "rf,m,rofF<>,rmF,y,xH,rm,x"))] +; [(set (match_operand:DF 0 "general_operand" "=rm,&rf,&rof<>") +; (match_operand:DF 1 "general_operand" "rf,m,rofF<>"))] + "" + "* +{ + if (which_alternative == 6) + return \"fpmove%.d %x1,fpa0\;fpmove%.d fpa0,%x0\"; + if (FPA_REG_P (operands[0])) + { + if (GET_CODE (operands[1]) == CONST_DOUBLE) + return output_move_const_double (operands); + if (FP_REG_P (operands[1])) + return \"fmove%.d %1,sp@-\;fpmove%.d sp@+,%x0\"; + return \"fpmove%.d %x1,%x0\"; + } + else if (FPA_REG_P (operands[1])) + { + if (FP_REG_P(operands[0])) + return \"fpmove%.d %x1,sp@-\;fmoved sp@+,%0\"; + else + return \"fpmove%.d %x1,%x0\"; + } + if (FP_REG_P (operands[0])) + { + if (FP_REG_P (operands[1])) + return \"fmove%.x %1,%0\"; + if (REG_P (operands[1])) + { + rtx xoperands[2]; + xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1); + output_asm_insn (\"move%.l %1,%-\", xoperands); + output_asm_insn (\"move%.l %1,%-\", operands); + return \"fmove%.d %+,%0\"; + } + if (GET_CODE (operands[1]) == CONST_DOUBLE) + return output_move_const_double (operands); + return \"fmove%.d %f1,%0\"; + } + else if (FP_REG_P (operands[1])) + { + if (REG_P (operands[0])) + { + output_asm_insn (\"fmove%.d %f1,%-\;move%.l %+,%0\", operands); + operands[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); + return \"move%.l %+,%0\"; + } + else + return \"fmove%.d %f1,%0\"; + } + return output_move_double (operands); +} +") + +;; movdi can apply to fp regs in some cases +(define_insn "movdi" + ;; Let's see if it really still needs to handle fp regs, and, if so, why. + [(set (match_operand:DI 0 "general_operand" "=rm,&r,&ro<>,y,rm,!*x,!rm") + (match_operand:DI 1 "general_operand" "rF,m,roi<>F,rmiF,y,rmF,*x"))] +; [(set (match_operand:DI 0 "general_operand" "=rm,&r,&ro<>,!&rm,!&f,y,rm,x,!x,!rm") +; (match_operand:DI 1 "general_operand" "r,m,roi<>,fF,rfmF,rmi,y,rm,x"))] +; [(set (match_operand:DI 0 "general_operand" "=rm,&rf,&ro<>,!&rm,!&f") +; (match_operand:DI 1 "general_operand" "r,m,roi<>,fF,rfF"))] + "" + "* +{ + if (which_alternative == 8) + return \"fpmove%.d %x1,fpa0\;fpmove%.d fpa0,%x0\"; + if (FPA_REG_P (operands[0]) || FPA_REG_P (operands[1])) + return \"fpmove%.d %x1,%x0\"; + if (FP_REG_P (operands[0])) + { + if (FP_REG_P (operands[1])) + return \"fmove%.x %1,%0\"; + if (REG_P (operands[1])) + { + rtx xoperands[2]; + xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1); + output_asm_insn (\"move%.l %1,%-\", xoperands); + output_asm_insn (\"move%.l %1,%-\", operands); + return \"fmove%.d %+,%0\"; + } + if (GET_CODE (operands[1]) == CONST_DOUBLE) + return output_move_const_double (operands); + return \"fmove%.d %f1,%0\"; + } + else if (FP_REG_P (operands[1])) + { + if (REG_P (operands[0])) + { + output_asm_insn (\"fmove%.d %f1,%-\;move%.l %+,%0\", operands); + operands[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); + return \"move%.l %+,%0\"; + } + else + return \"fmove%.d %f1,%0\"; + } + return output_move_double (operands); +} +") + +;; Thus goes after the move instructions +;; because the move instructions are better (require no spilling) +;; when they can apply. It goes before the add/sub insns +;; so we will prefer it to them. + +(define_insn "pushasi" + [(set (match_operand:SI 0 "push_operand" "=m") + (match_operand:SI 1 "address_operand" "p"))] + "" + "pea %a1") + +;; truncation instructions +(define_insn "truncsiqi2" + [(set (match_operand:QI 0 "general_operand" "=dm,d") + (truncate:QI + (match_operand:SI 1 "general_operand" "doJ,i")))] + "" + "* +{ + if (GET_CODE (operands[0]) == REG) + { + /* Must clear condition codes, since the mov.l bases them on + the entire 32 bits, not just the desired 8 bits. */ + CC_STATUS_INIT; + return \"move%.l %1,%0\"; + } + if (GET_CODE (operands[1]) == MEM) + operands[1] = adj_offsettable_operand (operands[1], 3); + return \"move%.b %1,%0\"; +}") + +(define_insn "trunchiqi2" + [(set (match_operand:QI 0 "general_operand" "=dm,d") + (truncate:QI + (match_operand:HI 1 "general_operand" "doJ,i")))] + "" + "* +{ + if (GET_CODE (operands[0]) == REG + && (GET_CODE (operands[1]) == MEM + || GET_CODE (operands[1]) == CONST_INT)) + { + /* Must clear condition codes, since the mov.w bases them on + the entire 16 bits, not just the desired 8 bits. */ + CC_STATUS_INIT; + return \"move%.w %1,%0\"; + } + if (GET_CODE (operands[0]) == REG) + { + /* Must clear condition codes, since the mov.l bases them on + the entire 32 bits, not just the desired 8 bits. */ + CC_STATUS_INIT; + return \"move%.l %1,%0\"; + } + if (GET_CODE (operands[1]) == MEM) + operands[1] = adj_offsettable_operand (operands[1], 1); + return \"move%.b %1,%0\"; +}") + +(define_insn "truncsihi2" + [(set (match_operand:HI 0 "general_operand" "=dm,d") + (truncate:HI + (match_operand:SI 1 "general_operand" "roJ,i")))] + "" + "* +{ + if (GET_CODE (operands[0]) == REG) + { + /* Must clear condition codes, since the mov.l bases them on + the entire 32 bits, not just the desired 8 bits. */ + CC_STATUS_INIT; + return \"move%.l %1,%0\"; + } + if (GET_CODE (operands[1]) == MEM) + operands[1] = adj_offsettable_operand (operands[1], 2); + return \"move%.w %1,%0\"; +}") + +;; zero extension instructions + +(define_expand "zero_extendhisi2" + [(set (match_operand:SI 0 "register_operand" "") + (const_int 0)) + (set (strict_low_part (subreg:HI (match_dup 0) 0)) + (match_operand:HI 1 "general_operand" ""))] + "" + "operands[1] = make_safe_from (operands[1], operands[0]);") + +(define_expand "zero_extendqihi2" + [(set (match_operand:HI 0 "register_operand" "") + (const_int 0)) + (set (strict_low_part (subreg:QI (match_dup 0) 0)) + (match_operand:QI 1 "general_operand" ""))] + "" + "operands[1] = make_safe_from (operands[1], operands[0]);") + +(define_expand "zero_extendqisi2" + [(set (match_operand:SI 0 "register_operand" "") + (const_int 0)) + (set (strict_low_part (subreg:QI (match_dup 0) 0)) + (match_operand:QI 1 "general_operand" ""))] + "" + " operands[1] = make_safe_from (operands[1], operands[0]); ") + +;; Patterns to recognize zero-extend insns produced by the combiner. + +;; Note that the one starting from HImode comes before those for QImode +;; so that a constant operand will match HImode, not QImode. +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=do<>") + (zero_extend:SI + (match_operand:HI 1 "general_operand" "rmn")))] + "" + "* +{ + if (DATA_REG_P (operands[0])) + { + if (GET_CODE (operands[1]) == REG + && REGNO (operands[0]) == REGNO (operands[1])) + return \"and%.l %#0xFFFF,%0\"; + if (reg_mentioned_p (operands[0], operands[1])) + return \"move%.w %1,%0\;and%.l %#0xFFFF,%0\"; + return \"clr%.l %0\;move%.w %1,%0\"; + } + else if (GET_CODE (operands[0]) == MEM + && GET_CODE (XEXP (operands[0], 0)) == PRE_DEC) + return \"move%.w %1,%0\;clr%.w %0\"; + else if (GET_CODE (operands[0]) == MEM + && GET_CODE (XEXP (operands[0], 0)) == POST_INC) + return \"clr%.w %0\;move%.w %1,%0\"; + else + { + output_asm_insn (\"clr%.w %0\", operands); + operands[0] = adj_offsettable_operand (operands[0], 2); + return \"move%.w %1,%0\"; + } +}") + +(define_insn "" + [(set (match_operand:HI 0 "general_operand" "=do<>") + (zero_extend:HI + (match_operand:QI 1 "general_operand" "dmn")))] + "" + "* +{ + if (DATA_REG_P (operands[0])) + { + if (GET_CODE (operands[1]) == REG + && REGNO (operands[0]) == REGNO (operands[1])) + return \"and%.w %#0xFF,%0\"; + if (reg_mentioned_p (operands[0], operands[1])) + return \"move%.b %1,%0\;and%.w %#0xFF,%0\"; + return \"clr%.w %0\;move%.b %1,%0\"; + } + else if (GET_CODE (operands[0]) == MEM + && GET_CODE (XEXP (operands[0], 0)) == PRE_DEC) + { + if (REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM) + { + output_asm_insn (\"clr%.w %-\", operands); + operands[0] = gen_rtx (MEM, GET_MODE (operands[0]), + plus_constant (stack_pointer_rtx, 1)); + return \"move%.b %1,%0\"; + } + else + return \"move%.b %1,%0\;clr%.b %0\"; + } + else if (GET_CODE (operands[0]) == MEM + && GET_CODE (XEXP (operands[0], 0)) == POST_INC) + return \"clr%.b %0\;move%.b %1,%0\"; + else + { + output_asm_insn (\"clr%.b %0\", operands); + operands[0] = adj_offsettable_operand (operands[0], 1); + return \"move%.b %1,%0\"; + } +}") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=do<>") + (zero_extend:SI + (match_operand:QI 1 "general_operand" "dmn")))] + "" + "* +{ + if (DATA_REG_P (operands[0])) + { + if (GET_CODE (operands[1]) == REG + && REGNO (operands[0]) == REGNO (operands[1])) + return \"and%.l %#0xFF,%0\"; + if (reg_mentioned_p (operands[0], operands[1])) + return \"move%.b %1,%0\;and%.l %#0xFF,%0\"; + return \"clr%.l %0\;move%.b %1,%0\"; + } + else if (GET_CODE (operands[0]) == MEM + && GET_CODE (XEXP (operands[0], 0)) == PRE_DEC) + { + operands[0] = XEXP (XEXP (operands[0], 0), 0); +#ifdef MOTOROLA +#ifdef SGS + return \"clr.l -(%0)\;move%.b %1,3(%0)\"; +#else + return \"clr.l -(%0)\;move%.b %1,(3,%0)\"; +#endif +#else + return \"clrl %0@-\;moveb %1,%0@(3)\"; +#endif + } + else if (GET_CODE (operands[0]) == MEM + && GET_CODE (XEXP (operands[0], 0)) == POST_INC) + { + operands[0] = XEXP (XEXP (operands[0], 0), 0); +#ifdef MOTOROLA +#ifdef SGS + return \"clr.l (%0)+\;move%.b %1,-1(%0)\"; +#else + return \"clr.l (%0)+\;move%.b %1,(-1,%0)\"; +#endif +#else + return \"clrl %0@+\;moveb %1,%0@(-1)\"; +#endif + } + else + { + output_asm_insn (\"clr%.l %0\", operands); + operands[0] = adj_offsettable_operand (operands[0], 3); + return \"move%.b %1,%0\"; + } +}") + +;; sign extension instructions +;; Note that the one starting from HImode comes before those for QImode +;; so that a constant operand will match HImode, not QImode. + +(define_insn "extendhisi2" + [(set (match_operand:SI 0 "general_operand" "=*d,a") + (sign_extend:SI + (match_operand:HI 1 "general_operand" "0,rmn")))] + "" + "* +{ + if (ADDRESS_REG_P (operands[0])) + return \"move%.w %1,%0\"; + return \"ext%.l %0\"; +}") + +(define_insn "extendqihi2" + [(set (match_operand:HI 0 "general_operand" "=d") + (sign_extend:HI + (match_operand:QI 1 "general_operand" "0")))] + "" + "ext%.w %0") + +(define_insn "extendqisi2" + [(set (match_operand:SI 0 "general_operand" "=d") + (sign_extend:SI + (match_operand:QI 1 "general_operand" "0")))] + "TARGET_68020" + "extb%.l %0") + +;; Conversions between float and double. + +(define_expand "extendsfdf2" + [(set (match_operand:DF 0 "general_operand" "") + (float_extend:DF + (match_operand:SF 1 "general_operand" "")))] + "TARGET_68881 || TARGET_FPA" + "") + +(define_insn "" + [(set (match_operand:DF 0 "general_operand" "=x,y") + (float_extend:DF + (match_operand:SF 1 "general_operand" "xH,rmF")))] + "TARGET_FPA" + "fpstod %w1,%0") + +(define_insn "" + [(set (match_operand:DF 0 "general_operand" "=*fdm,f") + (float_extend:DF + (match_operand:SF 1 "general_operand" "f,dmF")))] + "TARGET_68881" + "* +{ + if (FP_REG_P (operands[0]) && FP_REG_P (operands[1])) + { + if (REGNO (operands[0]) == REGNO (operands[1])) + { + /* Extending float to double in an fp-reg is a no-op. + NOTICE_UPDATE_CC has already assumed that the + cc will be set. So cancel what it did. */ + cc_status = cc_prev_status; + return \"\"; + } + return \"fmove%.x %1,%0\"; + } + if (FP_REG_P (operands[0])) + return \"fmove%.s %f1,%0\"; + if (DATA_REG_P (operands[0]) && FP_REG_P (operands[1])) + { + output_asm_insn (\"fmove%.d %f1,%-\;move%.l %+,%0\", operands); + operands[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); + return \"move%.l %+,%0\"; + } + return \"fmove%.d %f1,%0\"; +}") + +;; This cannot output into an f-reg because there is no way to be +;; sure of truncating in that case. +;; But on the Sun FPA, we can be sure. +(define_expand "truncdfsf2" + [(set (match_operand:SF 0 "general_operand" "") + (float_truncate:SF + (match_operand:DF 1 "general_operand" "")))] + "TARGET_68881 || TARGET_FPA" + "") + +(define_insn "" + [(set (match_operand:SF 0 "general_operand" "=x,y") + (float_truncate:SF + (match_operand:DF 1 "general_operand" "xH,rmF")))] + "TARGET_FPA" + "fpdtos %y1,%0") + +(define_insn "" + [(set (match_operand:SF 0 "general_operand" "=dm") + (float_truncate:SF + (match_operand:DF 1 "general_operand" "f")))] + "TARGET_68881" + "fmove%.s %f1,%0") + +;; Conversion between fixed point and floating point. +;; Note that among the fix-to-float insns +;; the ones that start with SImode come first. +;; That is so that an operand that is a CONST_INT +;; (and therefore lacks a specific machine mode). +;; will be recognized as SImode (which is always valid) +;; rather than as QImode or HImode. + +(define_expand "floatsisf2" + [(set (match_operand:SF 0 "general_operand" "") + (float:SF (match_operand:SI 1 "general_operand" "")))] + "TARGET_68881 || TARGET_FPA" + "") + +(define_insn "" + [(set (match_operand:SF 0 "general_operand" "=y,x") + (float:SF (match_operand:SI 1 "general_operand" "rmi,x")))] + "TARGET_FPA" + "fpltos %1,%0") + +(define_insn "" + [(set (match_operand:SF 0 "general_operand" "=f") + (float:SF (match_operand:SI 1 "general_operand" "dmi")))] + "TARGET_68881" + "fmove%.l %1,%0") + +(define_expand "floatsidf2" + [(set (match_operand:DF 0 "general_operand" "") + (float:DF (match_operand:SI 1 "general_operand" "")))] + "TARGET_68881 || TARGET_FPA" + "") + +(define_insn "" + [(set (match_operand:DF 0 "general_operand" "=y,x") + (float:DF (match_operand:SI 1 "general_operand" "rmi,x")))] + "TARGET_FPA" + "fpltod %1,%0") + +(define_insn "" + [(set (match_operand:DF 0 "general_operand" "=f") + (float:DF (match_operand:SI 1 "general_operand" "dmi")))] + "TARGET_68881" + "fmove%.l %1,%0") + +(define_insn "floathisf2" + [(set (match_operand:SF 0 "general_operand" "=f") + (float:SF (match_operand:HI 1 "general_operand" "dmn")))] + "TARGET_68881" + "fmove%.w %1,%0") + +(define_insn "floathidf2" + [(set (match_operand:DF 0 "general_operand" "=f") + (float:DF (match_operand:HI 1 "general_operand" "dmn")))] + "TARGET_68881" + "fmove%.w %1,%0") + +(define_insn "floatqisf2" + [(set (match_operand:SF 0 "general_operand" "=f") + (float:SF (match_operand:QI 1 "general_operand" "dmn")))] + "TARGET_68881" + "fmove%.b %1,%0") + +(define_insn "floatqidf2" + [(set (match_operand:DF 0 "general_operand" "=f") + (float:DF (match_operand:QI 1 "general_operand" "dmn")))] + "TARGET_68881" + "fmove%.b %1,%0") + +;; Convert a float to a float whose value is an integer. +;; This is the first stage of converting it to an integer type. + +(define_insn "ftruncdf2" + [(set (match_operand:DF 0 "general_operand" "=f") + (fix:DF (match_operand:DF 1 "general_operand" "fFm")))] + "TARGET_68881" + "* +{ + if (FP_REG_P (operands[1])) + return \"fintrz%.x %f1,%0\"; + return \"fintrz%.d %f1,%0\"; +}") + +(define_insn "ftruncsf2" + [(set (match_operand:SF 0 "general_operand" "=f") + (fix:SF (match_operand:SF 1 "general_operand" "dfFm")))] + "TARGET_68881" + "* +{ + if (FP_REG_P (operands[1])) + return \"fintrz%.x %f1,%0\"; + return \"fintrz%.s %f1,%0\"; +}") + +;; Convert a float whose value is an integer +;; to an actual integer. Second stage of converting float to integer type. +(define_insn "fixsfqi2" + [(set (match_operand:QI 0 "general_operand" "=dm") + (fix:QI (match_operand:SF 1 "general_operand" "f")))] + "TARGET_68881" + "fmove%.b %1,%0") + +(define_insn "fixsfhi2" + [(set (match_operand:HI 0 "general_operand" "=dm") + (fix:HI (match_operand:SF 1 "general_operand" "f")))] + "TARGET_68881" + "fmove%.w %1,%0") + +(define_insn "fixsfsi2" + [(set (match_operand:SI 0 "general_operand" "=dm") + (fix:SI (match_operand:SF 1 "general_operand" "f")))] + "TARGET_68881" + "fmove%.l %1,%0") + +(define_insn "fixdfqi2" + [(set (match_operand:QI 0 "general_operand" "=dm") + (fix:QI (match_operand:DF 1 "general_operand" "f")))] + "TARGET_68881" + "fmove%.b %1,%0") + +(define_insn "fixdfhi2" + [(set (match_operand:HI 0 "general_operand" "=dm") + (fix:HI (match_operand:DF 1 "general_operand" "f")))] + "TARGET_68881" + "fmove%.w %1,%0") + +(define_insn "fixdfsi2" + [(set (match_operand:SI 0 "general_operand" "=dm") + (fix:SI (match_operand:DF 1 "general_operand" "f")))] + "TARGET_68881" + "fmove%.l %1,%0") + +;; Convert a float to an integer. +;; On the Sun FPA, this is done in one step. + +(define_insn "fix_truncsfsi2" + [(set (match_operand:SI 0 "general_operand" "=x,y") + (fix:SI (fix:SF (match_operand:SF 1 "general_operand" "xH,rmF"))))] + "TARGET_FPA" + "fpstol %w1,%0") + +(define_insn "fix_truncdfsi2" + [(set (match_operand:SI 0 "general_operand" "=x,y") + (fix:SI (fix:DF (match_operand:DF 1 "general_operand" "xH,rmF"))))] + "TARGET_FPA" + "fpdtol %y1,%0") + +;; add instructions + +;; Note that the last two alternatives are near-duplicates +;; in order to handle insns generated by reload. +;; This is needed since they are not themselves reloaded, +;; so commutativity won't apply to them. +(define_insn "addsi3" + [(set (match_operand:SI 0 "general_operand" "=m,r,!a,!a") + (plus:SI (match_operand:SI 1 "general_operand" "%0,0,a,rJK") + (match_operand:SI 2 "general_operand" "dIKLs,mrIKLs,rJK,a")))] + "" + "* +{ + if (! operands_match_p (operands[0], operands[1])) + { + if (!ADDRESS_REG_P (operands[1])) + { + rtx tmp = operands[1]; + + operands[1] = operands[2]; + operands[2] = tmp; + } + + /* These insns can result from reloads to access + stack slots over 64k from the frame pointer. */ + if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) + 0x8000 >= (unsigned) 0x10000) + return \"move%.l %2,%0\;add%.l %1,%0\"; +#ifdef SGS + if (GET_CODE (operands[2]) == REG) + return \"lea 0(%1,%2.l),%0\"; + else + return \"lea %c2(%1),%0\"; +#else /* not SGS */ +#ifdef MOTOROLA + if (GET_CODE (operands[2]) == REG) + return \"lea (%1,%2.l),%0\"; + else + return \"lea (%c2,%1),%0\"; +#else /* not MOTOROLA (MIT syntax) */ + if (GET_CODE (operands[2]) == REG) + return \"lea %1@(0,%2:l),%0\"; + else + return \"lea %1@(%c2),%0\"; +#endif /* not MOTOROLA */ +#endif /* not SGS */ + } + if (GET_CODE (operands[2]) == CONST_INT) + { +#ifndef NO_ADDSUB_Q + if (INTVAL (operands[2]) > 0 + && INTVAL (operands[2]) <= 8) + return (ADDRESS_REG_P (operands[0]) + ? \"addq%.w %2,%0\" + : \"addq%.l %2,%0\"); + if (INTVAL (operands[2]) < 0 + && INTVAL (operands[2]) >= -8) + { + operands[2] = gen_rtx (CONST_INT, VOIDmode, + - INTVAL (operands[2])); + return (ADDRESS_REG_P (operands[0]) + ? \"subq%.w %2,%0\" + : \"subq%.l %2,%0\"); + } +#endif + if (ADDRESS_REG_P (operands[0]) + && INTVAL (operands[2]) >= -0x8000 + && INTVAL (operands[2]) < 0x8000) + return \"add%.w %2,%0\"; + } + return \"add%.l %2,%0\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=a") + (plus:SI (match_operand:SI 1 "general_operand" "0") + (sign_extend:SI (match_operand:HI 2 "general_operand" "rmn"))))] + "" + "add%.w %2,%0") + +(define_insn "addhi3" + [(set (match_operand:HI 0 "general_operand" "=m,r") + (plus:HI (match_operand:HI 1 "general_operand" "%0,0") + (match_operand:HI 2 "general_operand" "dn,rmn")))] + "" + "* +{ +#ifndef NO_ADDSUB_Q + if (GET_CODE (operands[2]) == CONST_INT) + { + if (INTVAL (operands[2]) > 0 + && INTVAL (operands[2]) <= 8) + return \"addq%.w %2,%0\"; + } + if (GET_CODE (operands[2]) == CONST_INT) + { + if (INTVAL (operands[2]) < 0 + && INTVAL (operands[2]) >= -8) + { + operands[2] = gen_rtx (CONST_INT, VOIDmode, + - INTVAL (operands[2])); + return \"subq%.w %2,%0\"; + } + } +#endif + return \"add%.w %2,%0\"; +}") + +(define_insn "" + [(set (strict_low_part (match_operand:HI 0 "general_operand" "+m,d")) + (plus:HI (match_dup 0) + (match_operand:HI 1 "general_operand" "dn,rmn")))] + "" + "add%.w %1,%0") + +(define_insn "addqi3" + [(set (match_operand:QI 0 "general_operand" "=m,d") + (plus:QI (match_operand:QI 1 "general_operand" "%0,0") + (match_operand:QI 2 "general_operand" "dn,dmn")))] + "" + "* +{ +#ifndef NO_ADDSUB_Q + if (GET_CODE (operands[2]) == CONST_INT) + { + if (INTVAL (operands[2]) > 0 + && INTVAL (operands[2]) <= 8) + return \"addq%.b %2,%0\"; + } + if (GET_CODE (operands[2]) == CONST_INT) + { + if (INTVAL (operands[2]) < 0 && INTVAL (operands[2]) >= -8) + { + operands[2] = gen_rtx (CONST_INT, VOIDmode, - INTVAL (operands[2])); + return \"subq%.b %2,%0\"; + } + } +#endif + return \"add%.b %2,%0\"; +}") + +(define_insn "" + [(set (strict_low_part (match_operand:QI 0 "general_operand" "+m,d")) + (plus:QI (match_dup 0) + (match_operand:QI 1 "general_operand" "dn,dmn")))] + "" + "add%.b %1,%0") + +(define_expand "adddf3" + [(set (match_operand:DF 0 "general_operand" "") + (plus:DF (match_operand:DF 1 "general_operand" "") + (match_operand:DF 2 "general_operand" "")))] + "TARGET_68881 || TARGET_FPA" + "") + +(define_insn "" + [(set (match_operand:DF 0 "general_operand" "=x,y") + (plus:DF (match_operand:DF 1 "general_operand" "%xH,y") + (match_operand:DF 2 "general_operand" "xH,dmF")))] + "TARGET_FPA" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + return \"fpadd%.d %y2,%0\"; + if (rtx_equal_p (operands[0], operands[2])) + return \"fpadd%.d %y1,%0\"; + if (which_alternative == 0) + return \"fpadd3%.d %w2,%w1,%0\"; + return \"fpadd3%.d %x2,%x1,%0\"; +}") + +(define_insn "" + [(set (match_operand:DF 0 "general_operand" "=f") + (plus:DF (match_operand:DF 1 "general_operand" "%0") + (match_operand:DF 2 "general_operand" "fmG")))] + "TARGET_68881" + "* +{ + if (REG_P (operands[2])) + return \"fadd%.x %2,%0\"; + return \"fadd%.d %f2,%0\"; +}") + +(define_expand "addsf3" + [(set (match_operand:SF 0 "general_operand" "") + (plus:SF (match_operand:SF 1 "general_operand" "") + (match_operand:SF 2 "general_operand" "")))] + "TARGET_68881 || TARGET_FPA" + "") + +(define_insn "" + [(set (match_operand:SF 0 "general_operand" "=x,y") + (plus:SF (match_operand:SF 1 "general_operand" "%xH,y") + (match_operand:SF 2 "general_operand" "xH,rmF")))] + "TARGET_FPA" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + return \"fpadd%.s %w2,%0\"; + if (rtx_equal_p (operands[0], operands[2])) + return \"fpadd%.s %w1,%0\"; + if (which_alternative == 0) + return \"fpadd3%.s %w2,%w1,%0\"; + return \"fpadd3%.s %2,%1,%0\"; +}") + +(define_insn "" + [(set (match_operand:SF 0 "general_operand" "=f") + (plus:SF (match_operand:SF 1 "general_operand" "%0") + (match_operand:SF 2 "general_operand" "fdmF")))] + "TARGET_68881" + "* +{ + if (REG_P (operands[2]) && ! DATA_REG_P (operands[2])) + return \"fadd%.x %2,%0\"; + return \"fadd%.s %f2,%0\"; +}") + +;; subtract instructions + +(define_insn "subsi3" + [(set (match_operand:SI 0 "general_operand" "=m,r,!a,?d") + (minus:SI (match_operand:SI 1 "general_operand" "0,0,a,mrIKs") + (match_operand:SI 2 "general_operand" "dIKs,mrIKs,J,0")))] + "" + "* +{ + if (! operands_match_p (operands[0], operands[1])) + { + if (operands_match_p (operands[0], operands[2])) + { +#ifndef NO_ADDSUB_Q + if (GET_CODE (operands[1]) == CONST_INT) + { + if (INTVAL (operands[1]) > 0 + && INTVAL (operands[1]) <= 8) + return \"subq%.l %1,%0\;neg%.l %0\"; + } +#endif + return \"sub%.l %1,%0\;neg%.l %0\"; + } + /* This case is matched by J, but negating -0x8000 + in an lea would give an invalid displacement. + So do this specially. */ + if (INTVAL (operands[2]) == -0x8000) + return \"move%.l %1,%0\;sub%.l %2,%0\"; +#ifdef SGS + return \"lea %n2(%1),%0\"; +#else +#ifdef MOTOROLA + return \"lea (%n2,%1),%0\"; +#else /* not MOTOROLA (MIT syntax) */ + return \"lea %1@(%n2),%0\"; +#endif /* not MOTOROLA */ +#endif /* not SGS */ + } + if (GET_CODE (operands[2]) == CONST_INT) + { +#ifndef NO_ADDSUB_Q + if (INTVAL (operands[2]) > 0 + && INTVAL (operands[2]) <= 8) + return \"subq%.l %2,%0\"; +#endif + if (ADDRESS_REG_P (operands[0]) + && INTVAL (operands[2]) >= -0x8000 + && INTVAL (operands[2]) < 0x8000) + return \"sub%.w %2,%0\"; + } + return \"sub%.l %2,%0\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=a") + (minus:SI (match_operand:SI 1 "general_operand" "0") + (sign_extend:SI (match_operand:HI 2 "general_operand" "rmn"))))] + "" + "sub%.w %2,%0") + +(define_insn "subhi3" + [(set (match_operand:HI 0 "general_operand" "=m,r") + (minus:HI (match_operand:HI 1 "general_operand" "0,0") + (match_operand:HI 2 "general_operand" "dn,rmn")))] + "" + "sub%.w %2,%0") + +(define_insn "" + [(set (strict_low_part (match_operand:HI 0 "general_operand" "+m,d")) + (minus:HI (match_dup 0) + (match_operand:HI 1 "general_operand" "dn,rmn")))] + "" + "sub%.w %1,%0") + +(define_insn "subqi3" + [(set (match_operand:QI 0 "general_operand" "=m,d") + (minus:QI (match_operand:QI 1 "general_operand" "0,0") + (match_operand:QI 2 "general_operand" "dn,dmn")))] + "" + "sub%.b %2,%0") + +(define_insn "" + [(set (strict_low_part (match_operand:QI 0 "general_operand" "+m,d")) + (minus:QI (match_dup 0) + (match_operand:QI 1 "general_operand" "dn,dmn")))] + "" + "sub%.b %1,%0") + +(define_expand "subdf3" + [(set (match_operand:DF 0 "general_operand" "") + (minus:DF (match_operand:DF 1 "general_operand" "") + (match_operand:DF 2 "general_operand" "")))] + "TARGET_68881 || TARGET_FPA" + "") + +(define_insn "" + [(set (match_operand:DF 0 "general_operand" "=x,y,y") + (minus:DF (match_operand:DF 1 "general_operand" "xH,y,dmF") + (match_operand:DF 2 "general_operand" "xH,dmF,0")))] + "TARGET_FPA" + "* +{ + if (rtx_equal_p (operands[0], operands[2])) + return \"fprsub%.d %y1,%0\"; + if (rtx_equal_p (operands[0], operands[1])) + return \"fpsub%.d %y2,%0\"; + if (which_alternative == 0) + return \"fpsub3%.d %w2,%w1,%0\"; + return \"fpsub3%.d %x2,%x1,%0\"; +}") + +(define_insn "" + [(set (match_operand:DF 0 "general_operand" "=f") + (minus:DF (match_operand:DF 1 "general_operand" "0") + (match_operand:DF 2 "general_operand" "fmG")))] + "TARGET_68881" + "* +{ + if (REG_P (operands[2])) + return \"fsub%.x %2,%0\"; + return \"fsub%.d %f2,%0\"; +}") + +(define_expand "subsf3" + [(set (match_operand:SF 0 "general_operand" "") + (minus:SF (match_operand:SF 1 "general_operand" "") + (match_operand:SF 2 "general_operand" "")))] + "TARGET_68881 || TARGET_FPA" + "") + +(define_insn "" + [(set (match_operand:SF 0 "general_operand" "=x,y,y") + (minus:SF (match_operand:SF 1 "general_operand" "xH,y,rmF") + (match_operand:SF 2 "general_operand" "xH,rmF,0")))] + "TARGET_FPA" + "* +{ + if (rtx_equal_p (operands[0], operands[2])) + return \"fprsub%.s %w1,%0\"; + if (rtx_equal_p (operands[0], operands[1])) + return \"fpsub%.s %w2,%0\"; + if (which_alternative == 0) + return \"fpsub3%.s %w2,%w1,%0\"; + return \"fpsub3%.s %2,%1,%0\"; +}") + +(define_insn "" + [(set (match_operand:SF 0 "general_operand" "=f") + (minus:SF (match_operand:SF 1 "general_operand" "0") + (match_operand:SF 2 "general_operand" "fdmF")))] + "TARGET_68881" + "* +{ + if (REG_P (operands[2]) && ! DATA_REG_P (operands[2])) + return \"fsub%.x %2,%0\"; + return \"fsub%.s %f2,%0\"; +}") + +;; multiply instructions + +(define_insn "mulhi3" + [(set (match_operand:HI 0 "general_operand" "=d") + (mult:HI (match_operand:HI 1 "general_operand" "%0") + (match_operand:HI 2 "general_operand" "dmn")))] + "" + "* +{ +#ifdef MOTOROLA + return \"muls.w %2,%0\"; +#else + return \"muls %2,%0\"; +#endif +}") + +(define_insn "mulhisi3" + [(set (match_operand:SI 0 "general_operand" "=d") + (mult:SI (match_operand:HI 1 "general_operand" "%0") + (match_operand:HI 2 "general_operand" "dmn")))] + "" + "* +{ +#ifdef MOTOROLA + return \"muls.w %2,%0\"; +#else + return \"muls %2,%0\"; +#endif +}") + +(define_insn "mulsi3" + [(set (match_operand:SI 0 "general_operand" "=d") + (mult:SI (match_operand:SI 1 "general_operand" "%0") + (match_operand:SI 2 "general_operand" "dmsK")))] + "TARGET_68020" + "muls%.l %2,%0") + +(define_insn "umulhi3" + [(set (match_operand:HI 0 "general_operand" "=d") + (umult:HI (match_operand:HI 1 "general_operand" "%0") + (match_operand:HI 2 "general_operand" "dmn")))] + "" + "* +{ +#ifdef MOTOROLA + return \"mulu.w %2,%0\"; +#else + return \"mulu %2,%0\"; +#endif +}") + +(define_insn "umulhisi3" + [(set (match_operand:SI 0 "general_operand" "=d") + (umult:SI (match_operand:HI 1 "general_operand" "%0") + (match_operand:HI 2 "general_operand" "dmn")))] + "" + "* +{ +#ifdef MOTOROLA + return \"mulu.w %2,%0\"; +#else + return \"mulu %2,%0\"; +#endif +}") + +(define_insn "umulsi3" + [(set (match_operand:SI 0 "general_operand" "=d") + (umult:SI (match_operand:SI 1 "general_operand" "%0") + (match_operand:SI 2 "general_operand" "dmsK")))] + "TARGET_68020" + "mulu%.l %2,%0") + +(define_expand "muldf3" + [(set (match_operand:DF 0 "general_operand" "") + (mult:DF (match_operand:DF 1 "general_operand" "") + (match_operand:DF 2 "general_operand" "")))] + "TARGET_68881 || TARGET_FPA" + "") + +(define_insn "" + [(set (match_operand:DF 0 "general_operand" "=x,y") + (mult:DF (match_operand:DF 1 "general_operand" "%xH,y") + (match_operand:DF 2 "general_operand" "xH,rmF")))] + "TARGET_FPA" + "* +{ + if (rtx_equal_p (operands[1], operands[2])) + return \"fpsqr%.d %y1,%0\"; + if (rtx_equal_p (operands[0], operands[1])) + return \"fpmul%.d %y2,%0\"; + if (rtx_equal_p (operands[0], operands[2])) + return \"fpmul%.d %y1,%0\"; + if (which_alternative == 0) + return \"fpmul3%.d %w2,%w1,%0\"; + return \"fpmul3%.d %x2,%x1,%0\"; +}") + +(define_insn "" + [(set (match_operand:DF 0 "general_operand" "=f") + (mult:DF (match_operand:DF 1 "general_operand" "%0") + (match_operand:DF 2 "general_operand" "fmG")))] + "TARGET_68881" + "* +{ + if (REG_P (operands[2])) + return \"fmul%.x %2,%0\"; + return \"fmul%.d %f2,%0\"; +}") + +(define_expand "mulsf3" + [(set (match_operand:SF 0 "general_operand" "") + (mult:SF (match_operand:SF 1 "general_operand" "") + (match_operand:SF 2 "general_operand" "")))] + "TARGET_68881 || TARGET_FPA" + "") + +(define_insn "" + [(set (match_operand:SF 0 "general_operand" "=x,y") + (mult:SF (match_operand:SF 1 "general_operand" "%xH,y") + (match_operand:SF 2 "general_operand" "xH,rmF")))] + "TARGET_FPA" + "* +{ + if (rtx_equal_p (operands[1], operands[2])) + return \"fpsqr%.s %w1,%0\"; + if (rtx_equal_p (operands[0], operands[1])) + return \"fpmul%.s %w2,%0\"; + if (rtx_equal_p (operands[0], operands[2])) + return \"fpmul%.s %w1,%0\"; + if (which_alternative == 0) + return \"fpmul3%.s %w2,%w1,%0\"; + return \"fpmul3%.s %2,%1,%0\"; +}") + +(define_insn "" + [(set (match_operand:SF 0 "general_operand" "=f") + (mult:SF (match_operand:SF 1 "general_operand" "%0") + (match_operand:SF 2 "general_operand" "fdmF")))] + "TARGET_68881" + "* +{ + if (REG_P (operands[2]) && ! DATA_REG_P (operands[2])) + return \"fsglmul%.x %2,%0\"; + return \"fsglmul%.s %f2,%0\"; +}") + +;; divide instructions + +(define_insn "divhi3" + [(set (match_operand:HI 0 "general_operand" "=d") + (div:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "dmn")))] + "" + "* +{ +#ifdef MOTOROLA + return \"ext.l %0\;divs.w %2,%0\"; +#else + return \"extl %0\;divs %2,%0\"; +#endif +}") + +(define_insn "divhisi3" + [(set (match_operand:HI 0 "general_operand" "=d") + (div:HI (match_operand:SI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "dmn")))] + "" + "* +{ +#ifdef MOTOROLA + return \"divs.w %2,%0\"; +#else + return \"divs %2,%0\"; +#endif +}") + +(define_insn "divsi3" + [(set (match_operand:SI 0 "general_operand" "=d") + (div:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "dmsK")))] + "TARGET_68020" + "divs%.l %2,%0") + +(define_insn "udivhi3" + [(set (match_operand:HI 0 "general_operand" "=d") + (udiv:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "dmn")))] + "" + "* +{ +#ifdef MOTOROLA + return \"and.l %#0xFFFF,%0\;divu.w %2,%0\"; +#else + return \"andl %#0xFFFF,%0\;divu %2,%0\"; +#endif +}") + +(define_insn "udivhisi3" + [(set (match_operand:HI 0 "general_operand" "=d") + (udiv:HI (match_operand:SI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "dmn")))] + "" + "* +{ +#ifdef MOTOROLA + return \"divu.w %2,%0\"; +#else + return \"divu %2,%0\"; +#endif +}") + +(define_insn "udivsi3" + [(set (match_operand:SI 0 "general_operand" "=d") + (udiv:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "dmsK")))] + "TARGET_68020" + "divu%.l %2,%0") + +(define_expand "divdf3" + [(set (match_operand:DF 0 "general_operand" "") + (div:DF (match_operand:DF 1 "general_operand" "") + (match_operand:DF 2 "general_operand" "")))] + "TARGET_68881 || TARGET_FPA" + "") + +(define_insn "" + [(set (match_operand:DF 0 "general_operand" "=x,y,y") + (div:DF (match_operand:DF 1 "general_operand" "xH,y,rmF") + (match_operand:DF 2 "general_operand" "xH,rmF,0")))] + "TARGET_FPA" + "* +{ + if (rtx_equal_p (operands[0], operands[2])) + return \"fprdiv%.d %y1,%0\"; + if (rtx_equal_p (operands[0], operands[1])) + return \"fpdiv%.d %y2,%0\"; + if (which_alternative == 0) + return \"fpdiv3%.d %w2,%w1,%0\"; + return \"fpdiv3%.d %x2,%x1,%x0\"; +}") + +(define_insn "" + [(set (match_operand:DF 0 "general_operand" "=f") + (div:DF (match_operand:DF 1 "general_operand" "0") + (match_operand:DF 2 "general_operand" "fmG")))] + "TARGET_68881" + "* +{ + if (REG_P (operands[2])) + return \"fdiv%.x %2,%0\"; + return \"fdiv%.d %f2,%0\"; +}") + +(define_expand "divsf3" + [(set (match_operand:SF 0 "general_operand" "") + (div:SF (match_operand:SF 1 "general_operand" "") + (match_operand:SF 2 "general_operand" "")))] + "TARGET_68881 || TARGET_FPA" + "") + +(define_insn "" + [(set (match_operand:SF 0 "general_operand" "=x,y,y") + (div:SF (match_operand:SF 1 "general_operand" "xH,y,rmF") + (match_operand:SF 2 "general_operand" "xH,rmF,0")))] + "TARGET_FPA" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + return \"fpdiv%.s %w2,%0\"; + if (rtx_equal_p (operands[0], operands[2])) + return \"fprdiv%.s %w1,%0\"; + if (which_alternative == 0) + return \"fpdiv3%.s %w2,%w1,%0\"; + return \"fpdiv3%.s %2,%1,%0\"; +}") + +(define_insn "" + [(set (match_operand:SF 0 "general_operand" "=f") + (div:SF (match_operand:SF 1 "general_operand" "0") + (match_operand:SF 2 "general_operand" "fdmF")))] + "TARGET_68881" + "* +{ + if (REG_P (operands[2]) && ! DATA_REG_P (operands[2])) + return \"fsgldiv%.x %2,%0\"; + return \"fsgldiv%.s %f2,%0\"; +}") + +;; Remainder instructions. + +(define_insn "modhi3" + [(set (match_operand:HI 0 "general_operand" "=d") + (mod:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "dmn")))] + "" + "* +{ + /* The swap insn produces cc's that don't correspond to the result. */ + CC_STATUS_INIT; +#ifdef MOTOROLA +#ifdef SGS_3B1 + return \"ext.l %0\;divs.w %2,%0\;swap.w %0\"; +#else + return \"ext.l %0\;divs.w %2,%0\;swap %0\"; +#endif +#else + return \"extl %0\;divs %2,%0\;swap %0\"; +#endif +}") + +(define_insn "modhisi3" + [(set (match_operand:HI 0 "general_operand" "=d") + (mod:HI (match_operand:SI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "dmn")))] + "" + "* +{ + /* The swap insn produces cc's that don't correspond to the result. */ + CC_STATUS_INIT; +#ifdef MOTOROLA +#ifdef SGS_3B1 + return \"divs.w %2,%0\;swap.w %0\"; +#else + return \"divs.w %2,%0\;swap %0\"; +#endif +#else + return \"divs %2,%0\;swap %0\"; +#endif +}") + +(define_insn "umodhi3" + [(set (match_operand:HI 0 "general_operand" "=d") + (umod:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "dmn")))] + "" + "* +{ + /* The swap insn produces cc's that don't correspond to the result. */ + CC_STATUS_INIT; +#ifdef MOTOROLA +#ifdef SGS_3B1 + return \"and.l %#0xFFFF,%0\;divu.w %2,%0\;swap.w %0\"; +#else + return \"and.l %#0xFFFF,%0\;divu.w %2,%0\;swap %0\"; +#endif +#else + return \"andl %#0xFFFF,%0\;divu %2,%0\;swap %0\"; +#endif +}") + +(define_insn "umodhisi3" + [(set (match_operand:HI 0 "general_operand" "=d") + (umod:HI (match_operand:SI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "dmn")))] + "" + "* +{ + /* The swap insn produces cc's that don't correspond to the result. */ + CC_STATUS_INIT; +#ifdef MOTOROLA +#ifdef SGS_3B1 + return \"divu.w %2,%0\;swap.w %0\"; +#else + return \"divu.w %2,%0\;swap %0\"; +#endif +#else + return \"divu %2,%0\;swap %0\"; +#endif +}") + +(define_insn "divmodsi4" + [(set (match_operand:SI 0 "general_operand" "=d") + (div:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "dmsK"))) + (set (match_operand:SI 3 "general_operand" "=d") + (mod:SI (match_dup 1) (match_dup 2)))] + "TARGET_68020" + "divsl%.l %2,%3:%0") + +(define_insn "udivmodsi4" + [(set (match_operand:SI 0 "general_operand" "=d") + (udiv:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "dmsK"))) + (set (match_operand:SI 3 "general_operand" "=d") + (umod:SI (match_dup 1) (match_dup 2)))] + "TARGET_68020" + "divul%.l %2,%3:%0") + +;; logical-and instructions + +(define_insn "andsi3" + [(set (match_operand:SI 0 "general_operand" "=m,d") + (and:SI (match_operand:SI 1 "general_operand" "%0,0") + (match_operand:SI 2 "general_operand" "dKs,dmKs")))] + "" + "* +{ + if (GET_CODE (operands[2]) == CONST_INT + && (INTVAL (operands[2]) | 0xffff) == 0xffffffff + && (DATA_REG_P (operands[0]) + || offsettable_memref_p (operands[0]))) + { + if (GET_CODE (operands[0]) != REG) + operands[0] = adj_offsettable_operand (operands[0], 2); + operands[2] = gen_rtx (CONST_INT, VOIDmode, + INTVAL (operands[2]) & 0xffff); + /* Do not delete a following tstl %0 insn; that would be incorrect. */ + CC_STATUS_INIT; + if (operands[2] == const0_rtx) + return \"clr%.w %0\"; + return \"and%.w %2,%0\"; + } + return \"and%.l %2,%0\"; +}") + +(define_insn "andhi3" + [(set (match_operand:HI 0 "general_operand" "=m,d") + (and:HI (match_operand:HI 1 "general_operand" "%0,0") + (match_operand:HI 2 "general_operand" "dn,dmn")))] + "" + "and%.w %2,%0") + +(define_insn "andqi3" + [(set (match_operand:QI 0 "general_operand" "=m,d") + (and:QI (match_operand:QI 1 "general_operand" "%0,0") + (match_operand:QI 2 "general_operand" "dn,dmn")))] + "" + "and%.b %2,%0") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=d") + (and:SI (zero_extend:SI (match_operand:HI 1 "general_operand" "dm")) + (match_operand:SI 2 "general_operand" "0")))] + "GET_CODE (operands[2]) == CONST_INT + && (unsigned int) INTVAL (operands[2]) < (1 << GET_MODE_BITSIZE (HImode))" + "and%.w %1,%0") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=d") + (and:SI (zero_extend:SI (match_operand:QI 1 "general_operand" "dm")) + (match_operand:SI 2 "general_operand" "0")))] + "GET_CODE (operands[2]) == CONST_INT + && (unsigned int) INTVAL (operands[2]) < (1 << GET_MODE_BITSIZE (QImode))" + "and%.b %1,%0") + +;; inclusive-or instructions + +(define_insn "iorsi3" + [(set (match_operand:SI 0 "general_operand" "=m,d") + (ior:SI (match_operand:SI 1 "general_operand" "%0,0") + (match_operand:SI 2 "general_operand" "dKs,dmKs")))] + "" + "* +{ + register int logval; + if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) >> 16 == 0 + && (DATA_REG_P (operands[0]) + || offsettable_memref_p (operands[0]))) + { + if (GET_CODE (operands[0]) != REG) + operands[0] = adj_offsettable_operand (operands[0], 2); + /* Do not delete a following tstl %0 insn; that would be incorrect. */ + CC_STATUS_INIT; + return \"or%.w %2,%0\"; + } + if (GET_CODE (operands[2]) == CONST_INT + && (logval = exact_log2 (INTVAL (operands[2]))) >= 0 + && (DATA_REG_P (operands[0]) + || offsettable_memref_p (operands[0]))) + { + if (DATA_REG_P (operands[0])) + { + operands[1] = gen_rtx (CONST_INT, VOIDmode, logval); + } + else + { + operands[0] = adj_offsettable_operand (operands[0], 3 - (logval / 8)); + operands[1] = gen_rtx (CONST_INT, VOIDmode, logval % 8); + } + return \"bset %1,%0\"; + } + return \"or%.l %2,%0\"; +}") + +(define_insn "iorhi3" + [(set (match_operand:HI 0 "general_operand" "=m,d") + (ior:HI (match_operand:HI 1 "general_operand" "%0,0") + (match_operand:HI 2 "general_operand" "dn,dmn")))] + "" + "or%.w %2,%0") + +(define_insn "iorqi3" + [(set (match_operand:QI 0 "general_operand" "=m,d") + (ior:QI (match_operand:QI 1 "general_operand" "%0,0") + (match_operand:QI 2 "general_operand" "dn,dmn")))] + "" + "or%.b %2,%0") + +;; xor instructions + +(define_insn "xorsi3" + [(set (match_operand:SI 0 "general_operand" "=do,m") + (xor:SI (match_operand:SI 1 "general_operand" "%0,0") + (match_operand:SI 2 "general_operand" "di,dKs")))] + "" + "* +{ + if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) >> 16 == 0 + && (offsettable_memref_p (operands[0]) || DATA_REG_P (operands[0]))) + { + if (! DATA_REG_P (operands[0])) + operands[0] = adj_offsettable_operand (operands[0], 2); + /* Do not delete a following tstl %0 insn; that would be incorrect. */ + CC_STATUS_INIT; + return \"eor%.w %2,%0\"; + } + return \"eor%.l %2,%0\"; +}") + +(define_insn "xorhi3" + [(set (match_operand:HI 0 "general_operand" "=dm") + (xor:HI (match_operand:HI 1 "general_operand" "%0") + (match_operand:HI 2 "general_operand" "dn")))] + "" + "eor%.w %2,%0") + +(define_insn "xorqi3" + [(set (match_operand:QI 0 "general_operand" "=dm") + (xor:QI (match_operand:QI 1 "general_operand" "%0") + (match_operand:QI 2 "general_operand" "dn")))] + "" + "eor%.b %2,%0") + +;; negation instructions + +(define_insn "negsi2" + [(set (match_operand:SI 0 "general_operand" "=dm") + (neg:SI (match_operand:SI 1 "general_operand" "0")))] + "" + "neg%.l %0") + +(define_insn "neghi2" + [(set (match_operand:HI 0 "general_operand" "=dm") + (neg:HI (match_operand:HI 1 "general_operand" "0")))] + "" + "neg%.w %0") + +(define_insn "negqi2" + [(set (match_operand:QI 0 "general_operand" "=dm") + (neg:QI (match_operand:QI 1 "general_operand" "0")))] + "" + "neg%.b %0") + +(define_expand "negsf2" + [(set (match_operand:SF 0 "general_operand" "") + (neg:SF (match_operand:SF 1 "general_operand" "")))] + "TARGET_68881 || TARGET_FPA" + "") + +(define_insn "" + [(set (match_operand:SF 0 "general_operand" "=x,y") + (neg:SF (match_operand:SF 1 "general_operand" "xH,rmF")))] + "TARGET_FPA" + "fpneg%.s %w1,%0") + +(define_insn "" + [(set (match_operand:SF 0 "general_operand" "=f") + (neg:SF (match_operand:SF 1 "general_operand" "fdmF")))] + "TARGET_68881" + "* +{ + if (REG_P (operands[1]) && ! DATA_REG_P (operands[1])) + return \"fneg%.x %1,%0\"; + return \"fneg%.s %f1,%0\"; +}") + +(define_expand "negdf2" + [(set (match_operand:DF 0 "general_operand" "") + (neg:DF (match_operand:DF 1 "general_operand" "")))] + "TARGET_68881 || TARGET_FPA" + "") + +(define_insn "" + [(set (match_operand:DF 0 "general_operand" "=x,y") + (neg:DF (match_operand:DF 1 "general_operand" "xH,rmF")))] + "TARGET_FPA" + "fpneg%.d %y1, %0") + +(define_insn "" + [(set (match_operand:DF 0 "general_operand" "=f") + (neg:DF (match_operand:DF 1 "general_operand" "fmF")))] + "TARGET_68881" + "* +{ + if (REG_P (operands[1]) && ! DATA_REG_P (operands[1])) + return \"fneg%.x %1,%0\"; + return \"fneg%.d %f1,%0\"; +}") + +;; Absolute value instructions + +(define_expand "abssf2" + [(set (match_operand:SF 0 "general_operand" "") + (abs:SF (match_operand:SF 1 "general_operand" "")))] + "TARGET_68881 || TARGET_FPA" + "") + +(define_insn "" + [(set (match_operand:SF 0 "general_operand" "=x,y") + (abs:SF (match_operand:SF 1 "general_operand" "xH,rmF")))] + "TARGET_FPA" + "fpabs%.s %y1,%0") + +(define_insn "" + [(set (match_operand:SF 0 "general_operand" "=f") + (abs:SF (match_operand:SF 1 "general_operand" "fdmF")))] + "TARGET_68881" + "* +{ + if (REG_P (operands[1]) && ! DATA_REG_P (operands[1])) + return \"fabs%.x %1,%0\"; + return \"fabs%.s %f1,%0\"; +}") + +(define_expand "absdf2" + [(set (match_operand:DF 0 "general_operand" "") + (abs:DF (match_operand:DF 1 "general_operand" "")))] + "TARGET_68881 || TARGET_FPA" + "") + +(define_insn "" + [(set (match_operand:DF 0 "general_operand" "=x,y") + (abs:DF (match_operand:DF 1 "general_operand" "xH,rmF")))] + "TARGET_FPA" + "fpabs%.d %y1,%0") + +(define_insn "" + [(set (match_operand:DF 0 "general_operand" "=f") + (abs:DF (match_operand:DF 1 "general_operand" "fmF")))] + "TARGET_68881" + "* +{ + if (REG_P (operands[1]) && ! DATA_REG_P (operands[1])) + return \"fabs%.x %1,%0\"; + return \"fabs%.d %f1,%0\"; +}") + +;; one complement instructions + +(define_insn "one_cmplsi2" + [(set (match_operand:SI 0 "general_operand" "=dm") + (not:SI (match_operand:SI 1 "general_operand" "0")))] + "" + "not%.l %0") + +(define_insn "one_cmplhi2" + [(set (match_operand:HI 0 "general_operand" "=dm") + (not:HI (match_operand:HI 1 "general_operand" "0")))] + "" + "not%.w %0") + +(define_insn "one_cmplqi2" + [(set (match_operand:QI 0 "general_operand" "=dm") + (not:QI (match_operand:QI 1 "general_operand" "0")))] + "" + "not%.b %0") + +;; Optimized special case of shifting. +;; Must precede the general case. + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=d") + (ashiftrt:SI (match_operand:SI 1 "memory_operand" "m") + (const_int 24)))] + "GET_CODE (XEXP (operands[1], 0)) != POST_INC + && GET_CODE (XEXP (operands[1], 0)) != PRE_DEC" + "* +{ + if (TARGET_68020) + return \"move%.b %1,%0\;extb%.l %0\"; + return \"move%.b %1,%0\;ext%.w %0\;ext%.l %0\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=d") + (lshiftrt:SI (match_operand:SI 1 "memory_operand" "m") + (const_int 24)))] + "GET_CODE (XEXP (operands[1], 0)) != POST_INC + && GET_CODE (XEXP (operands[1], 0)) != PRE_DEC" + "* +{ + if (reg_mentioned_p (operands[0], operands[1])) + return \"move%.b %1,%0\;and%.l %#0xFF,%0\"; + return \"clr%.l %0\;move%.b %1,%0\"; +}") + +(define_insn "" + [(set (cc0) (compare (match_operand:QI 0 "general_operand" "i") + (lshiftrt:SI (match_operand:SI 1 "memory_operand" "m") + (const_int 24))))] + "(GET_CODE (operands[0]) == CONST_INT + && (INTVAL (operands[0]) & ~0xff) == 0)" + "* cc_status.flags |= CC_REVERSED; +#ifdef HPUX_ASM + return \"cmp%.b %1,%0\"; +#else + return \"cmp%.b %0,%1\"; +#endif +") + +(define_insn "" + [(set (cc0) (compare (lshiftrt:SI (match_operand:SI 0 "memory_operand" "m") + (const_int 24)) + (match_operand:QI 1 "general_operand" "i")))] + "(GET_CODE (operands[1]) == CONST_INT + && (INTVAL (operands[1]) & ~0xff) == 0)" + "* +#ifdef HPUX_ASM + return \"cmp%.b %0,%1\"; +#else + return \"cmp%.b %1,%0\"; +#endif +") + +(define_insn "" + [(set (cc0) (compare (match_operand:QI 0 "general_operand" "i") + (ashiftrt:SI (match_operand:SI 1 "memory_operand" "m") + (const_int 24))))] + "(GET_CODE (operands[0]) == CONST_INT + && ((INTVAL (operands[0]) + 0x80) & ~0xff) == 0)" + "* cc_status.flags |= CC_REVERSED; +#ifdef HPUX_ASM + return \"cmp%.b %1,%0\"; +#else + return \"cmp%.b %0,%1\"; +#endif +") + +(define_insn "" + [(set (cc0) (compare (ashiftrt:SI (match_operand:SI 0 "memory_operand" "m") + (const_int 24)) + (match_operand:QI 1 "general_operand" "i")))] + "(GET_CODE (operands[1]) == CONST_INT + && ((INTVAL (operands[1]) + 0x80) & ~0xff) == 0)" + "* +#ifdef HPUX_ASM + return \"cmp%.b %0,%1\"; +#else + return \"cmp%.b %1,%0\"; +#endif +") + +;; arithmetic shift instructions +;; We don't need the shift memory by 1 bit instruction + +(define_insn "ashlsi3" + [(set (match_operand:SI 0 "general_operand" "=d") + (ashift:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "dI")))] + "" + "asl%.l %2,%0") + +(define_insn "ashlhi3" + [(set (match_operand:HI 0 "general_operand" "=d") + (ashift:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "dI")))] + "" + "asl%.w %2,%0") + +(define_insn "ashlqi3" + [(set (match_operand:QI 0 "general_operand" "=d") + (ashift:QI (match_operand:QI 1 "general_operand" "0") + (match_operand:QI 2 "general_operand" "dI")))] + "" + "asl%.b %2,%0") + +(define_insn "ashrsi3" + [(set (match_operand:SI 0 "general_operand" "=d") + (ashiftrt:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "dI")))] + "" + "asr%.l %2,%0") + +(define_insn "ashrhi3" + [(set (match_operand:HI 0 "general_operand" "=d") + (ashiftrt:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "dI")))] + "" + "asr%.w %2,%0") + +(define_insn "ashrqi3" + [(set (match_operand:QI 0 "general_operand" "=d") + (ashiftrt:QI (match_operand:QI 1 "general_operand" "0") + (match_operand:QI 2 "general_operand" "dI")))] + "" + "asr%.b %2,%0") + +;; logical shift instructions + +(define_insn "lshlsi3" + [(set (match_operand:SI 0 "general_operand" "=d") + (lshift:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "dI")))] + "" + "lsl%.l %2,%0") + +(define_insn "lshlhi3" + [(set (match_operand:HI 0 "general_operand" "=d") + (lshift:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "dI")))] + "" + "lsl%.w %2,%0") + +(define_insn "lshlqi3" + [(set (match_operand:QI 0 "general_operand" "=d") + (lshift:QI (match_operand:QI 1 "general_operand" "0") + (match_operand:QI 2 "general_operand" "dI")))] + "" + "lsl%.b %2,%0") + +(define_insn "lshrsi3" + [(set (match_operand:SI 0 "general_operand" "=d") + (lshiftrt:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "dI")))] + "" + "lsr%.l %2,%0") + +(define_insn "lshrhi3" + [(set (match_operand:HI 0 "general_operand" "=d") + (lshiftrt:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "dI")))] + "" + "lsr%.w %2,%0") + +(define_insn "lshrqi3" + [(set (match_operand:QI 0 "general_operand" "=d") + (lshiftrt:QI (match_operand:QI 1 "general_operand" "0") + (match_operand:QI 2 "general_operand" "dI")))] + "" + "lsr%.b %2,%0") + +;; rotate instructions + +(define_insn "rotlsi3" + [(set (match_operand:SI 0 "general_operand" "=d") + (rotate:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "dI")))] + "" + "rol%.l %2,%0") + +(define_insn "rotlhi3" + [(set (match_operand:HI 0 "general_operand" "=d") + (rotate:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "dI")))] + "" + "rol%.w %2,%0") + +(define_insn "rotlqi3" + [(set (match_operand:QI 0 "general_operand" "=d") + (rotate:QI (match_operand:QI 1 "general_operand" "0") + (match_operand:QI 2 "general_operand" "dI")))] + "" + "rol%.b %2,%0") + +(define_insn "rotrsi3" + [(set (match_operand:SI 0 "general_operand" "=d") + (rotatert:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "dI")))] + "" + "ror%.l %2,%0") + +(define_insn "rotrhi3" + [(set (match_operand:HI 0 "general_operand" "=d") + (rotatert:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "dI")))] + "" + "ror%.w %2,%0") + +(define_insn "rotrqi3" + [(set (match_operand:QI 0 "general_operand" "=d") + (rotatert:QI (match_operand:QI 1 "general_operand" "0") + (match_operand:QI 2 "general_operand" "dI")))] + "" + "ror%.b %2,%0") + +;; Special cases of bit-field insns which we should +;; recognize in preference to the general case. +;; These handle aligned 8-bit and 16-bit fields, +;; which can usually be done with move instructions. + +(define_insn "" + [(set (zero_extract:SI (match_operand:SI 0 "nonimmediate_operand" "+do") + (match_operand:SI 1 "immediate_operand" "i") + (match_operand:SI 2 "immediate_operand" "i")) + (match_operand:SI 3 "general_operand" "d"))] + "TARGET_68020 && TARGET_BITFIELD + && GET_CODE (operands[1]) == CONST_INT + && (INTVAL (operands[1]) == 8 || INTVAL (operands[1]) == 16) + && GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) % INTVAL (operands[1]) == 0 + && (GET_CODE (operands[0]) == REG + || ! mode_dependent_address_p (XEXP (operands[0], 0)))" + "* +{ + if (REG_P (operands[0])) + { + if (INTVAL (operands[1]) + INTVAL (operands[2]) != 32) + return \"bfins %3,%0{%b2:%b1}\"; + } + else + operands[0] + = adj_offsettable_operand (operands[0], INTVAL (operands[2]) / 8); + + if (GET_CODE (operands[3]) == MEM) + operands[3] = adj_offsettable_operand (operands[3], + (32 - INTVAL (operands[1])) / 8); + if (INTVAL (operands[1]) == 8) + return \"move%.b %3,%0\"; + return \"move%.w %3,%0\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=&d") + (zero_extract:SI (match_operand:SI 1 "nonimmediate_operand" "do") + (match_operand:SI 2 "immediate_operand" "i") + (match_operand:SI 3 "immediate_operand" "i")))] + "TARGET_68020 && TARGET_BITFIELD + && GET_CODE (operands[2]) == CONST_INT + && (INTVAL (operands[2]) == 8 || INTVAL (operands[2]) == 16) + && GET_CODE (operands[3]) == CONST_INT + && INTVAL (operands[3]) % INTVAL (operands[2]) == 0 + && (GET_CODE (operands[1]) == REG + || ! mode_dependent_address_p (XEXP (operands[1], 0)))" + "* +{ + cc_status.flags |= CC_NOT_NEGATIVE; + if (REG_P (operands[1])) + { + if (INTVAL (operands[2]) + INTVAL (operands[3]) != 32) + return \"bfextu %1{%b3:%b2},%0\"; + } + else + operands[1] + = adj_offsettable_operand (operands[1], INTVAL (operands[3]) / 8); + + output_asm_insn (\"clr%.l %0\", operands); + if (GET_CODE (operands[0]) == MEM) + operands[0] = adj_offsettable_operand (operands[0], + (32 - INTVAL (operands[1])) / 8); + if (INTVAL (operands[2]) == 8) + return \"move%.b %1,%0\"; + return \"move%.w %1,%0\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=d") + (sign_extract:SI (match_operand:SI 1 "nonimmediate_operand" "do") + (match_operand:SI 2 "immediate_operand" "i") + (match_operand:SI 3 "immediate_operand" "i")))] + "TARGET_68020 && TARGET_BITFIELD + && GET_CODE (operands[2]) == CONST_INT + && (INTVAL (operands[2]) == 8 || INTVAL (operands[2]) == 16) + && GET_CODE (operands[3]) == CONST_INT + && INTVAL (operands[3]) % INTVAL (operands[2]) == 0 + && (GET_CODE (operands[1]) == REG + || ! mode_dependent_address_p (XEXP (operands[1], 0)))" + "* +{ + if (REG_P (operands[1])) + { + if (INTVAL (operands[2]) + INTVAL (operands[3]) != 32) + return \"bfexts %1{%b3:%b2},%0\"; + } + else + operands[1] + = adj_offsettable_operand (operands[1], INTVAL (operands[3]) / 8); + + if (INTVAL (operands[2]) == 8) + return \"move%.b %1,%0\;extb%.l %0\"; + return \"move%.w %1,%0\;ext%.l %0\"; +}") + +;; Bit field instructions, general cases. +;; "o,d" constraint causes a nonoffsettable memref to match the "o" +;; so that its address is reloaded. + +(define_insn "extv" + [(set (match_operand:SI 0 "general_operand" "=d,d") + (sign_extract:SI (match_operand:QI 1 "nonimmediate_operand" "o,d") + (match_operand:SI 2 "general_operand" "di,di") + (match_operand:SI 3 "general_operand" "di,di")))] + "TARGET_68020 && TARGET_BITFIELD" + "bfexts %1{%b3:%b2},%0") + +(define_insn "extzv" + [(set (match_operand:SI 0 "general_operand" "=d,d") + (zero_extract:SI (match_operand:QI 1 "nonimmediate_operand" "o,d") + (match_operand:SI 2 "general_operand" "di,di") + (match_operand:SI 3 "general_operand" "di,di")))] + "TARGET_68020 && TARGET_BITFIELD" + "* +{ + cc_status.flags |= CC_NOT_NEGATIVE; + return \"bfextu %1{%b3:%b2},%0\"; +}") + +(define_insn "" + [(set (zero_extract:SI (match_operand:QI 0 "nonimmediate_operand" "+o,d") + (match_operand:SI 1 "general_operand" "di,di") + (match_operand:SI 2 "general_operand" "di,di")) + (xor:SI (zero_extract:SI (match_dup 0) (match_dup 1) (match_dup 2)) + (match_operand 3 "immediate_operand" "i,i")))] + "TARGET_68020 && TARGET_BITFIELD + && GET_CODE (operands[3]) == CONST_INT + && (INTVAL (operands[3]) == -1 + || (GET_CODE (operands[1]) == CONST_INT + && (~ INTVAL (operands[3]) & ((1 << INTVAL (operands[1]))- 1)) == 0))" + "* +{ + CC_STATUS_INIT; + return \"bfchg %0{%b2:%b1}\"; +}") + +(define_insn "" + [(set (zero_extract:SI (match_operand:QI 0 "nonimmediate_operand" "+o,d") + (match_operand:SI 1 "general_operand" "di,di") + (match_operand:SI 2 "general_operand" "di,di")) + (const_int 0))] + "TARGET_68020 && TARGET_BITFIELD" + "* +{ + CC_STATUS_INIT; + return \"bfclr %0{%b2:%b1}\"; +}") + +(define_insn "" + [(set (zero_extract:SI (match_operand:QI 0 "nonimmediate_operand" "+o,d") + (match_operand:SI 1 "general_operand" "di,di") + (match_operand:SI 2 "general_operand" "di,di")) + (const_int -1))] + "TARGET_68020 && TARGET_BITFIELD" + "* +{ + CC_STATUS_INIT; + return \"bfset %0{%b2:%b1}\"; +}") + +(define_insn "insv" + [(set (zero_extract:SI (match_operand:QI 0 "nonimmediate_operand" "+o,d") + (match_operand:SI 1 "general_operand" "di,di") + (match_operand:SI 2 "general_operand" "di,di")) + (match_operand:SI 3 "general_operand" "d,d"))] + "TARGET_68020 && TARGET_BITFIELD" + "bfins %3,%0{%b2:%b1}") + +;; Now recognize bit field insns that operate on registers +;; (or at least were intended to do so). + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=d") + (sign_extract:SI (match_operand:SI 1 "nonimmediate_operand" "d") + (match_operand:SI 2 "general_operand" "di") + (match_operand:SI 3 "general_operand" "di")))] + "TARGET_68020 && TARGET_BITFIELD" + "bfexts %1{%b3:%b2},%0") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=d") + (zero_extract:SI (match_operand:SI 1 "nonimmediate_operand" "d") + (match_operand:SI 2 "general_operand" "di") + (match_operand:SI 3 "general_operand" "di")))] + "TARGET_68020 && TARGET_BITFIELD" + "* +{ + cc_status.flags |= CC_NOT_NEGATIVE; + return \"bfextu %1{%b3:%b2},%0\"; +}") + +(define_insn "" + [(set (zero_extract:SI (match_operand:SI 0 "nonimmediate_operand" "+d") + (match_operand:SI 1 "general_operand" "di") + (match_operand:SI 2 "general_operand" "di")) + (const_int 0))] + "TARGET_68020 && TARGET_BITFIELD" + "* +{ + CC_STATUS_INIT; + return \"bfclr %0{%b2:%b1}\"; +}") + +(define_insn "" + [(set (zero_extract:SI (match_operand:SI 0 "nonimmediate_operand" "+d") + (match_operand:SI 1 "general_operand" "di") + (match_operand:SI 2 "general_operand" "di")) + (const_int -1))] + "TARGET_68020 && TARGET_BITFIELD" + "* +{ + CC_STATUS_INIT; + return \"bfset %0{%b2:%b1}\"; +}") + +(define_insn "" + [(set (zero_extract:SI (match_operand:SI 0 "nonimmediate_operand" "+d") + (match_operand:SI 1 "general_operand" "di") + (match_operand:SI 2 "general_operand" "di")) + (match_operand:SI 3 "general_operand" "d"))] + "TARGET_68020 && TARGET_BITFIELD" + "* +{ +#if 0 + /* These special cases are now recognized by a specific pattern. */ + if (GET_CODE (operands[1]) == CONST_INT && GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[1]) == 16 && INTVAL (operands[2]) == 16) + return \"move%.w %3,%0\"; + if (GET_CODE (operands[1]) == CONST_INT && GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[1]) == 24 && INTVAL (operands[2]) == 8) + return \"move%.b %3,%0\"; +#endif + return \"bfins %3,%0{%b2:%b1}\"; +}") + +;; Special patterns for optimizing bit-field instructions. + +(define_insn "" + [(set (cc0) + (zero_extract:SI (match_operand:QI 0 "memory_operand" "o") + (match_operand:SI 1 "general_operand" "di") + (match_operand:SI 2 "general_operand" "di")))] + "TARGET_68020 && TARGET_BITFIELD + && GET_CODE (operands[1]) == CONST_INT" + "* +{ + if (operands[1] == const1_rtx + && GET_CODE (operands[2]) == CONST_INT) + { + int width = GET_CODE (operands[0]) == REG ? 31 : 7; + return output_btst (operands, + gen_rtx (CONST_INT, VOIDmode, + width - INTVAL (operands[2])), + operands[0], + insn, 1000); + /* Pass 1000 as SIGNPOS argument so that btst will + not think we are testing the sign bit for an `and' + and assume that nonzero implies a negative result. */ + } + if (INTVAL (operands[1]) != 32) + cc_status.flags = CC_NOT_NEGATIVE; + return \"bftst %0{%b2:%b1}\"; +}") + +(define_insn "" + [(set (cc0) + (subreg:QI + (zero_extract:SI (match_operand:QI 0 "memory_operand" "o") + (match_operand:SI 1 "general_operand" "di") + (match_operand:SI 2 "general_operand" "di")) + 0))] + "TARGET_68020 && TARGET_BITFIELD + && GET_CODE (operands[1]) == CONST_INT" + "* +{ + if (operands[1] == const1_rtx + && GET_CODE (operands[2]) == CONST_INT) + { + int width = GET_CODE (operands[0]) == REG ? 31 : 7; + return output_btst (operands, + gen_rtx (CONST_INT, VOIDmode, + width - INTVAL (operands[2])), + operands[0], + insn, 1000); + /* Pass 1000 as SIGNPOS argument so that btst will + not think we are testing the sign bit for an `and' + and assume that nonzero implies a negative result. */ + } + if (INTVAL (operands[1]) != 32) + cc_status.flags = CC_NOT_NEGATIVE; + return \"bftst %0{%b2:%b1}\"; +}") + +(define_insn "" + [(set (cc0) + (subreg:HI + (zero_extract:SI (match_operand:QI 0 "memory_operand" "o") + (match_operand:SI 1 "general_operand" "di") + (match_operand:SI 2 "general_operand" "di")) + 0))] + "TARGET_68020 && TARGET_BITFIELD + && GET_CODE (operands[1]) == CONST_INT" + "* +{ + if (operands[1] == const1_rtx + && GET_CODE (operands[2]) == CONST_INT) + { + int width = GET_CODE (operands[0]) == REG ? 31 : 7; + return output_btst (operands, + gen_rtx (CONST_INT, VOIDmode, + width - INTVAL (operands[2])), + operands[0], + insn, 1000); + /* Pass 1000 as SIGNPOS argument so that btst will + not think we are testing the sign bit for an `and' + and assume that nonzero implies a negative result. */ + } + if (INTVAL (operands[1]) != 32) + cc_status.flags = CC_NOT_NEGATIVE; + return \"bftst %0{%b2:%b1}\"; +}") + +;;; now handle the register cases +(define_insn "" + [(set (cc0) + (zero_extract:SI (match_operand:SI 0 "nonimmediate_operand" "d") + (match_operand:SI 1 "general_operand" "di") + (match_operand:SI 2 "general_operand" "di")))] + "TARGET_68020 && TARGET_BITFIELD + && GET_CODE (operands[1]) == CONST_INT" + "* +{ + if (operands[1] == const1_rtx + && GET_CODE (operands[2]) == CONST_INT) + { + int width = GET_CODE (operands[0]) == REG ? 31 : 7; + return output_btst (operands, + gen_rtx (CONST_INT, VOIDmode, + width - INTVAL (operands[2])), + operands[0], + insn, 1000); + /* Pass 1000 as SIGNPOS argument so that btst will + not think we are testing the sign bit for an `and' + and assume that nonzero implies a negative result. */ + } + if (INTVAL (operands[1]) != 32) + cc_status.flags = CC_NOT_NEGATIVE; + return \"bftst %0{%b2:%b1}\"; +}") + +(define_insn "" + [(set (cc0) + (subreg:QI + (zero_extract:SI (match_operand:SI 0 "nonimmediate_operand" "d") + (match_operand:SI 1 "general_operand" "di") + (match_operand:SI 2 "general_operand" "di")) + 0))] + "TARGET_68020 && TARGET_BITFIELD + && GET_CODE (operands[1]) == CONST_INT" + "* +{ + if (operands[1] == const1_rtx + && GET_CODE (operands[2]) == CONST_INT) + { + int width = GET_CODE (operands[0]) == REG ? 31 : 7; + return output_btst (operands, + gen_rtx (CONST_INT, VOIDmode, + width - INTVAL (operands[2])), + operands[0], + insn, 1000); + /* Pass 1000 as SIGNPOS argument so that btst will + not think we are testing the sign bit for an `and' + and assume that nonzero implies a negative result. */ + } + if (INTVAL (operands[1]) != 32) + cc_status.flags = CC_NOT_NEGATIVE; + return \"bftst %0{%b2:%b1}\"; +}") + +(define_insn "" + [(set (cc0) + (subreg:HI + (zero_extract:SI (match_operand:SI 0 "nonimmediate_operand" "d") + (match_operand:SI 1 "general_operand" "di") + (match_operand:SI 2 "general_operand" "di")) + 0))] + "TARGET_68020 && TARGET_BITFIELD + && GET_CODE (operands[1]) == CONST_INT" + "* +{ + if (operands[1] == const1_rtx + && GET_CODE (operands[2]) == CONST_INT) + { + int width = GET_CODE (operands[0]) == REG ? 31 : 7; + return output_btst (operands, + gen_rtx (CONST_INT, VOIDmode, + width - INTVAL (operands[2])), + operands[0], + insn, 1000); + /* Pass 1000 as SIGNPOS argument so that btst will + not think we are testing the sign bit for an `and' + and assume that nonzero implies a negative result. */ + } + if (INTVAL (operands[1]) != 32) + cc_status.flags = CC_NOT_NEGATIVE; + return \"bftst %0{%b2:%b1}\"; +}") + +(define_insn "seq" + [(set (match_operand:QI 0 "general_operand" "=d") + (eq (cc0) (const_int 0)))] + "" + "* + cc_status = cc_prev_status; + OUTPUT_JUMP (\"seq %0\", \"fseq %0\", \"seq %0\"); +") + +(define_insn "sne" + [(set (match_operand:QI 0 "general_operand" "=d") + (ne (cc0) (const_int 0)))] + "" + "* + cc_status = cc_prev_status; + OUTPUT_JUMP (\"sne %0\", \"fsne %0\", \"sne %0\"); +") + +(define_insn "sgt" + [(set (match_operand:QI 0 "general_operand" "=d") + (gt (cc0) (const_int 0)))] + "" + "* + cc_status = cc_prev_status; + OUTPUT_JUMP (\"sgt %0\", \"fsgt %0\", 0); +") + +(define_insn "sgtu" + [(set (match_operand:QI 0 "general_operand" "=d") + (gtu (cc0) (const_int 0)))] + "" + "* cc_status = cc_prev_status; + return \"shi %0\"; ") + +(define_insn "slt" + [(set (match_operand:QI 0 "general_operand" "=d") + (lt (cc0) (const_int 0)))] + "" + "* cc_status = cc_prev_status; + OUTPUT_JUMP (\"slt %0\", \"fslt %0\", \"smi %0\"); ") + +(define_insn "sltu" + [(set (match_operand:QI 0 "general_operand" "=d") + (ltu (cc0) (const_int 0)))] + "" + "* cc_status = cc_prev_status; + return \"scs %0\"; ") + +(define_insn "sge" + [(set (match_operand:QI 0 "general_operand" "=d") + (ge (cc0) (const_int 0)))] + "" + "* cc_status = cc_prev_status; + OUTPUT_JUMP (\"sge %0\", \"fsge %0\", \"spl %0\"); ") + +(define_insn "sgeu" + [(set (match_operand:QI 0 "general_operand" "=d") + (geu (cc0) (const_int 0)))] + "" + "* cc_status = cc_prev_status; + return \"scc %0\"; ") + +(define_insn "sle" + [(set (match_operand:QI 0 "general_operand" "=d") + (le (cc0) (const_int 0)))] + "" + "* + cc_status = cc_prev_status; + OUTPUT_JUMP (\"sle %0\", \"fsle %0\", 0); +") + +(define_insn "sleu" + [(set (match_operand:QI 0 "general_operand" "=d") + (leu (cc0) (const_int 0)))] + "" + "* cc_status = cc_prev_status; + return \"sls %0\"; ") + +;; Basic conditional jump instructions. + +(define_insn "beq" + [(set (pc) + (if_then_else (eq (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +{ +#ifdef MOTOROLA + OUTPUT_JUMP (\"jbeq %l0\", \"fbeq %l0\", \"jbeq %l0\"); +#else + OUTPUT_JUMP (\"jeq %l0\", \"fjeq %l0\", \"jeq %l0\"); +#endif +}") + +(define_insn "bne" + [(set (pc) + (if_then_else (ne (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +{ +#ifdef MOTOROLA + OUTPUT_JUMP (\"jbne %l0\", \"fbne %l0\", \"jbne %l0\"); +#else + OUTPUT_JUMP (\"jne %l0\", \"fjne %l0\", \"jne %l0\"); +#endif +}") + +(define_insn "bgt" + [(set (pc) + (if_then_else (gt (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +#ifdef MOTOROLA + OUTPUT_JUMP (\"jbgt %l0\", \"fbgt %l0\", 0); +#else + OUTPUT_JUMP (\"jgt %l0\", \"fjgt %l0\", 0); +#endif +") + +(define_insn "bgtu" + [(set (pc) + (if_then_else (gtu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +#ifdef MOTOROLA + return \"jbhi %l0\"; +#else + return \"jhi %l0\"; +#endif +") + +(define_insn "blt" + [(set (pc) + (if_then_else (lt (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +#ifdef MOTOROLA + OUTPUT_JUMP (\"jblt %l0\", \"fblt %l0\", \"jbmi %l0\"); +#else + OUTPUT_JUMP (\"jlt %l0\", \"fjlt %l0\", \"jmi %l0\"); +#endif +") + +(define_insn "bltu" + [(set (pc) + (if_then_else (ltu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +#ifdef MOTOROLA + return \"jbcs %l0\"; +#else + return \"jcs %l0\"; +#endif +") + +(define_insn "bge" + [(set (pc) + (if_then_else (ge (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +#ifdef MOTOROLA + OUTPUT_JUMP (\"jbge %l0\", \"fbge %l0\", \"jbpl %l0\"); +#else + OUTPUT_JUMP (\"jge %l0\", \"fjge %l0\", \"jpl %l0\"); +#endif +") + +(define_insn "bgeu" + [(set (pc) + (if_then_else (geu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +#ifdef MOTOROLA + return \"jbcc %l0\"; +#else + return \"jcc %l0\"; +#endif +") + +(define_insn "ble" + [(set (pc) + (if_then_else (le (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +#ifdef MOTOROLA + OUTPUT_JUMP (\"jble %l0\", \"fble %l0\", 0); +#else + OUTPUT_JUMP (\"jle %l0\", \"fjle %l0\", 0); +#endif +") + +(define_insn "bleu" + [(set (pc) + (if_then_else (leu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +#ifdef MOTOROLA + return \"jbls %l0\"; +#else + return \"jls %l0\"; +#endif +") + +;; Negated conditional jump instructions. + +(define_insn "" + [(set (pc) + (if_then_else (eq (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* +{ +#ifdef MOTOROLA + OUTPUT_JUMP (\"jbne %l0\", \"fbne %l0\", \"jbne %l0\"); +#else + OUTPUT_JUMP (\"jne %l0\", \"fjne %l0\", \"jne %l0\"); +#endif +}") + +(define_insn "" + [(set (pc) + (if_then_else (ne (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* +{ +#ifdef MOTOROLA + OUTPUT_JUMP (\"jbeq %l0\", \"fbeq %l0\", \"jbeq %l0\"); +#else + OUTPUT_JUMP (\"jeq %l0\", \"fjeq %l0\", \"jeq %l0\"); +#endif +}") + +(define_insn "" + [(set (pc) + (if_then_else (gt (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* +#ifdef MOTOROLA + OUTPUT_JUMP (\"jble %l0\", \"fbngt %l0\", 0); +#else + OUTPUT_JUMP (\"jle %l0\", \"fjngt %l0\", 0); +#endif +") + +(define_insn "" + [(set (pc) + (if_then_else (gtu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* +#ifdef MOTOROLA + return \"jbls %l0\"; +#else + return \"jls %l0\"; +#endif +") + +(define_insn "" + [(set (pc) + (if_then_else (lt (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* +#ifdef MOTOROLA + OUTPUT_JUMP (\"jbge %l0\", \"fbnlt %l0\", \"jbpl %l0\"); +#else + OUTPUT_JUMP (\"jge %l0\", \"fjnlt %l0\", \"jpl %l0\"); +#endif +") + +(define_insn "" + [(set (pc) + (if_then_else (ltu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* +#ifdef MOTOROLA + return \"jbcc %l0\"; +#else + return \"jcc %l0\"; +#endif +") + +(define_insn "" + [(set (pc) + (if_then_else (ge (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* +#ifdef MOTOROLA + OUTPUT_JUMP (\"jblt %l0\", \"fbnge %l0\", \"jbmi %l0\"); +#else + OUTPUT_JUMP (\"jlt %l0\", \"fjnge %l0\", \"jmi %l0\"); +#endif +") + +(define_insn "" + [(set (pc) + (if_then_else (geu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* +#ifdef MOTOROLA + return \"jbcs %l0\"; +#else + return \"jcs %l0\"; +#endif +") + +(define_insn "" + [(set (pc) + (if_then_else (le (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* +#ifdef MOTOROLA + OUTPUT_JUMP (\"jbgt %l0\", \"fbnle %l0\", 0); +#else + OUTPUT_JUMP (\"jgt %l0\", \"fjnle %l0\", 0); +#endif +") + +(define_insn "" + [(set (pc) + (if_then_else (leu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* +#ifdef MOTOROLA + return \"jbhi %l0\"; +#else + return \"jhi %l0\"; +#endif +") + +;; Subroutines of "casesi". + +(define_expand "casesi_1" + [(set (match_operand:SI 3 "general_operand" "") + (plus:SI (match_operand:SI 0 "general_operand" "") + ;; Note operand 1 has been negated! + (match_operand:SI 1 "immediate_operand" ""))) + (set (cc0) (compare (match_operand:SI 2 "general_operand" "") + (match_dup 3))) + (set (pc) (if_then_else (ltu (cc0) (const_int 0)) + (label_ref (match_operand 4 "" "")) (pc)))] + "" + "") + +(define_expand "casesi_2" + [(set (match_operand:SI 0 "" "") (mem:HI (match_operand:SI 1 "" ""))) + ;; The USE here is so that at least one jump-insn will refer to the label, + ;; to keep it alive in jump_optimize. + (parallel [(set (pc) + (plus:SI (pc) (match_dup 0))) + (use (label_ref (match_operand 2 "" "")))])] + "" + "") + +;; Operand 0 is index (in bytes); operand 1 is minimum, operand 2 themaximum; +;; operand 3 is CODE_LABEL for the table; +;; operand 4 is the CODE_LABEL to go to if index out of range. +(define_expand "casesi" + ;; We don't use these for generating the RTL, but we must describe + ;; the operands here. + [(match_operand:SI 0 "general_operand" "") + (match_operand:SI 1 "immediate_operand" "") + (match_operand:SI 2 "general_operand" "") + (match_operand 3 "" "") + (match_operand 4 "" "")] + "" + " +{ + rtx table_elt_addr; + rtx index_diff; + + operands[1] = negate_rtx (SImode, operands[1]); + index_diff = gen_reg_rtx (SImode); + /* Emit the first few insns. */ + emit_insn (gen_casesi_1 (operands[0], operands[1], operands[2], + index_diff, operands[4])); + /* Construct a memory address. This may emit some insns. */ + table_elt_addr + = memory_address_noforce + (HImode, + gen_rtx (PLUS, Pmode, + gen_rtx (MULT, Pmode, index_diff, + gen_rtx (CONST_INT, VOIDmode, 2)), + gen_rtx (LABEL_REF, VOIDmode, operands[3]))); + /* Emit the last few insns. */ + emit_insn (gen_casesi_2 (gen_reg_rtx (HImode), table_elt_addr, operands[3])); + DONE; +}") + +;; Recognize one of the insns resulting from casesi_2. +(define_insn "" + [(set (pc) + (plus:SI (pc) (match_operand:HI 0 "general_operand" "r"))) + (use (label_ref (match_operand 1 "" "")))] + "" + "* +{ +#ifdef ASM_RETURN_CASE_JUMP + ASM_RETURN_CASE_JUMP; +#else +#ifdef SGS +#ifdef ASM_OUTPUT_CASE_LABEL + return \"jmp 6(%%pc,%0.w)\"; +#else + return \"jmp 2(%%pc,%0.w)\"; +#endif +#else /* not SGS */ +#ifdef MOTOROLA + return \"jmp (2,pc,%0.w)\"; +#else + return \"jmp pc@(2,%0:w)\"; +#endif +#endif +#endif /* no ASM_RETURN_CASE_JUMP */ +}") + +;; Unconditional and other jump instructions +(define_insn "jump" + [(set (pc) + (label_ref (match_operand 0 "" "")))] + "" + "* +#ifdef MOTOROLA + return \"jbra %l0\"; +#else + return \"jra %l0\"; +#endif +") + +(define_insn "" + [(set (pc) + (if_then_else + (ne (compare (plus:HI (match_operand:HI 0 "general_operand" "=g") + (const_int -1)) + (const_int -1)) + (const_int 0)) + (label_ref (match_operand 1 "" "")) + (pc))) + (set (match_dup 0) + (plus:HI (match_dup 0) + (const_int -1)))] + "" + "* +{ + CC_STATUS_INIT; + if (DATA_REG_P (operands[0])) + return \"dbra %0,%l1\"; + if (GET_CODE (operands[0]) == MEM) + { +#ifdef MOTOROLA +#ifdef NO_ADDSUB_Q + return \"sub%.w %#1,%0\;jbcc %l1\"; +#else + return \"subq%.w %#1,%0\;jbcc %l1\"; +#endif +#else /* not MOTOROLA */ + return \"subqw %#1,%0\;jcc %l1\"; +#endif + } +#ifdef MOTOROLA +#ifdef HPUX_ASM +#ifndef NO_ADDSUB_Q + return \"sub%.w %#1,%0\;cmp%.w %0,%#-1\;jbne %l1\"; +#else + return \"subq%.w %#1,%0\;cmp%.w %0,%#-1\;jbne %l1\"; +#endif +#else /* not HPUX_ASM */ + return \"subq%.w %#1,%0\;cmp%.w %#-1,%0\;jbne %l1\"; +#endif +#else /* not MOTOROLA */ + return \"subqw %#1,%0\;cmpw %#-1,%0\;jne %l1\"; +#endif +}") + +(define_insn "" + [(set (pc) + (if_then_else + (ne (compare (plus:SI (match_operand:SI 0 "general_operand" "=g") + (const_int -1)) + (const_int -1)) + (const_int 0)) + (label_ref (match_operand 1 "" "")) + (pc))) + (set (match_dup 0) + (plus:SI (match_dup 0) + (const_int -1)))] + "" + "* +{ + CC_STATUS_INIT; +#ifdef MOTOROLA +#ifndef NO_ADDSUB_Q + if (DATA_REG_P (operands[0])) + return \"dbra %0,%l1\;clr.w %0\;sub.l %#1,%0\;jbcc %l1\"; + if (GET_CODE (operands[0]) == MEM) + return \"sub.l %#1,%0\;jbcc %l1\"; +#else + if (DATA_REG_P (operands[0])) + return \"dbra %0,%l1\;clr.w %0\;subq.l %#1,%0\;jbcc %l1\"; + if (GET_CODE (operands[0]) == MEM) + return \"subq.l %#1,%0\;jbcc %l1\"; +#endif /* not NO_ADDSUB_Q */ +#ifdef HPUX_ASM +#ifndef NO_ADDSUB_Q + return \"sub.l %#1,%0\;cmp.l %0,%#-1\;jbne %l1\"; +#else + return \"subq.l %#1,%0\;cmp.l %0,%#-1\;jbne %l1\"; +#endif +#else + return \"subq.l %#1,%0\;cmp.l %#-1,%0\;jbne %l1\"; +#endif +#else + if (DATA_REG_P (operands[0])) + return \"dbra %0,%l1\;clrw %0\;subql %#1,%0\;jcc %l1\"; + if (GET_CODE (operands[0]) == MEM) + return \"subql %#1,%0\;jcc %l1\"; + return \"subql %#1,%0\;cmpl %#-1,%0\;jne %l1\"; +#endif +}") + +;; dbra patterns that use REG_NOTES info generated by strength_reduce. + +(define_insn "" + [(set (pc) + (if_then_else + (ge (plus:SI (match_operand:SI 0 "general_operand" "=g") + (const_int -1)) + (const_int 0)) + (label_ref (match_operand 1 "" "")) + (pc))) + (set (match_dup 0) + (plus:SI (match_dup 0) + (const_int -1)))] + "find_reg_note (insn, REG_NONNEG, 0)" + "* +{ + CC_STATUS_INIT; +#ifdef MOTOROLA +#ifndef NO_ADDSUB_Q + if (DATA_REG_P (operands[0])) + return \"dbra %0,%l1\;clr.w %0\;sub.l %#1,%0\;jbcc %l1\"; + if (GET_CODE (operands[0]) == MEM) + return \"sub.l %#1,%0\;jbcc %l1\"; +#else + if (DATA_REG_P (operands[0])) + return \"dbra %0,%l1\;clr.w %0\;subq.l %#1,%0\;jbcc %l1\"; + if (GET_CODE (operands[0]) == MEM) + return \"subq.l %#1,%0\;jbcc %l1\"; +#endif +#ifdef HPUX_ASM +#ifndef NO_ADDSUB_Q + return \"sub.l %#1,%0\;cmp.l %0,%#-1\;jbne %l1\"; +#else + return \"subq.l %#1,%0\;cmp.l %0,%#-1\;jbne %l1\"; +#endif +#else + return \"subq.l %#1,%0\;cmp.l %#-1,%0\;jbne %l1\"; +#endif +#else + if (DATA_REG_P (operands[0])) + return \"dbra %0,%l1\;clrw %0\;subql %#1,%0\;jcc %l1\"; + if (GET_CODE (operands[0]) == MEM) + return \"subql %#1,%0\;jcc %l1\"; + return \"subql %#1,%0\;cmpl %#-1,%0\;jne %l1\"; +#endif +}") + +;; Call subroutine with no return value. +(define_insn "call" + [(call (match_operand:QI 0 "general_operand" "o") + (match_operand:SI 1 "general_operand" "g"))] + ;; Operand 1 not really used on the m68000. + + "" + "* +#ifdef MOTOROLA + return \"jsr %0\"; +#else + return \"jbsr %0\"; +#endif +") + +;; Call subroutine, returning value in operand 0 +;; (which must be a hard register). +(define_insn "call_value" + [(set (match_operand 0 "" "=rf") + (call (match_operand:QI 1 "general_operand" "o") + (match_operand:SI 2 "general_operand" "g")))] + ;; Operand 2 not really used on the m68000. + "" + "* +#ifdef MOTOROLA + return \"jsr %1\"; +#else + return \"jbsr %1\"; +#endif +") + +(define_insn "nop" + [(const_int 0)] + "" + "nop") + +;; This should not be used unless the add/sub insns can't be. + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=a") + (match_operand:QI 1 "address_operand" "p"))] + "" + "lea %a1,%0") + +;; This is the first machine-dependent peephole optimization. +;; It is useful when a floating value is returned from a function call +;; and then is moved into an FP register. +;; But it is mainly intended to test the support for these optimizations. + +(define_peephole + [(set (reg:SI 15) (plus:SI (reg:SI 15) (const_int 4))) + (set (match_operand:DF 0 "register_operand" "f") + (match_operand:DF 1 "register_operand" "ad"))] + "FP_REG_P (operands[0]) && ! FP_REG_P (operands[1])" + "* +{ + rtx xoperands[2]; + xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1); + output_asm_insn (\"move%.l %1,%@\", xoperands); + output_asm_insn (\"move%.l %1,%-\", operands); + return \"fmove%.d %+,%0\"; +} +") + +;; FPA multiply and add. +(define_insn "" + [(set (match_operand:DF 0 "register_operand" "=x,y,y") + (plus:DF (mult:DF (match_operand:DF 1 "general_operand" "%x,dmF,y") + (match_operand:DF 2 "general_operand" "xH,y,y")) + (match_operand:DF 3 "general_operand" "xH,y,dmF")))] + "TARGET_FPA" + "* +{ + if (which_alternative == 0) + return \"fpma%.d %1,%w2,%w3,%0\"; + return \"fpma%.d %x1,%x2,%x3,%0\"; +}") + +(define_insn "" + [(set (match_operand:DF 0 "register_operand" "=x,y,y") + (plus:DF (match_operand:DF 1 "general_operand" "xH,y,dmF") + (mult:DF (match_operand:DF 2 "general_operand" "%x,dmF,y") + (match_operand:DF 3 "general_operand" "xH,y,y"))))] + "TARGET_FPA" + "* +{ + if (which_alternative == 0) + return \"fpma%.d %2,%w3,%w1,%0\"; + return \"fpma%.d %x2,%x3,%x1,%0\"; +}") + +(define_insn "" + [(set (match_operand:SF 0 "register_operand" "=x,y,y") + (plus:SF (mult:SF (match_operand:SF 1 "general_operand" "%x,ydmF,y") + (match_operand:SF 2 "general_operand" "xH,y,ydmF")) + (match_operand:SF 3 "general_operand" "xH,ydmF,ydmF")))] + "TARGET_FPA" + "* +{ + if (which_alternative == 0) + return \"fpma%.s %1,%w2,%w3,%0\"; + return \"fpma%.s %1,%2,%3,%0\"; +}") + +(define_insn "" + [(set (match_operand:SF 0 "register_operand" "=x,y,y") + (plus:SF (match_operand:SF 1 "general_operand" "xH,ydmF,ydmF") + (mult:SF (match_operand:SF 2 "general_operand" "%x,ydmF,y") + (match_operand:SF 3 "general_operand" "xH,y,ydmF"))))] + "TARGET_FPA" + "* +{ + if (which_alternative == 0) + return \"fpma%.s %2,%w3,%w1,%0\"; + return \"fpma%.s %2,%3,%1,%0\"; +}") + +;; FPA Multiply and subtract +(define_insn "" + [(set (match_operand:DF 0 "register_operand" "=x,y,y") + (minus:DF (match_operand:DF 1 "general_operand" "xH,rmF,y") + (mult:DF (match_operand:DF 2 "register_operand" "%xH,y,y") + (match_operand:DF 3 "general_operand" "x,y,rmF"))))] + "TARGET_FPA" + "* +{ + if (which_alternative == 0) + return \"fpms%.d %3,%w2,%w1,%0\"; + return \"fpms%.d %x3,%2,%x1,%0\"; +}") + +(define_insn "" + [(set (match_operand:SF 0 "register_operand" "=x,y,y") + (minus:SF (match_operand:SF 1 "general_operand" "xH,rmF,yrmF") + (mult:SF (match_operand:SF 2 "register_operand" "%xH,rmF,y") + (match_operand:SF 3 "general_operand" "x,y,yrmF"))))] + "TARGET_FPA" + "* +{ + if (which_alternative == 0) + return \"fpms%.s %3,%w2,%w1,%0\"; + return \"fpms%.s %3,%2,%1,%0\"; +}") + +(define_insn "" + [(set (match_operand:DF 0 "register_operand" "=x,y,y") + (minus:DF (mult:DF (match_operand:DF 1 "register_operand" "%xH,y,y") + (match_operand:DF 2 "general_operand" "x,y,rmF")) + (match_operand:DF 3 "general_operand" "xH,rmF,y")))] + "TARGET_FPA" + "* +{ + if (which_alternative == 0) + return \"fpmr%.d %2,%w1,%w3,%0\"; + return \"fpmr%.d %x2,%1,%x3,%0\"; +}") + +(define_insn "" + [(set (match_operand:SF 0 "register_operand" "=x,y,y") + (minus:SF (mult:SF (match_operand:SF 1 "register_operand" "%xH,rmF,y") + (match_operand:SF 2 "general_operand" "x,y,yrmF")) + (match_operand:SF 3 "general_operand" "xH,rmF,yrmF")))] + "TARGET_FPA" + "* +{ + if (which_alternative == 0) + return \"fpmr%.s %2,%w1,%w3,%0\"; + return \"fpmr%.s %x2,%1,%x3,%0\"; +}") + +;; FPA Add and multiply +(define_insn "" + [(set (match_operand:DF 0 "register_operand" "=x,y,y") + (mult:DF (plus:DF (match_operand:DF 1 "register_operand" "%xH,y,y") + (match_operand:DF 2 "general_operand" "x,y,rmF")) + (match_operand:DF 3 "general_operand" "xH,rmF,y")))] + "TARGET_FPA" + "* +{ + if (which_alternative == 0) + return \"fpam%.d %2,%w1,%w3,%0\"; + return \"fpam%.d %x2,%1,%x3,%0\"; +}") + +(define_insn "" + [(set (match_operand:DF 0 "register_operand" "=x,y,y") + (mult:DF (match_operand:DF 1 "general_operand" "xH,rmF,y") + (plus:DF (match_operand:DF 2 "register_operand" "%xH,y,y") + (match_operand:DF 3 "general_operand" "x,y,rmF"))))] + "TARGET_FPA" + "* +{ + if (which_alternative == 0) + return \"fpam%.d %3,%w2,%w1,%0\"; + return \"fpam%.d %x3,%2,%x1,%0\"; +}") + +(define_insn "" + [(set (match_operand:SF 0 "register_operand" "=x,y,y") + (mult:SF (plus:SF (match_operand:SF 1 "register_operand" "%xH,rmF,y") + (match_operand:SF 2 "general_operand" "x,y,yrmF")) + (match_operand:SF 3 "general_operand" "xH,rmF,yrmF")))] + "TARGET_FPA" + "* +{ + if (which_alternative == 0) + return \"fpam%.s %2,%w1,%w3,%0\"; + return \"fpam%.s %x2,%1,%x3,%0\"; +}") + +(define_insn "" + [(set (match_operand:SF 0 "register_operand" "=x,y,y") + (mult:SF (match_operand:SF 1 "general_operand" "xH,rmF,yrmF") + (plus:SF (match_operand:SF 2 "register_operand" "%xH,rmF,y") + (match_operand:SF 3 "general_operand" "x,y,yrmF"))))] + "TARGET_FPA" + "* +{ + if (which_alternative == 0) + return \"fpam%.s %3,%w2,%w1,%0\"; + return \"fpam%.s %x3,%2,%x1,%0\"; +}") + +;;FPA Subtract and multiply +(define_insn "" + [(set (match_operand:DF 0 "register_operand" "=x,y,y") + (mult:DF (minus:DF (match_operand:DF 1 "register_operand" "xH,y,y") + (match_operand:DF 2 "general_operand" "x,y,rmF")) + (match_operand:DF 3 "general_operand" "xH,rmF,y")))] + "TARGET_FPA" + "* +{ + if (which_alternative == 0) + return \"fpsm%.d %2,%w1,%w3,%0\"; + return \"fpsm%.d %x2,%1,%x3,%0\"; +}") + +(define_insn "" + [(set (match_operand:DF 0 "register_operand" "=x,y,y") + (mult:DF (match_operand:DF 1 "general_operand" "xH,rmF,y") + (minus:DF (match_operand:DF 2 "register_operand" "xH,y,y") + (match_operand:DF 3 "general_operand" "x,y,rmF"))))] + "TARGET_FPA" + "* +{ + if (which_alternative == 0) + return \"fpsm%.d %3,%w2,%w1,%0\"; + return \"fpsm%.d %x3,%2,%x1,%0\"; +}") + +(define_insn "" + [(set (match_operand:SF 0 "register_operand" "=x,y,y") + (mult:SF (minus:SF (match_operand:SF 1 "register_operand" "xH,rmF,y") + (match_operand:SF 2 "general_operand" "x,y,yrmF")) + (match_operand:SF 3 "general_operand" "xH,rmF,yrmF")))] + "TARGET_FPA" + "* +{ + if (which_alternative == 0) + return \"fpsm%.s %2,%w1,%w3,%0\"; + return \"fpsm%.s %x2,%1,%x3,%0\"; +}") + +(define_insn "" + [(set (match_operand:SF 0 "register_operand" "=x,y,y") + (mult:SF (match_operand:SF 1 "general_operand" "xH,rmF,yrmF") + (minus:SF (match_operand:SF 2 "register_operand" "xH,rmF,y") + (match_operand:SF 3 "general_operand" "x,y,yrmF"))))] + "TARGET_FPA" + "* +{ + if (which_alternative == 0) + return \"fpsm%.s %3,%w2,%w1,%0\"; + return \"fpsm%.s %x3,%2,%x1,%0\"; +}") + + +;;- Local variables: +;;- mode:emacs-lisp +;;- comment-start: ";;- " +;;- comment-start-skip: ";+- *" +;;- eval: (set-syntax-table (copy-sequence (syntax-table))) +;;- eval: (modify-syntax-entry ?[ "(]") +;;- eval: (modify-syntax-entry ?] ")[") +;;- eval: (modify-syntax-entry ?{ "(}") +;;- eval: (modify-syntax-entry ?} "){") +;;- End: diff --git a/gcc-1.40/config/m88k.md b/gcc-1.40/config/m88k.md new file mode 100644 index 0000000..366ac90 --- /dev/null +++ b/gcc-1.40/config/m88k.md @@ -0,0 +1,2273 @@ +;;- Machine description for the Motorola 88000 for GNU C compiler +;; Copyright (C) 1988 Free Software Foundation, Inc. +;; Contributed by Michael Tiemann (tiemann@mcc.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 1, 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. + + +;;- See file "rtl.def" for documentation on define_insn, match_*, et. al. + +;;- cpp macro #define NOTICE_UPDATE_CC in file tm.h handles condition code +;;- updates for most instructions. + +;;- Operand classes for the register allocator: + +;; Compare instructions. +;; This pattern is used for generating an "insn" +;; which does just a compare and sets a (fictitious) condition code. + +;; The actual the m88000 insns are compare-and-conditional-jump. +;; The define_peephole's below recognize the combinations of +;; compares and jumps, and output each pair as a single assembler insn. + +;; This controls RTL generation and register allocation. +(define_insn "cmpsi" + [(set (cc0) + (compare (match_operand:SI 0 "arith_operand" "rI") + (match_operand:SI 1 "arith_operand" "rI")))] + "" + "* +{ + if (GET_CODE (operands[0]) == CONST_INT) + { + cc_status.flags |= CC_REVERSED; + return \"cmp r25,%1,%0\"; + } + return \"cmp r25,%0,%1\"; +}") + +(define_insn "cmpdf" + [(set (cc0) + (compare (match_operand:DF 0 "nonmemory_operand" "rG") + (match_operand:DF 1 "nonmemory_operand" "rG")))] + "" + "* +{ + if (GET_CODE (operands[0]) == CONST_DOUBLE) + { + cc_status.flags |= CC_REVERSED | CC_IN_FCCR; + return \"fcmp.sdd r25,%1,%0\"; + } + cc_status.flags |= CC_IN_FCCR; + return \"fcmp.sdd r25,%0,%1\"; +}") + +(define_insn "cmpsf" + [(set (cc0) + (compare (match_operand:SF 0 "nonmemory_operand" "rG") + (match_operand:SF 1 "nonmemory_operand" "rG")))] + "" + "* +{ + if (GET_CODE (operands[0]) == CONST_DOUBLE) + { + cc_status.flags |= CC_REVERSED | CC_IN_FCCR; + return \"fcmp.sss r25,%1,%0\"; + } + cc_status.flags |= CC_IN_FCCR; + return \"fcmp.sss r25,%0,%1\"; +}") +;; We have to have this because cse can optimize the previous pattern +;; into this one. + +(define_insn "tstsi" + [(set (cc0) + (match_operand:SI 0 "register_operand" "r"))] + "" + "cmp r25,%0,0") + +(define_insn "tstdf" + [(set (cc0) + (match_operand:DF 0 "register_operand" "r"))] + "" + "* +{ + cc_status.flags |= CC_IN_FCCR; + return \"fcmp.sds r25,%0,r0\"; +}") + +(define_insn "tstsf" + [(set (cc0) + (match_operand:SF 0 "register_operand" "r"))] + "" + "* +{ + cc_status.flags |= CC_IN_FCCR; + return \"fcmp.sss r25,%0,r0\"; +}") + +;; These control RTL generation for conditional jump insns +;; and match them for register allocation. + +(define_insn "beq" + [(set (pc) + (if_then_else (eq (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "bb1 eq,r25,%l0") + +(define_peephole + [(set (cc0) + (match_operand:SI 0 "register_operand" "r")) + (set (pc) + (if_then_else (eq (cc0) + (const_int 0)) + (label_ref (match_operand 1 "" "")) + (pc)))] + "" + "* +{ + CC_STATUS_INIT; + return \"bcnd eq0,%0,%l1\"; +}") + +(define_insn "bne" + [(set (pc) + (if_then_else (ne (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "bb1 ne,r25,%l0") + +(define_peephole + [(set (cc0) + (match_operand:SI 0 "register_operand" "r")) + (set (pc) + (if_then_else (ne (cc0) + (const_int 0)) + (label_ref (match_operand 1 "" "")) + (pc)))] + "" + "* +{ + CC_STATUS_INIT; + return \"bcnd ne0,%0,%l1\"; +}") + +(define_insn "bgt" + [(set (pc) + (if_then_else (gt (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "bb1 gt,r25,%l0") + +(define_insn "bgtu" + [(set (pc) + (if_then_else (gtu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "bb1 hi,r25,%l0") + +(define_insn "blt" + [(set (pc) + (if_then_else (lt (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "bb1 lt,r25,%l0") + +(define_insn "bltu" + [(set (pc) + (if_then_else (ltu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "bb1 lo,r25,%l0") + +(define_insn "bge" + [(set (pc) + (if_then_else (ge (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "bb1 ge,r25,%l0") + +(define_insn "bgeu" + [(set (pc) + (if_then_else (geu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "bb1 hs,r25,%l0") + +(define_insn "ble" + [(set (pc) + (if_then_else (le (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "bb1 le,r25,%l0") + +(define_insn "bleu" + [(set (pc) + (if_then_else (leu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "bb1 ls,r25,%l0") + +;; These match inverted jump insns for register allocation. + +(define_insn "" + [(set (pc) + (if_then_else (eq (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "bb0 eq,r25,%l0") + +(define_peephole + [(set (cc0) (match_operand:SI 0 "register_operand" "r")) + (set (pc) + (if_then_else (eq (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 1 "" ""))))] + "" + "* +{ + CC_STATUS_INIT; + return \"bcnd ne0,%0,%l1\"; +}") + +(define_insn "" + [(set (pc) + (if_then_else (ne (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "bb0 ne,r25,%l0") + +(define_peephole + [(set (cc0) (match_operand:SI 0 "register_operand" "r")) + (set (pc) + (if_then_else (ne (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 1 "" ""))))] + "" + "* +{ + CC_STATUS_INIT; + return \"bcnd eq0,%0,%l1\"; +}") + +(define_insn "" + [(set (pc) + (if_then_else (gt (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "bb0 gt,r25,%l0") + +(define_insn "" + [(set (pc) + (if_then_else (gtu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "bb0 hi,r25,%l0") + +(define_insn "" + [(set (pc) + (if_then_else (lt (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "bb0 lt,r25,%l0") + +(define_insn "" + [(set (pc) + (if_then_else (ltu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "bb0 lo,r25,%l0") + +(define_insn "" + [(set (pc) + (if_then_else (ge (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "bb0 ge,r25,%l0") + +(define_insn "" + [(set (pc) + (if_then_else (geu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "bb0 hs,r25,%l0") + +(define_insn "" + [(set (pc) + (if_then_else (le (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "bb0 le,r25,%l0") + +(define_insn "" + [(set (pc) + (if_then_else (leu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "bb0 ls,r25,%l0") + +;; Move instructions + +(define_insn "swapsi" + [(set (match_operand:SI 0 "general_operand" "g") + (match_operand:SI 1 "general_operand" "g")) + (set (match_dup 1) (match_dup 0))] + "" + "* +{ + if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM) + { + CC_STATUS_INIT; + return \"ld r25,%0\;xmem r25,%1\;st r25,%0\"; + } + if (! REG_P (operands[1])) + return \"xmem %0,%1\"; + if (REG_P (operands[0])) + { + if (REGNO (operands[0]) == REGNO (operands[1])) + return \"\"; + return \"xor %0,%0,%1\;xor %1,%1,%0\;xor %0,%0,%1\"; + } + return \"xmem %1,%0\"; +}") + +(define_peephole + [(set (match_operand:SI 0 "register_operand" "=r") + (match_operand:SI 1 "memory_operand" "m")) + (set (match_operand:SI 2 "register_operand" "=r") + (match_operand:SI 3 "memory_operand" "m")) + (set (match_dup 1) (match_dup 2)) + (set (match_dup 3) (match_dup 0))] + "" + "* +{ + CC_STATUS_INIT; + return \"ld r25,%1\;xmem r25,%3\;st r25,%1\"; +}") + +(define_insn "swapqi" + [(set (match_operand:QI 0 "general_operand" "g") + (match_operand:QI 1 "general_operand" "g")) + (set (match_dup 1) (match_dup 0))] + "" + "* +{ + if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM) + { + CC_STATUS_INIT; + return \"ld.bu r25,%0\;xmem.bu r25,%1\;st.bu r25,%0\"; + } + if (! REG_P (operands[1])) + return \"xmem.bu %0,%1\"; + if (REG_P (operands[0])) + { + if (REGNO (operands[0]) == REGNO (operands[1])) + return \"\"; + return \"xor %0,%0,%1\;xor %1,%1,%0\;xor %0,%0,%1\"; + } + return \"xmem.bu %1,%0\"; +}") + +(define_peephole + [(set (match_operand:QI 0 "register_operand" "=r") + (match_operand:QI 1 "memory_operand" "m")) + (set (match_operand:QI 2 "register_operand" "=r") + (match_operand:QI 3 "memory_operand" "m")) + (set (match_dup 1) (match_dup 2)) + (set (match_dup 3) (match_dup 0))] + "" + "* +{ + CC_STATUS_INIT; + return \"ld.bu r25,%1\;xmem.bu r25,%3\;st.bu r25,%1\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "g") + (const_int 0))] + "" + "* +{ + if (REG_P (operands[0])) + return \"or %0,r0,0\"; + return \"st r0,%0\"; +}") + +(define_insn "movsi" + [(set (match_operand:SI 0 "general_operand" "=g,r") + (match_operand:SI 1 "general_operand" "r,mi"))] + "" + "* +{ + if (REG_P (operands[0])) + { + if (GET_CODE (operands[1]) == MEM) + return \"ld %0,%1\"; + if (GET_CODE (operands[1]) == CONST_INT) + return output_store_const_int (SImode, operands); + if (GET_CODE (operands[1]) == LABEL_REF + || GET_CODE (operands[1]) == SYMBOL_REF) + return \"lda %0,r0,%1\"; + return \"or %0,r0,%1\"; + } + return \"st %1,%0\"; +}") + +;; Simulate pre inc. Post inc/dec is automatically optimized +;; by sheer luck. ?? In which phase should this really be done?? +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "r") + (mem:SI (plus:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "arith_operand" "rI")))) + (set (match_dup 1) + (plus:SI (match_dup 1) + (match_dup 2)))] + "" + "ld %0,%1,%2\\t;; pipelined!\;addu %1,%1,%2\\t;; /") + +(define_insn "" + [(set (mem:SI (plus:SI (match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "arith_operand" "rI"))) + (match_operand:SI 2 "register_operand" "r")) + (set (match_dup 0) + (plus:SI (match_dup 0) + (match_dup 1)))] + "" + "st %2,%0,%1\\t;; pipelined!\;addu %0,%0,%1\\t;; /") + +(define_insn "" + [(set (match_operand:HI 0 "general_operand" "g") + (const_int 0))] + "" + "* +{ + if (REG_P (operands[0])) + return \"or %0,r0,0\"; + return \"st.h r0,%0\"; +}") + +(define_insn "movhi" + [(set (match_operand:HI 0 "general_operand" "=g,r") + (match_operand:HI 1 "general_operand" "r,mn"))] + "" + "* +{ + if (REG_P (operands[0])) + { + if (GET_CODE (operands[1]) == MEM) + return \"ld.h %0,%1\"; + if (GET_CODE (operands[1]) == CONST_INT) + return output_store_const_int (HImode, operands); + return \"or %0,r0,%1\"; + } + return \"st.h %1,%0\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "r") + (sign_extend:SI + (mem:HI (plus:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "arith_operand" "rI"))))) + (set (match_dup 1) + (plus:SI (match_dup 1) + (match_dup 2)))] + "" + "ld.h %0,%1,%2\\t;; pipelined!\;addu %1,%1,%2\\t;; /") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "r") + (zero_extend:SI + (mem:HI (plus:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "arith_operand" "rI"))))) + (set (match_dup 1) + (plus:SI (match_dup 1) + (match_dup 2)))] + "" + "ld.hu %0,%1,%2\\t;; pipelined!\;addu %1,%1,%2\\t;; /") + +(define_insn "" + [(set (mem:HI (plus:SI (match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "arith_operand" "rI"))) + (match_operand:SI 2 "register_operand" "r")) + (set (match_dup 0) + (plus:SI (match_dup 0) + (match_dup 1)))] + "" + "st.h %2,%0,%1\\t;; pipelined!\;addu %0,%0,%1\\t;; /") + +(define_insn "" + [(set (match_operand:QI 0 "general_operand" "g") + (const_int 0))] + "" + "* +{ + if (REG_P (operands[0])) + return \"or %0,r0,0\"; + return \"st.b r0,%0\"; +}") + +(define_insn "movqi" + [(set (match_operand:QI 0 "general_operand" "=g,r") + (match_operand:QI 1 "general_operand" "r,mn"))] + "" + "* +{ + if (REG_P (operands[0])) + { + if (GET_CODE (operands[1]) == MEM) + return \"ld.b %0,%1\"; + if (GET_CODE (operands[1]) == CONST_INT) + return output_store_const_int (QImode, operands); + return \"or %0,r0,%1\"; + } + return \"st.b %1,%0\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "r") + (sign_extend:SI + (mem:QI (plus:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "arith_operand" "rI"))))) + (set (match_dup 1) + (plus:SI (match_dup 1) + (match_dup 2)))] + "" + "ld.b %0,%1,%2\\t;; pipelined!\;addu %1,%1,%2\\t;; /") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "r") + (zero_extend:SI + (mem:QI (plus:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "arith_operand" "rI"))))) + (set (match_dup 1) + (plus:SI (match_dup 1) + (match_dup 2)))] + "" + "ld.bu %0,%1,%2\\t;; pipelined!\;addu %1,%1,%2\\t;; /") + +(define_insn "" + [(set (mem:QI (plus:SI (match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "arith_operand" "rI"))) + (match_operand:SI 2 "register_operand" "r")) + (set (match_dup 0) + (plus:SI (match_dup 0) + (match_dup 1)))] + "" + "st.b %2,%0,%1\\t;; pipelined!\;addu %0,%0,%1\\t;; /") + +;; The definition of this insn does not really explain what it does, +;; but it should suffice +;; that anything generated as this insn will be recognized as one +;; and that it won't successfully combine with anything. +(define_insn "movstrsi" + [(set (match_operand:BLK 0 "general_operand" "=g") + (match_operand:BLK 1 "general_operand" "g")) + (use (match_operand:SI 2 "arith32_operand" "rn")) + (clobber (reg:SI 10)) + (clobber (reg:SI 11)) + (clobber (reg:SI 12))] + "" + "* output_block_move (operands);") + +;; 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 "" + [(set (match_operand:DF 0 "general_operand" "=r,o") + (match_operand:DF 1 "" "mG,G"))] + "GET_CODE (operands[1]) == CONST_DOUBLE" + "* +{ + if (operands[1] == dconst0_rtx && GET_CODE (operands[0]) == REG) + { + operands[1] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); + return \"add %0,r0,0\;add %1,r0,0\"; + } + if (operands[1] == dconst0_rtx && GET_CODE (operands[0]) == MEM) + { + operands[1] = adj_offsettable_operand (operands[0], 4); + return \"st r0,%0\;st r0,%1\"; + } + return output_move_double (operands); +} +") + +(define_insn "movdf" + [(set (match_operand:DF 0 "general_operand" "=r,m") + (match_operand:DF 1 "general_operand" "rm,r"))] + "" + "* return output_move_double (operands);") + +(define_insn "movdi" + [(set (match_operand:DI 0 "general_operand" "=r,m") + (match_operand:DI 1 "general_operand" "rm,r"))] + "" + "* return output_move_double (operands);") + +(define_insn "movsf" + [(set (match_operand:SF 0 "general_operand" "=g,r") + (match_operand:SF 1 "general_operand" "r,mF"))] + "" + "* +{ + if (REG_P (operands[0])) + { + if (GET_CODE (operands[1]) == MEM) + return \"ld %0,%1\"; + if (GET_CODE (operands[1]) == CONST_DOUBLE) + return output_store_const_float (SFmode, operands); + return \"or %0,r0,%1\"; + } + return \"st %1,%0\"; +}") + +;;- load effective address +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (match_operand:QI 1 "address_operand" "p"))] + "" + "lda.b %0,%a1") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (match_operand:HI 1 "address_operand" "p"))] + "" + "lda.w %0,%a1") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (match_operand:SI 1 "address_operand" "p"))] + "" + "lda %0,%a1") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (match_operand:DI 1 "address_operand" "p"))] + "" + "lda.d %0,%a1") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (match_operand:SF 1 "address_operand" "p"))] + "" + "lda %0,%a1") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (match_operand:DF 1 "address_operand" "p"))] + "" + "lda.d %0,%a1") + +;;- truncation instructions +(define_insn "truncsiqi2" + [(set (match_operand:QI 0 "general_operand" "=g") + (truncate:QI + (match_operand:SI 1 "register_operand" "r")))] + "" + "* +{ + if (GET_CODE (operands[0]) == MEM) + return \"st.b %1,%0\"; + return \"or %0,r0,%1\"; +}") + +(define_insn "trunchiqi2" + [(set (match_operand:QI 0 "general_operand" "=g") + (truncate:QI + (match_operand:HI 1 "register_operand" "r")))] + "" + "* +{ + if (GET_CODE (operands[0]) == MEM) + return \"st.b %1,%0\"; + return \"or %0,r0,%1\"; +}") + +(define_insn "truncsihi2" + [(set (match_operand:HI 0 "general_operand" "=g") + (truncate:HI + (match_operand:SI 1 "register_operand" "r")))] + "" + "* +{ + if (GET_CODE (operands[0]) == MEM) + return \"st.h %1,%0\"; + return \"or %0,r0,%1\"; +}") + +;;- zero extension instructions + +;; Note that the one starting from HImode comes before those for QImode +;; so that a constant operand will match HImode, not QImode. + +(define_insn "zero_extendhisi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (zero_extend:SI + (match_operand:HI 1 "general_operand" "g")))] + "" + "* +{ + if (REG_P (operands[1])) + return \"mask %0,%1,0xffff\"; + if (GET_CODE (operands[1]) == CONST_INT) + return output_store_const_int (SImode, operands); + return \"ld.hu %0,%1\"; +}") + +(define_insn "zero_extendqihi2" + [(set (match_operand:HI 0 "register_operand" "=r") + (zero_extend:HI + (match_operand:QI 1 "general_operand" "g")))] + "" + "* +{ + if (REG_P (operands[1])) + return \"mask %0,%1,0xff\"; + if (GET_CODE (operands[1]) == CONST_INT) + return output_store_const_int (SImode, operands); + return \"ld.bu %0,%1\"; +}") + +(define_insn "zero_extendqisi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (zero_extend:SI + (match_operand:QI 1 "general_operand" "g")))] + "" + "* +{ + if (REG_P (operands[1])) + return \"mask %0,%1,0xff\"; + if (GET_CODE (operands[1]) == CONST_INT) + return output_store_const_int (SImode, operands); + return \"ld.bu %0,%1\"; +}") + +;;- sign extension instructions +;; Note that the one starting from HImode comes before those for QImode +;; so that a constant operand will match HImode, not QImode. + +(define_insn "extendhisi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (sign_extend:SI + (match_operand:HI 1 "general_operand" "g")))] + "" + "* +{ + if (REG_P (operands[1])) + return \"ext %0,%1,16<0>\"; + if (GET_CODE (operands[1]) == CONST_INT) + return output_store_const_int (SImode, operands); + return \"ld.h %0,%1\"; +}") + +(define_insn "extendqihi2" + [(set (match_operand:HI 0 "register_operand" "=r") + (sign_extend:HI + (match_operand:QI 1 "general_operand" "g")))] + "" + "* +{ + if (REG_P (operands[1])) + return \"ext %0,%1,8<0>\"; + if (GET_CODE (operands[1]) == CONST_INT) + return output_store_const_int (SImode, operands); + return \"ld.b %0,%1\"; +}") + +(define_insn "extendqisi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (sign_extend:SI + (match_operand:QI 1 "general_operand" "g")))] + "" + "* +{ + if (REG_P (operands[1])) + return \"ext %0,%1,8<0>\"; + if (GET_CODE (operands[1]) == CONST_INT) + return output_store_const_int (SImode, operands); + return \"ld.b %0,%1\"; +}") + +;; Conversions between float and double. + +(define_insn "extendsfdf2" + [(set (match_operand:DF 0 "general_operand" "=r") + (float_extend:DF + (match_operand:SF 1 "general_operand" "r")))] + "" + "fadd.dss %0,r0,%1") + +(define_insn "truncdfsf2" + [(set (match_operand:SF 0 "general_operand" "=r") + (float_truncate:SF + (match_operand:DF 1 "general_operand" "r")))] + "" + "fadd.ssd %0,r0,%1") +;; Conversions between floating point and integer + +(define_insn "floatsidf2" + [(set (match_operand:DF 0 "general_operand" "=r") + (float:DF (match_operand:SI 1 "general_operand" "r")))] + "" + "flt.ds %0,%1") + +(define_insn "floatsisf2" + [(set (match_operand:SF 0 "general_operand" "=r") + (float:SF (match_operand:SI 1 "general_operand" "r")))] + "" + "flt.ss %0,%1") + +(define_insn "fixdfsi2" + [(set (match_operand:SI 0 "general_operand" "=r") + (fix:SI (fix:DF (match_operand:DF 1 "general_operand" "r"))))] + "" + "int.sd %0,%1") + +(define_insn "fixsfsi2" + [(set (match_operand:SI 0 "general_operand" "=r") + (fix:SI (fix:SF (match_operand:SF 1 "general_operand" "r"))))] + "" + "int.ss %0,%1") + +;;- arithmetic instructions +;;- add instructions +(define_insn "addsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (plus:SI (match_operand:SI 1 "arith32_operand" "%r") + (match_operand:SI 2 "arith32_operand" "rn")))] + "" + "* +{ + unsigned int i; + + if (REG_P (operands[2])) + return \"addu %0,%1,%2\"; + i = INTVAL (operands[2]); + if (INT_FITS_16_BITS (i)) + return \"addu %0,%1,%2\"; + if (INT_FITS_16_BITS (-i)) + { + operands[2] = gen_rtx (CONST_INT, VOIDmode, -i); + return \"subu %0,%1,%2\"; + } + return \"or.u %0,r0,hi16(%2)\;or %0,%0,lo16(%2)\;addu %0,%1,%0\"; +}") + +(define_insn "adddf3" + [(set (match_operand:DF 0 "register_operand" "=r") + (plus:DF (match_operand:DF 1 "register_operand" "%r") + (match_operand:DF 2 "register_operand" "r")))] + "" + "fadd.ddd %0,%1,%2") + +;; a bunch more can go in here! + +(define_insn "addsf3" + [(set (match_operand:SF 0 "register_operand" "=r") + (plus:SF (match_operand:SF 1 "register_operand" "%r") + (match_operand:SF 2 "register_operand" "r")))] + "" + "fadd.sss %0,%1,%2") + +;;- subtract instructions +(define_insn "subsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (minus:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "arith32_operand" "rn")))] + "" + "* +{ + unsigned int i; + + if (REG_P (operands[2])) + return \"subu %0,%1,%2\"; + i = INTVAL (operands[2]); + if (INT_FITS_16_BITS (i)) + return \"subu %0,%1,%2\"; + if (INT_FITS_16_BITS (-i)) + { + operands[2] = gen_rtx (CONST_INT, VOIDmode, -i); + return \"addu %0,%1,%2\"; + } + return \"or.u %0,r0,hi16(%2)\;or %0,%0,lo16(%2)\;subu %0,%1,%0\"; +}") + +(define_insn "subdf3" + [(set (match_operand:DF 0 "register_operand" "=r") + (minus:DF (match_operand:DF 1 "register_operand" "%r") + (match_operand:DF 2 "register_operand" "r")))] + "" + "fsub.ddd %0,%1,%2") + +(define_insn "subsf3" + [(set (match_operand:SF 0 "register_operand" "=r") + (minus:SF (match_operand:SF 1 "register_operand" "%r") + (match_operand:SF 2 "register_operand" "r")))] + "" + "fsub.sss %0,%1,%2") + +;;- multiply instructions +(define_insn "mulsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (mult:SI (match_operand:SI 1 "register_operand" "%r") + (match_operand:SI 2 "arith32_operand" "rn")))] + "" + "* +{ + unsigned int i; + + if (REG_P (operands[2])) + return \"mul %0,%1,%2\"; + i = INTVAL (operands[2]); + if (INT_FITS_16_BITS (i)) + return \"mul %0,%1,%2\"; + return \"or.u %0,r0,hi16(%2)\;or %0,%0,lo16(%2)\;mul %0,%1,%0\"; +}") + +(define_insn "umulsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (umult:SI (match_operand:SI 1 "register_operand" "%r") + (match_operand:SI 2 "arith_operand" "rI")))] + "" + "mul %0,%1,%2") + +(define_insn "muldf3" + [(set (match_operand:DF 0 "register_operand" "=r") + (mult:DF (match_operand:DF 1 "register_operand" "%r") + (match_operand:DF 2 "register_operand" "r")))] + "" + "fmul.ddd %0,%1,%2") + +(define_insn "mulsf3" + [(set (match_operand:SF 0 "register_operand" "=r") + (mult:SF (match_operand:SF 1 "register_operand" "%r") + (match_operand:SF 2 "register_operand" "r")))] + "" + "fmul.sss %0,%1,%2") + +;;- divide instructions +(define_insn "divsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (div:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "arith32_operand" "rn")))] + "" + "* +{ + unsigned int i; + + if (REG_P (operands[2])) + return \"div %0,%1,%2\"; + i = INTVAL (operands[2]); + if (INT_FITS_16_BITS (i)) + return \"div %0,%1,%2\"; + return \"or.u %0,r0,hi16(%2)\;or %0,%0,lo16(%2)\;div %0,%1,%0\"; +}") + + +(define_insn "udivsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (udiv:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "arith_operand" "rI")))] + "" + "div %0,%1,%2") + +(define_insn "divdf3" + [(set (match_operand:DF 0 "register_operand" "=r") + (div:DF (match_operand:DF 1 "register_operand" "r") + (match_operand:DF 2 "register_operand" "r")))] + "" + "fdiv.ddd %0,%1,%2") + +(define_insn "divsf3" + [(set (match_operand:SF 0 "register_operand" "=r") + (div:SF (match_operand:SF 1 "register_operand" "r") + (match_operand:SF 2 "register_operand" "r")))] + "" + "fdiv.sss %0,%1,%2") + +;; Remainder instructions. + +(define_insn "modsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (mod:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "arith32_operand" "rn")))] + "" + "* +{ + unsigned int i; + + if (REG_P (operands[2])) + return \"div %0,%1,%2\;mul %0,%0,%2\;sub %0,%1,%0\"; + i = INTVAL (operands[2]); + if (INT_FITS_16_BITS (i)) + return \"div %0,%1,%2\;mul %0,%0,%2\;sub %0,%1,%0\"; + if (INT_FITS_16_BITS (-i)) + fatal (\"implement negative case for mod\"); + fatal (\"implement 32 bit case for mod\"); +}") + +(define_insn "umodsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (umod:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "arith_operand" "rI")))] + "" + "* +{ + unsigned int i; + + if (REG_P (operands[2])) + return \"div %0,%1,%2\;mul %0,%0,%2\;sub %0,%1,%0\"; + i = INTVAL (operands[2]); + if (INT_FITS_16_BITS (i)) + return \"div %0,%1,%2\;mul %0,%0,%2\;sub %0,%1,%0\"; + if (INT_FITS_16_BITS (-i)) + fatal (\"implement negative case for umod\"); + fatal (\"implement 32 bit case for umod\"); +}") + +(define_insn "divmodsi4" + [(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 (match_operand:SI 3 "register_operand" "=r") + (mod:SI (match_dup 1) (match_dup 2)))] + "" + "div %0,%1,%2\;mul %3,%0,%2\;sub %3,%1,%3") + +(define_insn "udivmodsi4" + [(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 (match_operand:SI 3 "register_operand" "=r") + (umod:SI (match_dup 1) (match_dup 2)))] + "" + "div %0,%1,%2\;mul %3,%0,%2\;sub %3,%1,%3") + +;;- and instructions (with complement also) +(define_insn "andsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (and:SI (match_operand:SI 1 "register_operand" "%r") + (match_operand:SI 2 "arith32_operand" "rn")))] + "" + "* +{ + unsigned int i; + + if (REG_P (operands[2])) + return \"and %0,%1,%2\"; + i = INTVAL (operands[2]); + if (INT_FITS_16_BITS (i)) + return \"mask %0,%1,%2\"; + if (INT_FITS_16_BITS (-i)) + { + operands[2] = gen_rtx (CONST_INT, VOIDmode, i & 0xffff); + return \"and %0,%1,%2\"; + } + return \"and.u %0,%1,hi16(%2)\;and %0,%1,lo16(%2)\"; +}") + +(define_insn "andcbsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (and:SI (match_operand:SI 1 "register_operand" "%r") + (not:SI (match_operand:SI 2 "register_operand" "r"))))] + "" + "and.c %0,%1,%2") + +;;- Bit set (inclusive or) instructions (with complement also) +(define_insn "iorsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (ior:SI (match_operand:SI 1 "register_operand" "%r") + (match_operand:SI 2 "arith32_operand" "rn")))] + "" + "* +{ + unsigned int i; + + if (REG_P (operands[2])) + return \"or %0,%1,%2\"; + i = INTVAL (operands[2]); + if (INT_FITS_16_BITS (i)) + return \"or %0,%1,%2\"; + return \"or.u %0,%1,hi16(%2)\;or %0,%1,lo16(%2)\"; +}") + +(define_insn "iorcbsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (ior:SI (match_operand:SI 1 "register_operand" "%r") + (not:SI (match_operand:SI 2 "register_operand" "r"))))] + "" + "or.c %0,%1,%2") + +;;- xor instructions (with complement also) +(define_insn "xorsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (xor:SI (match_operand:SI 1 "register_operand" "%r") + (match_operand:SI 2 "arith32_operand" "rn")))] + "" + "* +{ + unsigned int i; + + if (REG_P (operands[2])) + return \"xor %0,%1,%2\"; + i = INTVAL (operands[2]); + if (INT_FITS_16_BITS (i)) + return \"xor %0,%1,%2\"; + if ((i & 0xffff) == 0) + return \"xor.u %0,%1,hi16(%2)\"; + return \"xor.u %0,%1,hi16(%2)\;xor %0,%1,lo16(%2)\"; +}") + +(define_insn "xorcbsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (xor:SI (match_operand:SI 1 "register_operand" "%r") + (not:SI (match_operand:SI 2 "register_operand" "r"))))] + "" + "xor.c %0,%1,%2") + +;;- one complement instructions +(define_insn "one_cmplsi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (not:SI (match_operand:SI 1 "register_operand" "r")))] + "" + "xor.c %0,%1,r0") + +;; Optimized special case of shifting. +;; Must precede the general case. + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (ashiftrt:SI (match_operand:SI 1 "memory_operand" "m") + (const_int 24)))] + "" + "ld.b %0,%1") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (lshiftrt:SI (match_operand:SI 1 "memory_operand" "m") + (const_int 24)))] + "" + "ld.bu %0,%1") + +;;- 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) + return \"mak %0,%1,0<%2>\"; + return \"mask %0,%2,0x1f\;mak %0,%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) + return \"ext %0,%1,0<%2>\"; + return \"mask %0,%2,0x1f\;ext %0,%1,%0\"; +}") + +;;- logical shift instructions +(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) + return \"extu %0,%1,0<%2>\"; + return \"mask %0,%2,0x1f\;extu %0,%1,%0\"; +}") + +;;- rotate instructions + +(define_insn "rotlsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (rotate:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "arith_operand" "rI")))] + "" + "* +{ + if (GET_CODE (operands[2]) == CONST_INT) + { + operands[2] = gen_rtx (CONST_INT, SImode, 32 - INTVAL (operands[2])); + return \"rot %0,%1,%2\"; + } + return \"or %0,r0,32\;sub %0,%2,%0\;rot %0,%1,%0\"; +}") + +(define_insn "rotrsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (rotatert:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "arith_operand" "rI")))] + "" + "rot %0,%1,%2") + +;; Special cases of bit-field insns which we should +;; recognize in preference to the general case. +;; These handle aligned 8-bit and 16-bit fields, +;; which can usually be done with move instructions. + +(define_insn "" + [(set (zero_extract:SI (match_operand:SI 0 "general_operand" "+ro") + (match_operand:SI 1 "int5_operand" "K") + (match_operand:SI 2 "int5_operand" "K")) + (match_operand:SI 3 "register_operand" "r"))] + "(INTVAL (operands[1]) == 8 || INTVAL (operands[1]) == 16) + && INTVAL (operands[2]) % INTVAL (operands[1]) == 0" + "* +{ + if (REG_P (operands[0])) + { + if (INTVAL (operands[1]) + INTVAL (operands[2]) != 32) + return \"mak %0,%3,%1<%2>\"; + } + else + operands[0] + = adj_offsettable_operand (operands[0], INTVAL (operands[2]) / 8); + + if (GET_CODE (operands[3]) == MEM) + operands[3] = adj_offsettable_operand (operands[3], + (32 - INTVAL (operands[1])) / 8); + if (INTVAL (operands[1]) == 8) + return \"st.b %3,%0\"; + return \"st.w %3,%0\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=&r") + (zero_extract:SI (match_operand:SI 1 "general_operand" "ro") + (match_operand:SI 2 "int5_operand" "K") + (match_operand:SI 3 "int5_operand" "K")))] + "(INTVAL (operands[2]) == 8 || INTVAL (operands[2]) == 16) + && INTVAL (operands[3]) % INTVAL (operands[2]) == 0" + "* +{ + if (REG_P (operands[1])) + { + if (INTVAL (operands[2]) + INTVAL (operands[3]) != 32) + return \"extu %0,%1,%2<%3>\"; + } + else + operands[1] + = adj_offsettable_operand (operands[1], INTVAL (operands[3]) / 8); + + if (GET_CODE (operands[0]) == MEM) + operands[0] = adj_offsettable_operand (operands[0], + (32 - INTVAL (operands[1])) / 8); + if (INTVAL (operands[2]) == 8) + return \"ld.bu %0,%1\"; + return \"ld.hu %0,%1\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (sign_extract:SI (match_operand:SI 1 "general_operand" "ro") + (match_operand:SI 2 "int5_operand" "K") + (match_operand:SI 3 "int5_operand" "K")))] + "(INTVAL (operands[2]) == 8 || INTVAL (operands[2]) == 16) + && INTVAL (operands[3]) % INTVAL (operands[2]) == 0" + "* +{ + if (REG_P (operands[1])) + { + if (INTVAL (operands[2]) + INTVAL (operands[3]) != 32) + return \"extu %0,%1,%2<%3>\"; + } + else + operands[1] + = adj_offsettable_operand (operands[1], INTVAL (operands[3]) / 8); + + if (INTVAL (operands[2]) == 8) + return \"ld.b %0,%1\"; + return \"ld.h %0,%1\"; +}") + +;; Bit field instructions. + +(define_insn "extv" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (sign_extract:SI (match_operand:QI 1 "register_operand" "r,r") + (match_operand:SI 2 "arith_operand" "K,rK") + (match_operand:SI 3 "arith_operand" "K,&r")))] + "" + "* +{ + if (GET_CODE (operands[3]) == CONST_INT) + return \"ext %0,%1,%2<%3>\"; + if (GET_CODE (operands[2]) == CONST_INT) + { + operands[2] = gen_rtx (CONST_INT, VOIDmode, + (INTVAL (operands[2]) & 0x1f) << 5); + return \"mask %3,%3,0x1f\;or %3,%3,%2\;ext %0,%1,%3\"; + } + return \"mak %0,%2,5<5>\;mask %3,%3,0x1f\;or %3,%3,%0\;ext %0,%1,%3\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (sign_extract:SI (match_operand:SI 1 "register_operand" "r,r") + (match_operand:SI 2 "arith_operand" "K,rK") + (match_operand:SI 3 "arith_operand" "K,&r")))] + "" + "* +{ + if (GET_CODE (operands[3]) == CONST_INT) + return \"ext %0,%1,%2<%3>\"; + if (GET_CODE (operands[2]) == CONST_INT) + { + operands[2] = gen_rtx (CONST_INT, VOIDmode, + (INTVAL (operands[2]) & 0x1f) << 5); + return \"mask %3,%3,0x1f\;or %3,%3,%2\;ext %0,%1,%3\"; + } + return \"mak %0,%2,5<5>\;mask %3,%3,0x1f\;or %3,%3,%0\;ext %0,%1,%3\"; +}") + +(define_insn "extzv" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (zero_extract:SI (match_operand:QI 1 "register_operand" "r,r") + (match_operand:SI 2 "arith_operand" "K,Kr") + (match_operand:SI 3 "arith_operand" "K,&r")))] + "" + "* +{ + if (GET_CODE (operands[3]) == CONST_INT) + return \"extu %0,%1,%2<%3>\"; + if (GET_CODE (operands[2]) == CONST_INT) + { + operands[2] = gen_rtx (CONST_INT, VOIDmode, + (INTVAL (operands[2]) & 0x1f) << 5); + return \"mask %3,%3,0x1f\;or %3,%3,%2\;extu %0,%1,%3\"; + } + return \"mak %0,%2,5<5>\;mask %3,%3,0x1f\;or %3,%3,%0\;ext %0,%1,%3\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (zero_extract:SI (match_operand:SI 1 "register_operand" "r,r") + (match_operand:SI 2 "arith_operand" "K,Kr") + (match_operand:SI 3 "arith_operand" "K,&r")))] + "" + "* +{ + if (GET_CODE (operands[3]) == CONST_INT) + return \"extu %0,%1,%2<%3>\"; + if (GET_CODE (operands[2]) == CONST_INT) + { + operands[2] = gen_rtx (CONST_INT, VOIDmode, + (INTVAL (operands[2]) & 0x1f) << 5); + return \"mask %3,%3,0x1f\;or %3,%3,%2\;extu %0,%1,%3\"; + } + return \"mak %0,%2,5<5>\;mask %3,%3,0x1f\;or %3,%3,%0\;ext %0,%1,%3\"; +}") + +(define_insn "" + [(set (zero_extract:SI (match_operand:SI 0 "register_operand" "r,r,r") + (match_operand:SI 1 "arith_operand" "K,K,&r") + (match_operand:SI 2 "arith_operand" "K,&r,&")) + (const_int 0))] + "" + "* +{ + if (GET_CODE (operands[2]) == CONST_INT) + return \"clr %0,%0,%1<%2>\"; + if (GET_CODE (operands[1]) == CONST_INT) + { + operands[1] = gen_rtx (CONST_INT, VOIDmode, + (INTVAL (operands[1]) & 0x1f) << 5); + return \"mask %2,%2,0x1f\;or %2,%2,%1\;clr %0,%0,%2\"; + } + return \"mak %1,%1,5<5>\;mask %2,%2,0x1f\;or %2,%2,%1\;clr %0,%0,%2\"; +}") + +(define_insn "" + [(set (zero_extract:SI (match_operand:SI 0 "register_operand" "r,r,r") + (match_operand:SI 1 "arith_operand" "K,K,&r") + (match_operand:SI 2 "arith_operand" "K,&r,&r")) + (const_int -1))] + "" + "* +{ + if (GET_CODE (operands[2]) == CONST_INT) + return \"set %0,%0,%1<%2>\"; + if (GET_CODE (operands[1]) == CONST_INT) + { + operands[1] = gen_rtx (CONST_INT, VOIDmode, + (INTVAL (operands[1]) & 0x1f) << 5); + return \"mask %2,%2,0x1f\;or %2,%2,%1\;set %0,%0,%2\"; + } + return \"mak %1,%1,5<5>\;mask %2,%2,0x1f\;or %2,%2,%1\;set %0,%0,%2\"; +}") + +(define_insn "insv" + [(set (zero_extract:SI (match_operand:SI 0 "register_operand" "r,r,r") + (match_operand:SI 1 "arith_operand" "K,K,&r") + (match_operand:SI 2 "arith_operand" "K,&r,&r")) + (match_operand:SI 3 "register_operand" "&r,&r,r"))] + "" + "* +{ + if (GET_CODE (operands[2]) == CONST_INT) + return \"mak %3,%3,%1<%2>\;clr %0,%0,%1<%2>\;or %0,%0,%3\"; + if (GET_CODE (operands[1]) == CONST_INT) + { + operands[1] = gen_rtx (CONST_INT, VOIDmode, + (INTVAL (operands[1]) & 0x1f) << 5); + return \"mask %2,%2,0x1f\;or %2,%2,%1\;mak %3,%3,%2\;clr %0,%0,%2\;or %0,%0,%3\"; + } + return \"mak %1,%1,5<5>\;mask %2,%2,0x1f\;or %2,%2,%1\;mak %1,%3,%2\;clr %0,%0,%2\;or %0,%0,%1\"; +}") + +;; negate insns +(define_insn "negsi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (neg:SI (match_operand:SI 1 "arith_operand" "rI")))] + "" + "sub %0,r0,%1") + +(define_insn "negdf2" + [(set (match_operand:DF 0 "register_operand" "=r") + (neg:DF (match_operand:DF 1 "register_operand" "r")))] + "" + "fsub.dsd %0,r0,%1") + +(define_insn "negsf2" + [(set (match_operand:SF 0 "register_operand" "=r") + (neg:SF (match_operand:SF 1 "register_operand" "r")))] + "" + "fsub.sss %0,r0,%1") + +;; Store condition code values into registers +(define_insn "seq" + [(set (match_operand:SI 0 "general_operand" "=g") + (eq (cc0) (const_int 0)))] + "" + "* +{ + CC_STATUS_INIT; + if (REG_P (operands[0])) + return \"extu %0,r25,1\"; + return \"extu r25,r25,1\;st r25,%0\"; +}") + +(define_peephole + [(set (cc0) (match_operand:SI 0 "register_operand" "r")) + (set (match_operand:SI 1 "general_operand" "=g") + (eq (cc0) (const_int 0)))] + "" + "* +{ + CC_STATUS_INIT; + if (REG_P (operands[1])) + return \"cmp r25,%0,0\;extu %1,r25,1\"; + return \"cmp r25,%0,0\;extu r25,r25,1\;st r25,%1\"; +}") + +(define_peephole + [(set (cc0) + (compare + (match_operand:SI 0 "arith_operand" "r") + (match_operand:SI 1 "arith_operand" "rI"))) + (set (match_operand:SI 2 "general_operand" "=g") + (eq (cc0) (const_int 0)))] + "" + "* +{ + CC_STATUS_INIT; + if (REG_P (operands[2])) + return \"cmp r25,%0,%1\;extu %2,r25,1\"; + return \"cmp r25,%0,%1\;extu r25,r25,1\;st r25,%2\"; +}") + +(define_insn "sne" + [(set (match_operand:SI 0 "general_operand" "=g") + (ne (cc0) (const_int 0)))] + "" + "* +{ + CC_STATUS_INIT; + if (REG_P (operands[0])) + return \"extu %0,r25,1\"; + return \"extu r25,r25,1\;st r25,%0\"; +}") + +(define_peephole + [(set (cc0) (match_operand:SI 0 "register_operand" "r")) + (set (match_operand:SI 1 "general_operand" "=g") + (ne (cc0) (const_int 0)))] + "" + "* +{ + CC_STATUS_INIT; + if (REG_P (operands[1])) + return \"cmp r25,%0,0\;extu %1,r25,1\"; + return \"cmp r25,%0,0\;extu r25,r25,1\;st r25,%1\"; +}") + +(define_peephole + [(set (cc0) + (compare + (match_operand:SI 0 "arith_operand" "r") + (match_operand:SI 1 "arith_operand" "rI"))) + (set (match_operand:SI 2 "general_operand" "=g") + (ne (cc0) (const_int 0)))] + "" + "* +{ + CC_STATUS_INIT; + if (REG_P (operands[2])) + return \"cmp r25,%0,%1\;extu %2,r25,1\"; + return \"cmp r25,%0,%1\;extu r25,r25,1\;st r25,%2\"; +}") + +(define_insn "sgt" + [(set (match_operand:SI 0 "general_operand" "=g") + (gt (cc0) (const_int 0)))] + "" + "* +{ + CC_STATUS_INIT; + if (REG_P (operands[0])) + return \"extu %0,r25,1\"; + return \"extu r25,r25,1\;st r25,%0\"; +}") + +(define_peephole + [(set (cc0) (match_operand:SI 0 "register_operand" "r")) + (set (match_operand:SI 1 "general_operand" "=g") + (gt (cc0) (const_int 0)))] + "" + "* +{ + CC_STATUS_INIT; + if (REG_P (operands[1])) + return \"cmp r25,%0,0\;extu %1,r25,1\"; + return \"cmp r25,%0,0\;extu r25,r25,1\;st r25,%1\"; +}") + +(define_peephole + [(set (cc0) + (compare + (match_operand:SI 0 "arith_operand" "r") + (match_operand:SI 1 "arith_operand" "rI"))) + (set (match_operand:SI 2 "general_operand" "=g") + (gt (cc0) (const_int 0)))] + "" + "* +{ + CC_STATUS_INIT; + if (REG_P (operands[2])) + return \"cmp r25,%0,%1\;extu %2,r25,1\"; + return \"cmp r25,%0,%1\;extu r25,r25,1\;st r25,%2\"; +}") + +(define_insn "sgtu" + [(set (match_operand:SI 0 "general_operand" "=g") + (gtu (cc0) (const_int 0)))] + "" + "* +{ + CC_STATUS_INIT; + if (REG_P (operands[0])) + return \"extu %0,r25,1\"; + return \"extu r25,r25,1\;st r25,%0\"; +}") + +(define_peephole + [(set (cc0) (match_operand:SI 0 "register_operand" "r")) + (set (match_operand:SI 1 "general_operand" "=g") + (gtu (cc0) (const_int 0)))] + "" + "* +{ + CC_STATUS_INIT; + if (REG_P (operands[1])) + return \"cmp r25,%0,0\;extu %1,r25,1\"; + return \"cmp r25,%0,0\;extu r25,r25,1\;st r25,%1\"; +}") + +(define_peephole + [(set (cc0) + (compare + (match_operand:SI 0 "arith_operand" "r") + (match_operand:SI 1 "arith_operand" "rI"))) + (set (match_operand:SI 2 "general_operand" "=g") + (gtu (cc0) (const_int 0)))] + "" + "* +{ + CC_STATUS_INIT; + if (REG_P (operands[2])) + return \"cmp r25,%0,%1\;extu %2,r25,1\"; + return \"cmp r25,%0,%1\;extu r25,r25,1\;st r25,%2\"; +}") + +(define_insn "slt" + [(set (match_operand:SI 0 "general_operand" "=g") + (lt (cc0) (const_int 0)))] + "" + "* +{ + CC_STATUS_INIT; + if (REG_P (operands[0])) + return \"extu %0,r25,1\"; + return \"extu r25,r25,1\;st r25,%0\"; +}") + +(define_peephole + [(set (cc0) (match_operand:SI 0 "register_operand" "r")) + (set (match_operand:SI 1 "general_operand" "=g") + (lt (cc0) (const_int 0)))] + "" + "* +{ + CC_STATUS_INIT; + if (REG_P (operands[1])) + return \"cmp r25,%0,0\;extu %1,r25,1\"; + return \"cmp r25,%0,0\;extu r25,r25,1\;st r25,%1\"; +}") + +(define_peephole + [(set (cc0) + (compare + (match_operand:SI 0 "arith_operand" "r") + (match_operand:SI 1 "arith_operand" "rI"))) + (set (match_operand:SI 2 "general_operand" "=g") + (lt (cc0) (const_int 0)))] + "" + "* +{ + CC_STATUS_INIT; + if (REG_P (operands[2])) + return \"cmp r25,%0,%1\;extu %2,r25,1\"; + return \"cmp r25,%0,%1\;extu r25,r25,1\;st r25,%2\"; +}") + +(define_insn "sltu" + [(set (match_operand:SI 0 "general_operand" "=g") + (ltu (cc0) (const_int 0)))] + "" + "* +{ + CC_STATUS_INIT; + if (REG_P (operands[0])) + return \"extu %0,r25,1\"; + return \"extu r25,r25,1\;st r25,%0\"; +}") + +(define_peephole + [(set (cc0) (match_operand:SI 0 "register_operand" "r")) + (set (match_operand:SI 1 "general_operand" "=g") + (ltu (cc0) (const_int 0)))] + "" + "* +{ + CC_STATUS_INIT; + if (REG_P (operands[1])) + return \"cmp r25,%0,0\;extu %1,r25,1\"; + return \"cmp r25,%0,0\;extu r25,r25,1\;st r25,%1\"; +}") + +(define_peephole + [(set (cc0) + (compare + (match_operand:SI 0 "arith_operand" "r") + (match_operand:SI 1 "arith_operand" "rI"))) + (set (match_operand:SI 2 "general_operand" "=g") + (ltu (cc0) (const_int 0)))] + "" + "* +{ + CC_STATUS_INIT; + if (REG_P (operands[2])) + return \"cmp r25,%0,%1\;extu %2,r25,1\"; + return \"cmp r25,%0,%1\;extu r25,r25,1\;st r25,%2\"; +}") + +(define_insn "sge" + [(set (match_operand:SI 0 "general_operand" "=g") + (ge (cc0) (const_int 0)))] + "" + "* +{ + CC_STATUS_INIT; + if (REG_P (operands[0])) + return \"extu %0,r25,1\"; + return \"extu r25,r25,1\;st r25,%0\"; +}") + +(define_peephole + [(set (cc0) (match_operand:SI 0 "register_operand" "r")) + (set (match_operand:SI 1 "general_operand" "=g") + (ge (cc0) (const_int 0)))] + "" + "* +{ + CC_STATUS_INIT; + if (REG_P (operands[1])) + return \"cmp r25,%0,0\;extu %1,r25,1\"; + return \"cmp r25,%0,0\;extu r25,r25,1\;st r25,%1\"; +}") + +(define_peephole + [(set (cc0) + (compare + (match_operand:SI 0 "arith_operand" "r") + (match_operand:SI 1 "arith_operand" "rI"))) + (set (match_operand:SI 2 "general_operand" "=g") + (ge (cc0) (const_int 0)))] + "" + "* +{ + CC_STATUS_INIT; + if (REG_P (operands[2])) + return \"cmp r25,%0,%1\;extu %2,r25,1\"; + return \"cmp r25,%0,%1\;extu r25,r25,1\;st r25,%2\"; +}") + +(define_insn "sgeu" + [(set (match_operand:SI 0 "general_operand" "=g") + (geu (cc0) (const_int 0)))] + "" + "* +{ + CC_STATUS_INIT; + if (REG_P (operands[0])) + return \"extu %0,r25,1\"; + return \"extu r25,r25,1\;st r25,%0\"; +}") + +(define_peephole + [(set (cc0) (match_operand:SI 0 "register_operand" "r")) + (set (match_operand:SI 1 "general_operand" "=g") + (geu (cc0) (const_int 0)))] + "" + "* +{ + CC_STATUS_INIT; + if (REG_P (operands[1])) + return \"cmp r25,%0,0\;extu %1,r25,1\"; + return \"cmp r25,%0,0\;extu r25,r25,1\;st r25,%1\"; +}") + +(define_peephole + [(set (cc0) + (compare + (match_operand:SI 0 "arith_operand" "r") + (match_operand:SI 1 "arith_operand" "rI"))) + (set (match_operand:SI 2 "general_operand" "=g") + (geu (cc0) (const_int 0)))] + "" + "* +{ + CC_STATUS_INIT; + if (REG_P (operands[2])) + return \"cmp r25,%0,%1\;extu %2,r25,1\"; + return \"cmp r25,%0,%1\;extu r25,r25,1\;st r25,%2\"; +}") + +(define_insn "sle" + [(set (match_operand:SI 0 "general_operand" "=g") + (le (cc0) (const_int 0)))] + "" + "* +{ + CC_STATUS_INIT; + if (REG_P (operands[0])) + return \"extu %0,r25,1\"; + return \"extu r25,r25,1\;st r25,%0\"; +}") + +(define_peephole + [(set (cc0) (match_operand:SI 0 "register_operand" "r")) + (set (match_operand:SI 1 "general_operand" "=g") + (le (cc0) (const_int 0)))] + "" + "* +{ + CC_STATUS_INIT; + if (REG_P (operands[1])) + return \"cmp r25,%0,0\;extu %1,r25,1\"; + return \"cmp r25,%0,0\;extu r25,r25,1\;st r25,%1\"; +}") + +(define_peephole + [(set (cc0) + (compare + (match_operand:SI 0 "arith_operand" "r") + (match_operand:SI 1 "arith_operand" "rI"))) + (set (match_operand:SI 2 "general_operand" "=g") + (le (cc0) (const_int 0)))] + "" + "* +{ + CC_STATUS_INIT; + if (REG_P (operands[2])) + return \"cmp r25,%0,%1\;extu %2,r25,1\"; + return \"cmp r25,%0,%1\;extu r25,r25,1\;st r25,%2\"; +}") + +(define_insn "sleu" + [(set (match_operand:SI 0 "general_operand" "=g") + (leu (cc0) (const_int 0)))] + "" + "* +{ + CC_STATUS_INIT; + if (REG_P (operands[0])) + return \"extu %0,r25,1\"; + return \"extu r25,r25,1\;st r25,%0\"; +}") + +(define_peephole + [(set (cc0) (match_operand:SI 0 "register_operand" "r")) + (set (match_operand:SI 1 "general_operand" "=g") + (leu (cc0) (const_int 0)))] + "" + "* +{ + CC_STATUS_INIT; + if (REG_P (operands[1])) + return \"cmp r25,%0,0\;extu %1,r25,1\"; + return \"cmp r25,%0,0\;extu r25,r25,1\;st r25,%1\"; +}") + +(define_peephole + [(set (cc0) + (compare + (match_operand:SI 0 "arith_operand" "r") + (match_operand:SI 1 "arith_operand" "rI"))) + (set (match_operand:SI 2 "general_operand" "=g") + (leu (cc0) (const_int 0)))] + "" + "* +{ + CC_STATUS_INIT; + if (REG_P (operands[2])) + return \"cmp r25,%0,%1\;extu %2,r25,1\"; + return \"cmp r25,%0,%1\;extu r25,r25,1\;st r25,%2\"; +}") + + +;; Unconditional and other jump instructions +(define_insn "jump" + [(set (pc) + (label_ref (match_operand 0 "" "")))] + "" + "br %l0") + +(define_insn "" + [(set (pc) + (label_ref (match_operand 0 "" ""))) + (clobber (const_int 1))] + "" + "br.n %l0") + +(define_insn "tablejump" + [(set (pc) (match_operand:SI 0 "register_operand" "r")) + (use (label_ref (match_operand 1 "" "")))] + "" + "jmp %0") + +;;- jump to subroutine +(define_insn "call" + [(call (match_operand:SI 0 "memory_operand" "m") + (match_operand:SI 1 "general_operand" "g")) + (use (reg:SI 1))] + ;;- Don't use operand 1 for most machines. + "" + "* +{ + operands[0] = XEXP (operands[0], 0); + if (REG_P (operands[0])) + return \"jsr %0\"; + return \"bsr %0\"; +}") + +(define_insn "" + [(call (match_operand:SI 0 "memory_operand" "m") + (match_operand:SI 1 "general_operand" "g")) + (clobber (const_int 1)) + (use (reg:SI 1))] + ;;- Don't use operand 1 for most machines. + "" + "* +{ + operands[0] = XEXP (operands[0], 0); + if (REG_P (operands[0])) + return \"jsr.n %0\"; + return \"bsr.n %0\"; +}") + +;;- jump to subroutine +(define_insn "call_value" + [(set (match_operand 0 "" "=r") + (call (match_operand:SI 1 "memory_operand" "m") + (match_operand:SI 2 "general_operand" "g"))) + (use (reg:SI 1))] + ;;- Don't use operand 2 for most machines. + "" + "* +{ + operands[1] = XEXP (operands[1], 0); + if (REG_P (operands[1])) + return \"jsr %1\"; + return \"bsr %1\"; +}") + +(define_insn "" + [(set (match_operand 0 "" "=r") + (call (match_operand:SI 1 "memory_operand" "m") + (match_operand:SI 2 "general_operand" "g"))) + (use (reg:SI 1)) + (clobber (const_int 2))] + ;;- Don't use operand 2 for most machines. + "" + "* +{ + operands[1] = XEXP (operands[1], 0); + if (REG_P (operands[1])) + return \"jsr.n %1\"; + return \"bsr.n %1\"; +}") + +;; A memory ref with constant address is not normally valid. +;; But it is valid in a call insns. This pattern allows the +;; loading of the address to combine with the call. +(define_insn "" + [(call (mem:SI (match_operand:SI 0 "" "i")) + (match_operand:SI 1 "general_operand" "g")) + (use (reg:SI 1))] + ;;- Don't use operand 1 for most machines. + "GET_CODE (operands[0]) == SYMBOL_REF" + "bsr %0") + +(define_insn "" + [(call (mem:SI (match_operand:SI 0 "" "i")) + (match_operand:SI 1 "general_operand" "g")) + (clobber (const_int 1)) + (use (reg:SI 1))] + ;;- Don't use operand 1 for most machines. + "GET_CODE (operands[0]) == SYMBOL_REF" + "bsr.n %0") + +(define_insn "nop" + [(const_int 0)] + "" + "nop") + +;; Recognize jbs and jbc instructions. + +(define_insn "" + [(set (pc) + (if_then_else + (ne (sign_extract:SI (match_operand:SI 0 "register_operand" "r") + (const_int 1) + (match_operand:SI 1 "int5_operand" "K")) + (const_int 0)) + (label_ref (match_operand 2 "" "")) + (pc)))] + "" + "bb1 %1,%0,%l2") + +(define_insn "" + [(set (pc) + (if_then_else + (eq (sign_extract:SI (match_operand:SI 0 "register_operand" "r") + (const_int 1) + (match_operand:SI 1 "int5_operand" "K")) + (const_int 0)) + (label_ref (match_operand 2 "" "")) + (pc)))] + "" + "bb0 %1,%0,%l2") + +(define_insn "" + [(set (pc) + (if_then_else + (ne (sign_extract:SI (match_operand:SI 0 "register_operand" "r") + (const_int 1) + (match_operand:SI 1 "int5_operand" "K")) + (const_int 0)) + (pc) + (label_ref (match_operand 2 "" ""))))] + "" + "bb0 %1,%0,%l2") + +(define_insn "" + [(set (pc) + (if_then_else + (eq (sign_extract:SI (match_operand:SI 0 "register_operand" "r") + (const_int 1) + (match_operand:SI 1 "int5_operand" "K")) + (const_int 0)) + (pc) + (label_ref (match_operand 2 "" ""))))] + "" + "bb1 %1,%0,%l2") + +(define_insn "" + [(set (pc) + (if_then_else + (ne (sign_extract:SI (match_operand:SI 0 "general_operand" "r") + (const_int 1) + (match_operand:SI 1 "int5_operand" "K")) + (const_int 0)) + (label_ref (match_operand 2 "" "")) + (pc)))] + "" + "bb1 %1,%0,%l2") + +(define_insn "" + [(set (pc) + (if_then_else + (eq (sign_extract:SI (match_operand:SI 0 "general_operand" "r") + (const_int 1) + (match_operand:SI 1 "int5_operand" "K")) + (const_int 0)) + (label_ref (match_operand 2 "" "")) + (pc)))] + "" + "bb0 %1,%0,%l2") + +(define_insn "" + [(set (pc) + (if_then_else + (eq (and:SI (match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "int5_operand" "K")) + (const_int 0)) + (pc) + (label_ref (match_operand 2 "" ""))))] + "exact_log2 (INTVAL (operands[1])) >= 0" + "* +{ + operands[1] + = gen_rtx (CONST_INT, VOIDmode, exact_log2 (INTVAL (operands[1]))); + return \"bb1 %1,%0,%l2\"; +}") + +(define_insn "" + [(set (pc) + (if_then_else + (eq (and:SI (match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "int5_operand" "K")) + (const_int 0)) + (label_ref (match_operand 2 "" "")) + (pc)))] + "exact_log2 (INTVAL (operands[1])) >= 0" + "* +{ + operands[1] + = gen_rtx (CONST_INT, VOIDmode, exact_log2 (INTVAL (operands[1]))); + return \"bb0 %1,%0,%l2\"; +}") + +(define_insn "" + [(set (pc) + (if_then_else + (ne (and:SI (match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "int5_operand" "K")) + (const_int 0)) + (pc) + (label_ref (match_operand 2 "" ""))))] + "exact_log2 (INTVAL (operands[1])) >= 0" + "* +{ + operands[1] + = gen_rtx (CONST_INT, VOIDmode, exact_log2 (INTVAL (operands[1]))); + return \"bb0 %1,%0,%l2\"; +}") + +(define_insn "" + [(set (pc) + (if_then_else + (ne (and:SI (match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "int5_operand" "K")) + (const_int 0)) + (label_ref (match_operand 2 "" "")) + (pc)))] + "exact_log2 (INTVAL (operands[1])) >= 0" + "* +{ + operands[1] + = gen_rtx (CONST_INT, VOIDmode, exact_log2 (INTVAL (operands[1]))); + return \"bb1 %1,%0,%l2\"; +}") + +(define_insn "" + [(set (pc) + (if_then_else + (ne (sign_extract:SI (match_operand:SI 0 "general_operand" "r") + (const_int 1) + (match_operand:SI 1 "int5_operand" "K")) + (const_int 0)) + (pc) + (label_ref (match_operand 2 "" ""))))] + "" + "bb0 %1,%0,%l2") + +(define_insn "" + [(set (pc) + (if_then_else + (eq (sign_extract:SI (match_operand:SI 0 "general_operand" "r") + (const_int 1) + (match_operand:SI 1 "int5_operand" "K")) + (const_int 0)) + (pc) + (label_ref (match_operand 2 "" ""))))] + "" + "bb1 %1,%0,%l2") + +(define_insn "" + [(set (pc) + (if_then_else + (ne (and:SI (match_operand:SI 0 "register_operand" "r") + (const_int 1)) + (const_int 0)) + (label_ref (match_operand 1 "" "")) + (pc)))] + "" + "bb1 0,%0,%l1") + +(define_insn "" + [(set (pc) + (if_then_else + (eq (and:SI (match_operand:SI 0 "register_operand" "r") + (const_int 1)) + (const_int 0)) + (label_ref (match_operand 1 "" "")) + (pc)))] + "" + "bb0 0,%0,%l1") + +(define_insn "" + [(set (pc) + (if_then_else + (ne (and:SI (match_operand:SI 0 "register_operand" "r") + (const_int 1)) + (const_int 0)) + (pc) + (label_ref (match_operand 1 "" ""))))] + "" + "bb0 0,%0,%l1") + +(define_insn "" + [(set (pc) + (if_then_else + (eq (and:SI (match_operand:SI 0 "register_operand" "r") + (const_int 1)) + (const_int 0)) + (pc) + (label_ref (match_operand 1 "" ""))))] + "" + "bb1 0,%0,%l1") + +;; These four entries allow a jlbc or jlbs,to be made +;; by combination with a bic. +(define_insn "" + [(set (pc) + (if_then_else + (ne (and:SI (match_operand:SI 0 "register_operand" "r") + (not:SI (const_int -2))) + (const_int 0)) + (label_ref (match_operand 1 "" "")) + (pc)))] + "" + "bb1 0,%0,%l1") + +(define_insn "" + [(set (pc) + (if_then_else + (eq (and:SI (match_operand:SI 0 "register_operand" "r") + (not:SI (const_int -2))) + (const_int 0)) + (label_ref (match_operand 1 "" "")) + (pc)))] + "" + "bb0 0,%0,%l1") + +(define_insn "" + [(set (pc) + (if_then_else + (ne (and:SI (match_operand:SI 0 "register_operand" "r") + (not:SI (const_int -2))) + (const_int 0)) + (pc) + (label_ref (match_operand 1 "" ""))))] + "" + "bb0 0,%0,%l1") + +(define_insn "" + [(set (pc) + (if_then_else + (eq (and:SI (match_operand:SI 0 "register_operand" "r") + (not:SI (const_int -2))) + (const_int 0)) + (pc) + (label_ref (match_operand 1 "" ""))))] + "" + "bb1 0,%0,%l1") +;;- Local variables: +;;- mode:emacs-lisp +;;- comment-start: ";;- " +;;- eval: (set-syntax-table (copy-sequence (syntax-table))) +;;- eval: (modify-syntax-entry ?[ "(]") +;;- eval: (modify-syntax-entry ?] ")[") +;;- eval: (modify-syntax-entry ?{ "(}") +;;- eval: (modify-syntax-entry ?} "){") +;;- End: diff --git a/gcc-1.40/config/mips.md b/gcc-1.40/config/mips.md new file mode 100644 index 0000000..82b4a50 --- /dev/null +++ b/gcc-1.40/config/mips.md @@ -0,0 +1,1957 @@ +;; Mips.md Naive version of Machine Description for MIPS +;; Contributed by A. Lichnewsky, lich@inria.inria.fr +;; Changes by Michael Meissner, meissner@osf.org +;; Copyright (C) 1989, 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 1, 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. + +;; +;;------------------------------------------------------------------------ +;; + +;; +;; .................... +;; +;; Peephole Optimizations for +;; +;; ARITHMETIC +;; +;; .................... +;; + ;;- The following peepholes are + ;;- motivated by the fact that + ;;- stack movement result in some + ;;- cases in embarrassing sequences + ;;- of addiu SP,SP,int + ;;- addiu SP,SP,other_int + + ;;- -------------------- + ;;- REMARK: this would be done better + ;;- by analysis of dependencies in + ;;- basic blocks, prior to REG ALLOC, + ;;- and simplification of trees: + ;;- (+ (+ REG const) const) + ;;- -> (+ REG newconst) + ;;- -------------------- + ;;- Merged peephole code from + ;;- raeburn@ATHENA.MIT.EDU + +(define_peephole + [(set (match_operand:SI 0 "register_operand" "=r") + (match_operator 1 "additive_op" + [(match_operand:SI 2 "register_operand" "r") + (match_operand:SI 3 "small_int" "I")])) + (set (match_operand:SI 4 "register_operand" "=r") + (match_operator 5 "additive_op" + [(match_dup 0) + (match_operand:SI 6 "small_int" "I")]))] + "(REGNO (operands[0]) == REGNO (operands[4]) + || dead_or_set_p (insn, operands[0]))" + "* +{ + int addend; + /* compute sum, with signs */ + addend = INTVAL (operands[3]) * (GET_CODE (operands[1]) == PLUS ? 1 : -1); + addend += INTVAL (operands[6]) * (GET_CODE (operands[5]) == PLUS ? 1 : -1); + if (addend != 0) + { + operands[0] = gen_rtx (CONST_INT, VOIDmode, addend); + return \"addi%:\\t%4,%2,%0\"; + } + /* value is zero; copy */ + if (REGNO (operands[4]) != REGNO (operands[2])) + return \"add%:\\t%4,%2,$0\"; + /* copying to self; punt */ + return \" # null operation: additive operands cancel (%0,%2)\"; +}") + +;; +;; .................... +;; +;; ARITHMETIC +;; +;; .................... +;; + +(define_insn "adddf3" + [(set (match_operand:DF 0 "register_operand" "=f") + (plus:DF (match_operand:DF 1 "register_operand" "f") + (match_operand:DF 2 "register_operand" "f")))] + "" + "add.d\\t%0,%1,%2") + +(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")))] + "" + "add.s\\t%0,%1,%2") + +;; The following is generated when omiting the frame pointer +;; and for referencing large auto arrays during optimization. + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (plus:SI (match_operand:SI 1 "register_operand" "%r") + (match_operand:SI 2 "immediate_operand" "i")))] + "operands[1] == stack_pointer_rtx || operands[1] == frame_pointer_rtx" + "* +{ + int number; + if (GET_CODE (operands[2]) != CONST_INT) + return \"add%:\\t%0,%1,%2\"; + + number = INTVAL (operands[2]); + if (((unsigned) (number + 0x8000) > 0xffff)) + { + operands[3] = gen_rtx (REG, SImode, 1); /* assembler temp. */ + return \".set\\tnoat\\n\\tli\\t%3,%2\\n\\tadd%:\\t%0,%1,%3\\n\\t.set\\tat\"; + } + + return (number < 0) ? \"sub%:\\t%0,%1,%n2\" : \"add%:\\t%0,%1,%2\"; +}") + +(define_insn "addsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (plus:SI (match_operand:SI 1 "arith_operand" "%r") + (match_operand:SI 2 "arith_operand" "rI")))] + "" + "* +{ + return (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) < 0) + ? \"sub%:\\t%0,%1,%n2\" + : \"add%:\\t%0,%1,%2\"; +}") + + +;;- All kinds of subtract instructions. + +(define_insn "subdf3" + [(set (match_operand:DF 0 "register_operand" "=f") + (minus:DF (match_operand:DF 1 "register_operand" "f") + (match_operand:DF 2 "register_operand" "f")))] + "" + "sub.d\\t%0,%1,%2") + +(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")))] + "" + "sub.s\\t%0,%1,%2") + +;; The following is generated when omiting the frame pointer +;; and for referencing large auto arrays during optimization. + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (minus:SI (match_operand:SI 1 "register_operand" "%r") + (match_operand:SI 2 "immediate_operand" "i")))] + "operands[1] == stack_pointer_rtx || operands[1] == frame_pointer_rtx" + "* +{ + int number; + if (GET_CODE (operands[2]) != CONST_INT) + return \"sub%:\\t%0,%1,%2\"; + + number = INTVAL (operands[2]); + if (((unsigned) (number + 0x8000) > 0xffff)) + { + operands[3] = gen_rtx (REG, SImode, 1); /* assembler temp. */ + return \".set\\tnoat\\n\\tli\\t%3,%2\\n\\tsub%:\\t%0,%1,%3\\n\\t.set\\tat\"; + } + + return (number < 0) ? \"add%:\\t%0,%1,%n2\" : \"sub%:\\t%0,%1,%2\"; +}") + +(define_insn "subsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (minus:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "arith_operand" "rI")))] + "" + "* +{ + return (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) < 0) + ? \"add%:\\t%0,%1,%n2\" + : \"sub%:\\t%0,%1,%2\"; +}") + + +;;- Multiply instructions. + +(define_insn "muldf3" + [(set (match_operand:DF 0 "register_operand" "=f") + (mult:DF (match_operand:DF 1 "register_operand" "f") + (match_operand:DF 2 "register_operand" "f")))] + "" + "mul.d\\t%0,%1,%2") + +(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")))] + "" + "mul.s\\t%0,%1,%2") + +(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")))] + "" + "mul\\t%0,%1,%2") + + +;;- Divide instructions. + +(define_insn "divdf3" + [(set (match_operand:DF 0 "register_operand" "=f") + (div:DF (match_operand:DF 1 "register_operand" "f") + (match_operand:DF 2 "register_operand" "f")))] + "" + "div.d\\t%0,%1,%2") + +(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")))] + "" + "div.s\\t%0,%1,%2") + +(define_insn "divmodsi4" + [(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 (match_operand:SI 3 "register_operand" "=r") + (mod:SI (match_dup 1) + (match_dup 2)))] + "" + "div\\t$0,%1,%2\\n\\tmflo\\t%0\\t\\t#quotient\\n\\tmfhi\\t%3\\t\\t#remainder") + +(define_insn "divsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (div:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "arith_operand" "rI")))] + "" + "div\\t%0,%1,%2") + +(define_insn "udivmodsi4" + [(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 (match_operand:SI 3 "register_operand" "=r") + (umod:SI (match_dup 1) + (match_dup 2)))] + "" + "divu\\t$0,%1,%2\\n\\tmflo\\t%0\\t\\t#quotient\\n\\tmfhi\\t%3\\t\\t#remainder") + +(define_insn "udivsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (udiv:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "arith_operand" "rI")))] + "" + "divu\\t%0,%1,%2") + + +;; Remainder instructions + + +(define_insn "modsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (mod:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "arith_operand" "rI")))] + "" + "rem\\t%0,%1,%2") + +(define_insn "umodsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (umod:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "arith_operand" "rI")))] + "" + "remu\\t%0,%1,%2") + + +;; Absoluate value instructions -- Don't use the integer abs, +;; since that signals an exception on -2147483648 (sigh). + +(define_insn "abssf2" + [(set (match_operand:SF 0 "register_operand" "=f") + (abs:SF (match_operand:SF 1 "register_operand" "f")))] + "" + "abs.s\\t%0,%1") + +(define_insn "absdf2" + [(set (match_operand:DF 0 "register_operand" "=f") + (abs:DF (match_operand:DF 1 "register_operand" "f")))] + "" + "abs.d\\t%0,%1") + +;; +;; .................... +;; +;; LOGICAL +;; +;; .................... +;; + +(define_insn "anddi3" + [(set (match_operand:DI 0 "register_operand" "=&r") + (and:DI (match_operand:DI 1 "register_operand" "r") + (match_operand:DI 2 "register_operand" "r")))] + "" + "and\\t%0,%1,%2\;and\\t%D0,%D1,%D2") + +(define_insn "andsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (and:SI (match_operand:SI 1 "uns_arith_operand" "%r") + (match_operand:SI 2 "uns_arith_operand" "rK")))] + "" + "* +{ + return (GET_CODE (operands[2]) == CONST_INT) + ? \"andi\\t%0,%1,%x2\" + : \"and\\t%0,%1,%2\"; +}") + + +;; Simple hack to recognize the "nor" instruction on the MIPS +;; [rms: I don't think the following is actually required.] +;; This must appear before the normal or patterns, so that the +;; combiner will correctly fold things. + +(define_insn "" + [(set (match_operand:DI 0 "register_operand" "=r") + (not:DI (ior:DI (match_operand:DI 1 "register_operand" "r") + (match_operand:DI 2 "register_operand" "r"))))] + "" + "nor\\t%0,%1,%2\;nor\\t%D0,%D1,%D2") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (not:SI (ior:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "register_operand" "r"))))] + "" + "nor\\t%0,%1,%2") + +(define_insn "iordi3" + [(set (match_operand:DI 0 "register_operand" "=&r") + (ior:DI (match_operand:DI 1 "register_operand" "r") + (match_operand:DI 2 "register_operand" "r")))] + "" + "or\\t%0,%1,%2\;or\\t%D0,%D1,%D2") + +(define_insn "iorsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (ior:SI (match_operand:SI 1 "uns_arith_operand" "%r") + (match_operand:SI 2 "uns_arith_operand" "rJ")))] + "" + "* +{ + return (GET_CODE (operands[2]) == CONST_INT) + ? \"ori\\t%0,%1,%x2\" + : \"or\\t%0,%1,%2\"; +}") + +(define_insn "xordi3" + [(set (match_operand:DI 0 "register_operand" "=&r") + (xor:DI (match_operand:DI 1 "register_operand" "r") + (match_operand:DI 2 "register_operand" "r")))] + "" + "xor\\t%0,%1,%2\;xor\\t%D0,%D1,%D2") + +(define_insn "xorsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (xor:SI (match_operand:SI 1 "uns_arith_operand" "%r") + (match_operand:SI 2 "uns_arith_operand" "rK")))] + "" + "* +{ + return (GET_CODE (operands[2]) == CONST_INT) + ? \"xori\\t%0,%1,%x2\" + : \"xor\\t%0,%1,%2\"; +}") + +;; +;; .................... +;; +;; TRUNCATION +;; +;; .................... + +;; Extension and truncation insns. +;; Those for integer source operand +;; are ordered widest source type first. + + +(define_insn "truncsiqi2" + [(set (match_operand:QI 0 "register_operand" "=r") + (truncate:QI (match_operand:SI 1 "register_operand" "r")))] + "" + "andi\\t%0,%1,0xff\\t#truncsiqi2\\t %1 -> %0") + +(define_insn "truncsihi2" + [(set (match_operand:HI 0 "register_operand" "=r") + (truncate:HI (match_operand:SI 1 "register_operand" "r")))] + "" + "* + output_asm_insn (\"sll\\t%0,%1,0x10\\t#truncsihi2\\t %1 -> %0\", + operands); + return \"sra\\t%0,%0,0x10\\t#truncsihi2\\t %1 -> %0\"; +") + +(define_insn "trunchiqi2" + [(set (match_operand:QI 0 "register_operand" "=r") + (truncate:QI (match_operand:HI 1 "register_operand" "r")))] + "" + "andi\\t%0,%1,0xff\\t#trunchiqi2\\t %1 -> %0") + +(define_insn "truncdfsf2" + [(set (match_operand:SF 0 "register_operand" "=f") + (float_truncate:SF (match_operand:DF 1 "register_operand" "f")))] + "" + "cvt.s.d\\t%0,%1\\t#truncdfsf2\\t %1 -> %0") + +;; +;; .................... +;; +;; ZERO EXTENSION +;; +;; .................... + +;; Extension insns. +;; Those for integer source operand +;; are ordered widest source type first. + + + +(define_insn "zero_extendhisi2" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (zero_extend:SI (match_operand:HI 1 "general_operand" "r,m")))] + "" + "* +{ + if (which_alternative == 0) + { + output_asm_insn (\"sll\\t%0,%1,0x10\\t#zero_extendhisi2\\t %1 -> %0\", + operands); + return \"srl\\t%0,%0,0x10\\t#zero_extendhisi2\\t %1 -> %0\"; + } + else + return \"lhu\\t%0,%1\\t#zero extendhisi2 %1 -> %0\"; +}") + +(define_insn "zero_extendqihi2" + [(set (match_operand:HI 0 "register_operand" "=r") + (zero_extend:HI (match_operand:QI 1 "register_operand" "r")))] + "" + "* + output_asm_insn (\"sll\\t%0,%1,0x18\\t#zero_extendqihi2\\t %1 -> %0\", + operands); + return \"srl\\t%0,%0,0x18\\t#zero_extendqihi2\\t %1 -> %0\"; + ") + + +(define_insn "zero_extendqisi2" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (zero_extend:SI (match_operand:QI 1 "general_operand" "r,m")))] + "" + "* +{ + if (which_alternative == 0) + { + return \"andi\\t%0,%1,0xff\\t#zero_extendqisi2\\t %1 -> %0\"; + } + else + return \"lbu\\t%0,%1\\t#zero extendqisi2 %1 -> %0\"; +}") + + +;; +;; .................... +;; +;; SIGN EXTENSION +;; +;; .................... + +;; Extension insns. +;; Those for integer source operand +;; are ordered widest source type first. + + + +(define_insn "extendhisi2" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (sign_extend:SI (match_operand:HI 1 "general_operand" "r,m")))] + "" + "* +{ + if (which_alternative == 0) + { + output_asm_insn (\"sll\\t%0,%1,0x10\\t#sign extendhisi2\\t %1 -> %0\", + operands); + return \"sra\\t%0,%0,0x10\\t#sign extendhisi2\\t %1 -> %0\"; + } + else + return \"lh\\t%0,%1\\t#sign extendhisi2 %1 -> %0\"; +}") + +(define_insn "extendqihi2" + [(set (match_operand:HI 0 "register_operand" "=r") + (sign_extend:HI (match_operand:QI 1 "register_operand" "r")))] + "" + "* + output_asm_insn (\"sll\\t%0,%1,0x18\\t#sign extendqihi2\\t %1 -> %0\", + operands); + return \"sra\\t%0,%0,0x18\\t#sign extendqihi2\\t %1 -> %0\"; + ") + + +(define_insn "extendqisi2" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (sign_extend:SI (match_operand:QI 1 "general_operand" "r,m")))] + "" + "* +{ + if (which_alternative == 0) + { + output_asm_insn (\"sll\\t%0,%1,0x18\\t#sign extendqisi2\\t %1 -> %0\", + operands); + return \"sra\\t%0,%0,0x18\\t#sign extendqisi2\\t %1 -> %0\"; + } + else + return \"lb\\t%0,%1\\t#sign extendqisi2 %1 -> %0\"; +}") + + +(define_insn "extendsfdf2" + [(set (match_operand:DF 0 "register_operand" "=f") + (float_extend:DF (match_operand:SF 1 "register_operand" "f")))] + "" + "cvt.d.s\\t%0,%1\\t#extendsfdf2\\t %1 -> %0") + + +;; +;; .................... +;; +;; CONVERSIONS +;; +;; .................... + + +(define_insn "fix_truncdfsi2_internal" + [(set (match_operand:DF 0 "register_operand" "=f") + (fix:DF (match_operand:DF 1 "register_operand" "f"))) + (clobber (match_operand:SI 2 "register_operand" "r"))] + "" + "trunc.w.d %0,%1,%2") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (fix:SI (fix:DF (match_operand:DF 1 "register_operand" "f"))))] + "" + "mfc1\\t%0,%1") + +(define_expand "fix_truncdfsi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (fix:SI (fix:DF (match_operand:DF 1 "register_operand" "f"))))] + "" + " +{ + rtx reg1 = gen_reg_rtx (DFmode); /* fp reg that gets trunc result */ + rtx reg2 = gen_reg_rtx (SImode); /* gp reg that saves FP status bits */ + emit_insn (gen_fix_truncdfsi2_internal (reg1, operands[1], reg2)); + operands[1] = reg1; + /* Fall through and generate default code */ +}") + +(define_insn "fix_truncsfsi2_internal" + [(set (match_operand:SF 0 "register_operand" "=f") + (fix:SF (match_operand:SF 1 "register_operand" "f"))) + (clobber (match_operand:SI 2 "register_operand" "r"))] + "" + "trunc.w.s %0,%1,%2") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (fix:SI (fix:SF (match_operand:SF 1 "register_operand" "f"))))] + "" + "mfc1\\t%0,%1") + +(define_expand "fix_truncsfsi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (fix:SI (fix:SF (match_operand:SF 1 "register_operand" "f"))))] + "" + " +{ + rtx reg1 = gen_reg_rtx (SFmode); /* fp reg that gets trunc result */ + rtx reg2 = gen_reg_rtx (SImode); /* gp reg that saves FP status bits */ + emit_insn (gen_fix_truncsfsi2_internal (reg1, operands[1], reg2)); + operands[1] = reg1; + /* Fall through and generate default code */ +}") + +(define_insn "floatsidf2" + [(set (match_operand:DF 0 "register_operand" "=f") + (float:DF (match_operand:SI 1 "register_operand" "r")))] + "" + "mtc1\\t%1,%0\\t\\t#floatsidf2\\t%1 -> %0\;cvt.d.w\\t%0,%0") + + +(define_insn "floatsisf2" + [(set (match_operand:SF 0 "register_operand" "=f") + (float:SF (match_operand:SI 1 "register_operand" "r")))] + "" + "mtc1\\t%1,%0\\t\\t#floatsisf2\\t%1 -> %0\;cvt.s.w\\t%0,%0") + +(define_expand "fixuns_truncdfsi2" + [(set (match_operand:SI 0 "register_operand" "") + (unsigned_fix:SI (match_operand:DF 1 "register_operand" "")))] + "" + " +{ + rtx reg1 = gen_reg_rtx (DFmode); + rtx reg2 = gen_reg_rtx (DFmode); + rtx reg3 = gen_reg_rtx (SImode); + rtx label1 = gen_label_rtx (); + rtx label2 = gen_label_rtx (); + REAL_VALUE_TYPE offset = REAL_VALUE_LDEXP (1.0, 31); + + if (reg1) /* turn off complaints about unreached code */ + { + emit_move_insn (reg1, immed_real_const_1 (offset, DFmode)); + do_pending_stack_adjust (); + emit_insn (gen_rtx (SET, VOIDmode, cc0_rtx, + gen_rtx (COMPARE, DFmode, operands[1], reg1))); + + emit_jump_insn (gen_bge (label1)); + + emit_insn (gen_fix_truncdfsi2 (operands[0], operands[1])); + emit_jump_insn (gen_rtx (SET, VOIDmode, pc_rtx, + gen_rtx (LABEL_REF, VOIDmode, label2))); + emit_barrier (); + + emit_label (label1); + emit_move_insn (reg2, gen_rtx (MINUS, DFmode, operands[1], reg1)); + emit_move_insn (reg3, gen_rtx (CONST_INT, VOIDmode, 0x80000000)); + + emit_insn (gen_fix_truncdfsi2 (operands[0], reg2)); + emit_insn (gen_iorsi3 (operands[0], operands[0], reg3)); + + emit_label (label2); + + /* allow REG_NOTES to be set on last insn (labels don't have enough + fields, and can't be used for REG_NOTES anyway). */ + emit_insn (gen_rtx (USE, VOIDmode, stack_pointer_rtx)); + DONE; + } +}") + +(define_expand "fixuns_truncsfsi2" + [(set (match_operand:SI 0 "register_operand" "") + (unsigned_fix:SI (match_operand:SF 1 "register_operand" "")))] + "" + " +{ + rtx reg1 = gen_reg_rtx (SFmode); + rtx reg2 = gen_reg_rtx (SFmode); + rtx reg3 = gen_reg_rtx (SImode); + rtx label1 = gen_label_rtx (); + rtx label2 = gen_label_rtx (); + REAL_VALUE_TYPE offset = REAL_VALUE_LDEXP (1.0, 31); + + if (reg1) /* turn off complaints about unreached code */ + { + emit_move_insn (reg1, immed_real_const_1 (offset, SFmode)); + do_pending_stack_adjust (); + emit_insn (gen_rtx (SET, VOIDmode, cc0_rtx, + gen_rtx (COMPARE, SFmode, operands[1], reg1))); + + emit_jump_insn (gen_bge (label1)); + + emit_insn (gen_fix_truncsfsi2 (operands[0], operands[1])); + emit_jump_insn (gen_rtx (SET, VOIDmode, pc_rtx, + gen_rtx (LABEL_REF, VOIDmode, label2))); + emit_barrier (); + + emit_label (label1); + emit_move_insn (reg2, gen_rtx (MINUS, SFmode, operands[1], reg1)); + emit_move_insn (reg3, gen_rtx (CONST_INT, VOIDmode, 0x80000000)); + + emit_insn (gen_fix_truncsfsi2 (operands[0], reg2)); + emit_insn (gen_iorsi3 (operands[0], operands[0], reg3)); + + emit_label (label2); + + /* allow REG_NOTES to be set on last insn (labels don't have enough + fields, and can't be used for REG_NOTES anyway). */ + emit_insn (gen_rtx (USE, VOIDmode, stack_pointer_rtx)); + DONE; + } +}") + + ;;- Wild things used when + ;;- unions make double and int + ;;- overlap. + ;;- + ;;- This must be supported + ;;- since corresponding code + ;;- gets generated + +(define_insn "" + [(set (subreg:DF (match_operand:DI 0 "register_operand" "=ry") 0) + (match_operand:DF 1 "register_operand" "rf")) + (clobber (match_operand 2 "register_operand" "rf"))] + "" + "mfc1\\t%0,%L1\;mfc1\\t%D0,%M1") + +(define_insn "" + [(set (subreg:DF (match_operand:DI 0 "register_operand" "=ry") 0) + (match_operand:DF 1 "register_operand" "rf"))] + "" + "mfc1\\t%0,%L1\;mfc1\\t%D0,%M1") + +(define_insn "" + [(set (match_operand:DF 0 "register_operand" "=rf") + (subreg:DF (match_operand:DI 1 "register_operand" "ry") 0)) + (clobber (match_operand 2 "register_operand" "rf"))] + "" + "mfc1\\t%0,%L1\;mfc1\\t%D0,%M1") + +(define_insn "" + [(set (match_operand:DF 0 "register_operand" "=rf") + (subreg:DF (match_operand:DI 1 "register_operand" "ry") 0))] + "" + "mfc1\\t%0,%L1\;mfc1\\t%D0,%M1") + +;; +;; .................... +;; +;; MOVES +;; +;; and +;; +;; LOADS AND STORES +;; +;; .................... + +(define_insn "movdi" + [(set (match_operand:DI 0 "general_operand" "=r,*r,*m") + (match_operand:DI 1 "general_operand" "r,*miF,*r"))] + "" + "* +{ + extern rtx adj_offsettable_operand (); + extern int offsettable_address_p (); + + if (which_alternative == 0) + { + /* Move REGISTER <- REGISTER */ + if (REGNO (operands[0]) != (REGNO (operands[1])+1)) + return \"move\\t%0,%1\\n\\tmove\\t%D0,%D1\"; + else + return \"move\\t%D0,%D1\\n\\tmove\\t%0,%1\"; + } + + else if (which_alternative == 1) + { + if (GET_CODE (operands[1]) == MEM) + { + /* REGISTER <- MEMORY */ + if (offsettable_address_p (1, DImode, XEXP (operands[1], 0))) + { + operands[2] = adj_offsettable_operand (operands[1], 4); + return \"lw\\t%0,%1\;lw\\t%D0,%2\"; + } + + else + { + operands[2] = gen_rtx (REG, Pmode, 1); + return \".set\\tnoat\;la\\t%2,%1\;lw\\t%0,0(%2)\;lw\\t%D0,4(%2)\;set\\tat\"; + } + } + + /* REGISTER <- small integer constant */ + else if (CONSTANT_P (operands[1])) + { + operands[2] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[1]) >= 0 ? 0 : -1); + return \"li\\t%M0,%2\;li\\t%L0,%1\"; + } + + /* Register <- large integer constant */ + else if (GET_CODE (operands[1]) == CONST_DOUBLE) + { + operands[2] = gen_rtx (CONST_INT, VOIDmode, CONST_DOUBLE_LOW (operands[1])); + operands[3] = gen_rtx (CONST_INT, VOIDmode, CONST_DOUBLE_HIGH (operands[1])); + return \"li\\t%M0,%3\;li\\t%L0,%2\"; + } + } + + else if (which_alternative == 2 && GET_CODE (operands[0]) == MEM) + { + /* Memory <- Register */ + if (offsettable_address_p (1, DImode, XEXP (operands[0], 0))) + { + operands[2] = adj_offsettable_operand (operands[0], 4); + return \"sw\\t%1,%0\;sw\\t%D1,%2\"; + } + + else + { + operands[2] = gen_rtx (REG, Pmode, 1); + return \".set\\tnoat\;la\\t%2,%0\;sw\\t%1,0(%2)\;sw\\t%D1,4(%2)\;set\\tat\"; + } + } + + abort_with_insn (insn, \"impossible case in movdi\"); + return \"\"; +}") + +(define_insn "movsi" + [(set (match_operand:SI 0 "general_operand" "=r,r,m,r,r,m,*r") + (match_operand:SI 1 "general_operand" "r,m,r,i,J,J,*p"))] + "" + "* +{ + enum rtx_code code0 = GET_CODE (operands[0]); + enum rtx_code code1 = GET_CODE (operands[1]); + + if (code0 == REG && code1 == REG) + return \"move\\t%0,%1\"; + + else if (code0 == REG && code1 == MEM) + return \"lw\\t%0,%1\"; + + else if (code0 == MEM && code1 == REG) + return \"sw\\t%1,%0\"; + + else if (code0 == REG && code1 == CONST_INT) + return \"li\\t%0,%1\"; + + else if (code0 == MEM && code1 == CONST_INT && INTVAL (operands[1]) == 0) + return \"sw\\t$0,%0\"; + + else if (code0 == REG && CONSTANT_P (operands[1])) + return \"la\\t%0,%a1\"; + + else if (code0 == REG && code1 == PLUS + && GET_CODE (XEXP (operands[1], 0)) == REG + && GET_CODE (XEXP (operands[1], 1)) == CONST_INT) + { + operands[2] = XEXP (operands[1], 0); + operands[3] = XEXP (operands[1], 1); + return \"add%:\\t%0,%2,%3\"; + } + + abort_with_insn (insn, \"Bad movsi\"); + return 0; +}") + +(define_insn "movhi" + [(set (match_operand:HI 0 "general_operand" "=r,r,m,r,r,m") + (match_operand:HI 1 "general_operand" "r,m,r,i,J,J"))] + "" + "* +{ + enum rtx_code code0 = GET_CODE (operands[0]); + enum rtx_code code1 = GET_CODE (operands[1]); + + if (code0 == REG && code1 == REG) + return \"move\\t%0,%1\"; + + else if (code0 == REG && code1 == MEM) + return \"lh\\t%0,%1\"; + + else if (code0 == MEM && code1 == REG) + return \"sh\\t%1,%0\"; + + else if (code0 == REG && code1 == CONST_INT) + return \"li\\t%0,%1\"; + + else if (code0 == MEM && code1 == CONST_INT && INTVAL (operands[1]) == 0) + return \"sh\\t$0,%0\"; + + else if (code0 == REG && CONSTANT_P (operands[1])) + return \"la\\t%0,%a1\"; + + else if (code0 == REG && code1 == PLUS + && GET_CODE (XEXP (operands[1], 0)) == REG + && GET_CODE (XEXP (operands[1], 1)) == CONST_INT) + { + operands[2] = XEXP (operands[1], 0); + operands[3] = XEXP (operands[1], 1); + return \"add%:\\t%0,%2,%3\"; + } + + abort_with_insn (insn, \"Bad movhi\"); + return 0; +}") + +(define_insn "movqi" + [(set (match_operand:QI 0 "general_operand" "=r,r,m,r,r,m") + (match_operand:QI 1 "general_operand" "r,m,r,i,J,J"))] + "" + "* +{ + enum rtx_code code0 = GET_CODE (operands[0]); + enum rtx_code code1 = GET_CODE (operands[1]); + + if (code0 == REG && code1 == REG) + return \"move\\t%0,%1\"; + + else if (code0 == REG && code1 == MEM) + return \"lb\\t%0,%1\"; + + else if (code0 == MEM && code1 == REG) + return \"sb\\t%1,%0\"; + + else if (code0 == REG && code1 == CONST_INT) + return \"li\\t%0,%1\"; + + else if (code0 == MEM && code1 == CONST_INT && INTVAL (operands[1]) == 0) + return \"sb\\t$0,%0\"; + + else if (code0 == REG && CONSTANT_P (operands[1])) + return \"la\\t%0,%a1\"; + + else if (code0 == REG && code1 == PLUS + && GET_CODE (XEXP (operands[1], 0)) == REG + && GET_CODE (XEXP (operands[1], 1)) == CONST_INT) + { + operands[2] = XEXP (operands[1], 0); + operands[3] = XEXP (operands[1], 1); + return \"add%:\\t%0,%2,%3\"; + } + + abort_with_insn (insn, \"Bad movqi\"); + return 0; +}") + +(define_insn "movsf" + [(set (match_operand:SF 0 "general_operand" "=f,f,m,fy,*f,*y,*y,*m") + (match_operand:SF 1 "general_operand" "f,m,f,F,*y,*f,*m,*y"))] + "" + "* +{ + enum rtx_code code0 = GET_CODE (operands[0]); + enum rtx_code code1 = GET_CODE (operands[1]); + + if (code0 == REG) + { + if (code1 == REG) + { + if (FP_REG_P (REGNO (operands[0]))) + { + if (FP_REG_P (REGNO (operands[1]))) + return \"mov.s\\t%0,%1\"; + else + return \"mtc1\\t%1,%0\\t\\t# Calling sequence trick\"; + } + + else if (FP_REG_P (REGNO (operands[1]))) + return \"mfc1\\t%0,%1\\t\\t# Calling sequence trick\"; + + else + return \"move\\t%0,%1\"; + } + + else if (code1 == CONST_DOUBLE) + return \"li.s\\t%0,%1\"; + + else if (code1 == MEM) + return (GP_REG_P (REGNO (operands[0]))) ? \"lw\\t%0,%1\" : \"l.s\\t%0,%1\"; + } + + else if (code0 == MEM && code1 == REG) + return (GP_REG_P (REGNO (operands[1]))) ? \"sw\\t%1,%0\" : \"s.s\\t%1,%0\"; + + abort_with_insn (insn, \"Bad movsf\"); + return \"\"; +}") + + +(define_insn "movdf" + [(set (match_operand:DF 0 "general_operand" "=f,f,m,fy,*f,*y,&*y,*m") + (match_operand:DF 1 "general_operand" "f,m,f,F,*y,*f,*m,*y"))] + "" + "* +{ + extern rtx adj_offsettable_operand (); + extern int offsettable_address_p (); + + enum rtx_code code0 = GET_CODE (operands[0]); + enum rtx_code code1 = GET_CODE (operands[1]); + + if (code0 == REG) + { + if (code1 == REG) + { + if (FP_REG_P (REGNO (operands[0]))) + { + if (FP_REG_P (REGNO (operands[1]))) + return \"mov.d\\t%0,%1\"; + else + return \"mtc1\\t%L1,%0\\t\\t# Calling sequence trick\;mtc1\\t%M1,%D0\"; + } + + else if (FP_REG_P (REGNO (operands[1]))) + return \"mfc1\\t%L0,%1\\t\\t# Calling sequence trick\;mfc1\\t%M0,%D1\"; + + else if (REGNO (operands[0]) != (REGNO (operands[1])+1)) + return \"move\\t%0,%1\\n\\tmove\\t%D0,%D1\"; + + else + return \"move\\t%D0,%D1\\n\\tmove\\t%0,%1\"; + } + + else if (code1 == CONST_DOUBLE) + return \"li.d\\t%0,%1\"; + + else if (code1 == MEM) + { + if (FP_REG_P (REGNO (operands[0]))) + return \"l.d\\t%0,%1\"; + + else if (offsettable_address_p (1, DFmode, XEXP (operands[1], 0))) + { + operands[2] = adj_offsettable_operand (operands[1], 4); + if (reg_mentioned_p (operands[0], operands[1])) + return \"lw\\t%D0,%2\;lw\\t%0,%1\"; + else + return \"lw\\t%0,%1\;lw\\t%D0,%2\"; + } + + else + { + operands[2] = gen_rtx (REG, Pmode, 1); + return \".set\\tnoat\;la\\t%2,%1\;lw\\t%0,0(%2)\;lw\\t%D0,4(%2)\;set\\tat\"; + } + } + } + + else if (code0 == MEM && code1 == REG) + { + if (FP_REG_P (REGNO (operands[1]))) + return \"s.d\\t%1,%0\"; + + else if (offsettable_address_p (1, DFmode, XEXP (operands[0], 0))) + { + operands[2] = adj_offsettable_operand (operands[0], 4); + return \"sw\\t%1,%0\;sw\\t%D1,%2\"; + } + + else + { + operands[2] = gen_rtx (REG, Pmode, 1); + return \".set\\tnoat\;la\\t%2,%0\;sw\\t%1,0(%2)\;sw\\t%D1,4(%2)\;set\\tat\"; + } + } + + abort_with_insn (insn, \"Bad movdf\"); + return \"\"; +}") + + +;; +;; .................... +;; +;; OTHER ARITHMETIC AND SHIFT +;; +;; .................... + +(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) + operands[2] = gen_rtx (CONST_INT, VOIDmode, (XINT (operands[2], 0))& 0x1f); + + return \"sll\\t%0,%1,%2\"; +}") + +(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) + operands[2] = gen_rtx (CONST_INT, VOIDmode, (XINT (operands[2], 0))& 0x1f); + + return \"sra\\t%0,%1,%2\"; +}") + +(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) + operands[2] = gen_rtx (CONST_INT, VOIDmode, (XINT (operands[2], 0))& 0x1f); + + return \"srl\\t%0,%1,%2\"; +}") + +(define_insn "negsi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (neg:SI (match_operand:SI 1 "register_operand" "r")))] + "" + "sub%:\\t%0,$0,%1") + +(define_insn "negdf2" + [(set (match_operand:DF 0 "register_operand" "=f") + (neg:DF (match_operand:DF 1 "register_operand" "f")))] + "" + "neg.d\\t%0,%1") + +(define_insn "negsf2" + + [(set (match_operand:SF 0 "register_operand" "=f") + (neg:SF (match_operand:SF 1 "register_operand" "f")))] + "" + "neg.s\\t%0,%1") + + +(define_insn "one_cmplsi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (not:SI (match_operand:SI 1 "register_operand" "r")))] + "" + "nor\\t%0,$0,%1") + +;; +;; .................... +;; +;; COMPARISONS +;; +;; .................... + + ;;- Order is significant here + ;;- because there are untyped + ;;- comparisons generated by + ;;- the optimizer + ;;- (set (cc0) + ;;- (compare (const_int 2) + ;;- (const_int 1))) + +(define_insn "cmpsi" + [(set (cc0) + (compare (match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "arith_operand" "rI")))] + "" + "* + compare_collect (SImode, operands[0], operands[1]); + return \"\\t\\t\\t\\t# cmpsi\\t%0,%1\"; +") + + +(define_insn "" + [(set (cc0) + (match_operand:SI 0 "register_operand" "r"))] + "" + "* + compare_collect (SImode, operands[0], gen_rtx (REG, SImode, 0)); + return \"\\t\\t\\t\\t# (set (cc0)\\t%0)\"; +") + +;; These patterns are hopelessly invalid, because +;; comparing subword values properly requires extending them. + +;; (define_insn "cmphi" +;; [(set (cc0) +;; (compare (match_operand:HI 0 "register_operand" "r") +;; (match_operand:HI 1 "register_operand" "r")))] +;; "" +;; "* +;; compare_collect (HImode, operands[0], operands[1]); +;; return \" #\\tcmphi\\t%0,%1\"; +;; ") +;; +;; (define_insn "cmpqi" +;; [(set (cc0) +;; (compare (match_operand:QI 0 "register_operand" "r") +;; (match_operand:QI 1 "register_operand" "r")))] +;; "" +;; "* +;; compare_collect (QImode, operands[0], operands[1]); +;; return \" #\\tcmpqi\\t%0,%1\"; +;; ") +;; +;; (define_insn "" +;; [(set (cc0) +;; (match_operand:QI 0 "register_operand" "r"))] +;; "" +;; "* +;; compare_collect (QImode, operands[0], gen_rtx (REG, QImode, 0)); +;; return \" #\\t (set (cc0)\\t%0)\"; +;; ") +;; +;; (define_insn "" +;; [(set (cc0) +;; (match_operand:HI 0 "register_operand" "r"))] +;; "" +;; "* +;; compare_collect (HImode, operands[0], gen_rtx (REG, HImode, 0)); +;; return \" #\\t (set (cc0)\\t%0)\"; +;; ") + +(define_insn "cmpdf" + [(set (cc0) + (compare (match_operand:DF 0 "register_operand" "f") + (match_operand:DF 1 "register_operand" "f")))] + "" + "* + compare_collect (DFmode, operands[0], operands[1]); + return \" #\\t\\t\\t\\tcmpdf\\t%0,%1\" ; +") + +(define_insn "cmpsf" + [(set (cc0) + (compare (match_operand:SF 0 "register_operand" "f") + (match_operand:SF 1 "register_operand" "f")))] + "" + "* + compare_collect (SFmode, operands[0], operands[1]); + return \"\\t\\t\\t\\t# cmpsf\\t%0,%1\" ; +") + +;; +;; .................... +;; +;; BRANCHES +;; +;; .................... + +(define_insn "jump" + [(set (pc) + (label_ref (match_operand 0 "" "")))] + "" + "* +{ + if (GET_CODE (operands[0]) == REG) + return \"j\\t%0\"; + else + return \"j\\t%l0\"; +}") + + +(define_insn "tablejump" + [(set (pc) + (match_operand:SI 0 "register_operand" "r")) + (use (label_ref (match_operand 1 "" "")))] + "" + "j\\t%0") + + +(define_insn "beq" + [(set (pc) + (if_then_else (eq (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +{ + rtx br_ops[3]; + enum machine_mode mode; + compare_restore (br_ops, &mode, insn); + br_ops[2] = operands[0]; + if (mode == DFmode) + { + output_asm_insn (\"c.eq.d\\t%0,%1\\t\\t# beq\", br_ops); + output_asm_insn (\"bc1t\\t%2\\t\\t# beq\", br_ops); + } + else if (mode == SFmode) + { + output_asm_insn (\"c.eq.s\\t%0,%1\\t\\t# beq\", br_ops); + output_asm_insn (\"bc1t\\t%2\\t\\t# beq\", br_ops); + } + else + { + output_asm_insn (\"beq\\t%0,%1,%2\\t\\t# beq\", br_ops); + } + return \"\"; +} + ") + +(define_insn "bne" + [(set (pc) + (if_then_else (ne (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +{ + rtx br_ops[3]; + enum machine_mode mode; + compare_restore (br_ops, &mode, insn); + br_ops[2] = operands[0]; + if (mode == DFmode) + { + output_asm_insn (\"c.eq.d\\t%0,%1\\t\\t# bne\", br_ops); + output_asm_insn (\"bc1f\\t%2\\t\\t# bne\", br_ops); + } + else if (mode == SFmode) + { + output_asm_insn (\"c.eq.s\\t%0,%1\\t\\t# bne\", br_ops); + output_asm_insn (\"bc1f\\t%2\\t\\t# bne\", br_ops); + } + else + { + output_asm_insn (\"bne\\t%0,%1,%2\\t\\t# bne\", br_ops); + } + return \"\"; +} + +") + +(define_insn "bgt" + [(set (pc) + (if_then_else (gt (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +{ + rtx br_ops[3]; + enum machine_mode mode; + compare_restore (br_ops, &mode, insn); + br_ops[2] = operands[0]; + if (mode == DFmode) + { + output_asm_insn (\"c.le.d\\t%0,%1\\t\\t# bgt branch %0 > %1\", br_ops); + output_asm_insn (\"bc1f\\t%2\\t\\t# bgt\", br_ops); + } + else if (mode == SFmode) + { + output_asm_insn (\"c.le.s\\t%0,%1\\t\\t# bgt branch %0 > %1\", br_ops); + output_asm_insn (\"bc1f\\t%2\\t\\t# bgt\", br_ops); + } + else + { + output_asm_insn (\"bgt\\t%0,%1,%2\\t\\t# bgt\", br_ops); + } + return \"\"; +} + +") + +(define_insn "blt" + [(set (pc) + (if_then_else (lt (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +{ + rtx br_ops[3]; + enum machine_mode mode; + compare_restore (br_ops, &mode, insn); + br_ops[2] = operands[0]; + if (mode == DFmode) + { + output_asm_insn (\"c.lt.d\\t%0,%1\\t\\t# blt\", br_ops); + output_asm_insn (\"bc1t\\t%2\\t\\t# blt\", br_ops); + } + else if (mode == SFmode) + { + output_asm_insn (\"c.lt.s\\t%0,%1\\t\\t# blt\", br_ops); + output_asm_insn (\"bc1t\\t%2\\t\\t# blt\", br_ops); + } + else + { + output_asm_insn (\"blt\\t%0,%1,%2\\t\\t# blt\", br_ops); + } + return \" #\\tblt\\t%l0\\t\\t# blt\"; +} +") + +(define_insn "bgtu" + [(set (pc) + (if_then_else (gtu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +{ + rtx br_ops[3]; + enum machine_mode mode; + compare_restore (br_ops, &mode, insn); + br_ops[2] = operands[0]; + if (mode == DFmode) + { + output_asm_insn (\"c.le.d\\t%0,%1\\t\\t# bgtu\", br_ops); + output_asm_insn (\"bc1f\\t%2\\t\\t# bgtu\", br_ops); + } + else if (mode == SFmode) + { + output_asm_insn (\"c.le.s\\t%0,%1\\t\\t# bgtu\", br_ops); + output_asm_insn (\"bc1f\\t%2\\t\\t# bgtu\", br_ops); + } + else + { + output_asm_insn (\"bgtu\\t%0,%1,%2\\t\\t# bgtu\", br_ops); + } + return \" #\\tbgtu\\t%l0\\t\\t# bgtu\"; +} +") + +(define_insn "bltu" + [(set (pc) + (if_then_else (ltu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +{ + rtx br_ops[3]; + enum machine_mode mode; + compare_restore (br_ops, &mode, insn); + br_ops[2] = operands[0]; + if (mode == DFmode) + { + output_asm_insn (\"c.lt.d\\t%0,%1\\t\\t# bltu\", br_ops); + output_asm_insn (\"bc1t\\t%2\\t\\t# bltu\", br_ops); + } + else if (mode == SFmode) + { + output_asm_insn (\"c.lt.s\\t%0,%1\\t\\t# bltu\", br_ops); + output_asm_insn (\"bc1t\\t%2\\t\\t# bltu\", br_ops); + } + else + { + output_asm_insn (\"bltu\\t%0,%1,%2\\t\\t# bltu\", br_ops); + } + return \"\"; +} +") + +(define_insn "bge" + [(set (pc) + (if_then_else (ge (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +{ + rtx br_ops[3]; + enum machine_mode mode; + compare_restore (br_ops, &mode, insn); + br_ops[2] = operands[0]; + if (mode == DFmode) + { + output_asm_insn (\"c.lt.d\\t%0,%1\\t\\t# bge\", br_ops); + output_asm_insn (\"bc1f\\t%2\\t\\t# bge\", br_ops); + } + else if (mode == SFmode) + { + output_asm_insn (\"c.lt.s\\t%0,%1\\t\\t# bge\", br_ops); + output_asm_insn (\"bc1f\\t%2\\t\\t# bge\", br_ops); + } + else + { + output_asm_insn (\"bge\\t%0,%1,%2\\t\\t# bge\", br_ops); + } + return \"\"; +} +") + +(define_insn "bgeu" + [(set (pc) + (if_then_else (geu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +{ + rtx br_ops[3]; + enum machine_mode mode; + compare_restore (br_ops, &mode, insn); + br_ops[2] = operands[0]; + if (mode == DFmode) + { + output_asm_insn (\"c.lt.d\\t%0,%1\\t\\t# bgeu\", br_ops); + output_asm_insn (\"bc1f\\t%2\\t\\t# bgeu\", br_ops); + } + else if (mode == SFmode) + { + output_asm_insn (\"c.lt.s\\t%0,%1\\t\\t# bgeu\", br_ops); + output_asm_insn (\"bc1f\\t%2\\t\\t# bgeu\", br_ops); + } + else + { + output_asm_insn (\"bgeu\\t%0,%1,%2\\t\\t# bgeu\", br_ops); + } + return \"\"; +} +") + +(define_insn "ble" + [(set (pc) + (if_then_else (le (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +{ + rtx br_ops[3]; + enum machine_mode mode; + compare_restore (br_ops, &mode, insn); + br_ops[2] = operands[0]; + if (mode == DFmode) + { + output_asm_insn (\"c.le.d\\t%0,%1\\t\\t# ble\", br_ops); + output_asm_insn (\"bc1t\\t%2\\t\\t# ble\", br_ops); + } + else if (mode == SFmode) + { + output_asm_insn (\"c.le.s\\t%0,%1\\t\\t# ble\", br_ops); + output_asm_insn (\"bc1t\\t%2\\t\\t# ble\", br_ops); + } + else + { + output_asm_insn (\"ble\\t%0,%1,%2\\t\\t# ble\", br_ops); + } + return \"\"; +} +") + +(define_insn "bleu" + [(set (pc) + (if_then_else (leu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +{ + rtx br_ops[3]; + enum machine_mode mode; + compare_restore (br_ops, &mode, insn); + br_ops[2] = operands[0]; + if (mode == DFmode) + { + output_asm_insn (\"c.le.d\\t%0,%1\\t\\t# ble\", br_ops); + output_asm_insn (\"bc1t\\t%2\\t\\t# ble\", br_ops); + } + else if (mode == SFmode) + { + output_asm_insn (\"c.le.s\\t%0,%1\\t\\t# ble\", br_ops); + output_asm_insn (\"bc1t\\t%2\\t\\t# ble\", br_ops); + } + else + { + output_asm_insn (\"bleu\\t%0,%1,%2\\t\\t# bleu\", br_ops); + } + return \" #\\tbleu\\t%l0\\t\\t# bleu\"; +} +") + +(define_insn "" + [(set (pc) + (if_then_else (ne (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* +{ + rtx br_ops[3]; + enum machine_mode mode; + compare_restore (br_ops, &mode, insn); + br_ops[2] = operands[0]; + if (mode == DFmode) + { + output_asm_insn (\"c.eq.d\\t%0,%1\\t\\t# beq\", br_ops); + output_asm_insn (\"bc1t\\t%2\\t\\t# beq\", br_ops); + } + else if (mode == SFmode) + { + output_asm_insn (\"c.eq.s\\t%0,%1\\t\\t# beq\", br_ops); + output_asm_insn (\"bc1t\\t%2\\t\\t# beq\", br_ops); + } + else + { + output_asm_insn (\"beq\\t%0,%1,%2\\t\\t# beq Inv.\", br_ops); + } + return \"\"; +} +") + +(define_insn "" + [(set (pc) + (if_then_else (eq (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* +{ + rtx br_ops[3]; + enum machine_mode mode; + compare_restore (br_ops, &mode, insn); + br_ops[2] = operands[0]; + if (mode == DFmode) + { + output_asm_insn (\"c.eq.d\\t%0,%1\\t\\t# bne\", br_ops); + output_asm_insn (\"bc1f\\t%2\\t\\t# bne\", br_ops); + } + else if (mode == SFmode) + { + output_asm_insn (\"c.eq.s\\t%0,%1\\t\\t# bne\", br_ops); + output_asm_insn (\"bc1f\\t%2\\t\\t# beq\", br_ops); + } + else + { + output_asm_insn (\"bne\\t%0,%1,%2\\t\\t# bne Inv.\", br_ops); + } + return \"\"; +} + +") + +(define_insn "" + [(set (pc) + (if_then_else (le (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* +{ + rtx br_ops[3]; + enum machine_mode mode; + compare_restore (br_ops, &mode, insn); + br_ops[2] = operands[0]; + if (mode == DFmode) + { + output_asm_insn (\"c.le.d\\t%0,%1\\t\\t# bgt\", br_ops); + output_asm_insn (\"bc1f\\t%2\\t\\t# beq\", br_ops); + } + else if (mode == SFmode) + { + output_asm_insn (\"c.le.s\\t%0,%1\\t\\t# bgt\", br_ops); + output_asm_insn (\"bc1f\\t%2\\t\\t# beq\", br_ops); + } + else + { + output_asm_insn (\"bgt\\t%0,%1,%2\\t\\t# bgt Inv.\", br_ops); + } + return \"\"; +} +") + +(define_insn "" + [(set (pc) + (if_then_else (leu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* +{ + rtx br_ops[3]; + enum machine_mode mode; + compare_restore (br_ops, &mode, insn); + br_ops[2] = operands[0]; + if (mode == DFmode) + { + output_asm_insn (\"c.le.d\\t%0,%1\\t\\t# bgt\", br_ops); + output_asm_insn (\"bc1f\\t%2\\t\\t# beq\", br_ops); + } + else if (mode == SFmode) + { + output_asm_insn (\"c.le.s\\t%0,%1\\t\\t# bgt\", br_ops); + output_asm_insn (\"bc1f\\t%2\\t\\t# beq\", br_ops); + } + else + { + output_asm_insn (\"bgtu\\t%0,%1,%2\\t\\t# bgtu Inv.\", br_ops); + } + return \" #\\tbgtu\\t%l0\\t\\t# bgtu\"; +} +") + +(define_insn "" + [(set (pc) + (if_then_else (ge (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* +{ + rtx br_ops[3]; + enum machine_mode mode; + compare_restore (br_ops, &mode, insn); + br_ops[2] = operands[0]; + if (mode == DFmode) + { + output_asm_insn (\"c.lt.d\\t%0,%1\\t\\t# blt\", br_ops); + output_asm_insn (\"bc1t\\t%2\\t\\t# beq\", br_ops); + } + else if (mode == SFmode) + { + output_asm_insn (\"c.lt.s\\t%0,%1\\t\\t# blt\", br_ops); + output_asm_insn (\"bc1t\\t%2\\t\\t# beq\", br_ops); + } + else + { + output_asm_insn (\"blt\\t%0,%1,%2\\t\\t# blt Inv.\", br_ops); + } + return \"\"; +} +") + +(define_insn "" + [(set (pc) + (if_then_else (geu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* +{ + rtx br_ops[3]; + enum machine_mode mode; + compare_restore (br_ops, &mode, insn); + br_ops[2] = operands[0]; + if (mode == DFmode) + { + output_asm_insn (\"c.lt.d\\t%0,%1\\t\\t# bltu\", br_ops); + output_asm_insn (\"bc1t\\t%2\\t\\t# bltu\", br_ops); + } + else if (mode == SFmode) + { + output_asm_insn (\"c.lt.s\\t%0,%1\\t\\t# bltu\", br_ops); + output_asm_insn (\"bc1t\\t%2\\t\\t# bltu\", br_ops); + } + else + { + output_asm_insn (\"bltu\\t%0,%1,%2\\t\\t# bltu Inv.\", br_ops); + } + return \" #\\tbltu\\t%l0\\t\\t# bltu\"; +} +") + +(define_insn "" + [(set (pc) + (if_then_else (lt (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* +{ + rtx br_ops[3]; + enum machine_mode mode; + compare_restore (br_ops, &mode, insn); + br_ops[2] = operands[0]; + if (mode == DFmode) + { + output_asm_insn (\"c.lt.d\\t%0,%1\\t\\t# bge\", br_ops); + output_asm_insn (\"bc1f\\t%2\\t\\t# bge (DF) Inv.\", br_ops); + } + else if (mode == SFmode) + { + output_asm_insn (\"c.lt.s\\t%0,%1\\t\\t# bge\", br_ops); + output_asm_insn (\"bc1f\\t%2\\t\\t# bge (SF) Inv.\", br_ops); + } + else + { + output_asm_insn (\"bge\\t%0,%1,%2\\t\\t# bge Inv.\", br_ops); + } + return \"\"; +} +") + +(define_insn "" + [(set (pc) + (if_then_else (ltu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* +{ + rtx br_ops[3]; + enum machine_mode mode; + compare_restore (br_ops, &mode, insn); + br_ops[2] = operands[0]; + if (mode == DFmode) + { + output_asm_insn (\"c.lt.d\\t%0,%1\\t\\t# bge\", br_ops); + output_asm_insn (\"bc1f\\t%2\\t\\t# bgeu (DF) Inv.\", br_ops); + } + else if (mode == SFmode) + { + output_asm_insn (\"c.lt.s\\t%0,%1\\t\\t# bge\", br_ops); + output_asm_insn (\"bc1f\\t%2\\t\\t# bgeu (SF )Inv.\", br_ops); + } + else + { + output_asm_insn (\"bgeu\\t%0,%1,%2\\t\\t# bgeu Inv.\", br_ops); + } + return \" #\\tbgeu\\t%l0\\t\\t# bgeu\"; +} +") + +(define_insn "" + [(set (pc) + (if_then_else (gt (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* +{ + rtx br_ops[3]; + enum machine_mode mode; + compare_restore (br_ops, &mode, insn); + br_ops[2] = operands[0]; + if (mode == DFmode) + { + output_asm_insn (\"c.le.d\\t%0,%1\\t\\t# ble\", br_ops); + output_asm_insn (\"bc1t\\t%2\\t\\t# ble\", br_ops); + } + else if (mode == SFmode) + { + output_asm_insn (\"c.le.s\\t%0,%1\\t\\t# ble\", br_ops); + output_asm_insn (\"bc1t\\t%2\\t\\t# ble\", br_ops); + } + else + { + output_asm_insn (\"ble\\t%0,%1,%2\\t\\t# ble Inv.\", br_ops); + } + return \"\"; +} +") + +(define_insn "" + [(set (pc) + (if_then_else (gtu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* +{ + rtx br_ops[3]; + enum machine_mode mode; + compare_restore (br_ops, &mode, insn); + br_ops[2] = operands[0]; + if (mode == DFmode) + { + output_asm_insn (\"c.le.d\\t%0,%1\\t\\t# bleu\", br_ops); + output_asm_insn (\"bc1t\\t%2\\t\\t# bleu\", br_ops); + } + else if (mode == SFmode) + { + output_asm_insn (\"c.le.s\\t%0,%1\\t\\t# bleu\", br_ops); + output_asm_insn (\"bc1t\\t%2\\t\\t# bleu\", br_ops); + } + else + { + output_asm_insn (\"bleu\\t%0,%1,%2\\t\\t# bleu Inv.\", br_ops); + } + return \"\"; +} +") + +;; +;; .................... +;; +;; LINKAGE +;; +;; .................... + +(define_insn "call" + [(call (match_operand 0 "memory_operand" "m") + (match_operand 1 "" "i")) + (clobber (reg:SI 31))] + "" + "* +{ + register rtx target = XEXP (operands[0], 0); + + if (GET_CODE (target) == SYMBOL_REF) + return \"jal\\t%0\"; + + else + { + operands[0] = target; + return \"jal\\t$31,%0\"; + } +}") + + +(define_insn "call_value" + [(set (match_operand 0 "" "=rf") + (call (match_operand 1 "memory_operand" "m") + (match_operand 2 "" "i"))) + (clobber (reg:SI 31))] + "" + "* +{ + register rtx target = XEXP (operands[1], 0); + + if (GET_CODE (target) == SYMBOL_REF) + return \"jal\\t%1\"; + + else + { + operands[1] = target; + return \"jal\\t$31,%1\"; + } +}") + +(define_insn "nop" + [(const_int 0)] + "" + ".set\\tnoreorder\;nop\;.set\\treorder") + +(define_insn "probe" + [(mem:SI (reg:SI 29))] + "" + "* +{ + operands[0] = gen_rtx (REG, SImode, 1); + operands[1] = stack_pointer_rtx; + return \".set\\tnoat\;lw\\t%0,0(%1)\\t\\t# stack probe\;.set\\tat\"; +}") + +;; +;;- Local variables: +;;- mode:emacs-lisp +;;- comment-start: ";;- " +;;- eval: (set-syntax-table (copy-sequence (syntax-table))) +;;- eval: (modify-syntax-entry ?[ "(]") +;;- eval: (modify-syntax-entry ?] ")[") +;;- eval: (modify-syntax-entry ?{ "(}") +;;- eval: (modify-syntax-entry ?} "){") +;;- End: diff --git a/gcc-1.40/config/ns32k.md b/gcc-1.40/config/ns32k.md new file mode 100644 index 0000000..f5693de --- /dev/null +++ b/gcc-1.40/config/ns32k.md @@ -0,0 +1,2636 @@ +;; BUGS: +;; Insert no-op between an insn with memory read-write operands +;; following by a scale-indexing operation. +;; The Sequent assembler does not allow addresses to be used +;; except in insns which explicitly compute an effective address. +;; I.e., one cannot say "cmpd _p,@_x" +;; Implement unsigned multiplication?? + +;;- Machine descrption for GNU compiler +;;- ns32000 Version +;; Copyright (C) 1988 Free Software Foundation, Inc. +;; Contributed by Michael Tiemann (tiemann@mcc.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 1, 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. + + +;;- Instruction patterns. When multiple patterns apply, +;;- the first one in the file is chosen. +;;- +;;- See file "rtl.def" for documentation on define_insn, match_*, et. al. +;;- +;;- cpp macro #define NOTICE_UPDATE_CC in file tm.h handles condition code +;;- updates for most instructions. + +; tstsi is first test insn so that it is the one to match +; a constant argument. + +(define_insn "tstsi" + [(set (cc0) + (match_operand:SI 0 "general_operand" "rmn"))] + "" + "* +{ cc_status.flags |= CC_REVERSED; + operands[1] = const0_rtx; + return \"cmpqd %1,%0\"; }") + +(define_insn "tsthi" + [(set (cc0) + (match_operand:HI 0 "general_operand" "g"))] + "" + "* +{ cc_status.flags |= CC_REVERSED; + operands[1] = const0_rtx; + return \"cmpqw %1,%0\"; }") + +(define_insn "tstqi" + [(set (cc0) + (match_operand:QI 0 "general_operand" "g"))] + "" + "* +{ cc_status.flags |= CC_REVERSED; + operands[1] = const0_rtx; + return \"cmpqb %1,%0\"; }") + +(define_insn "tstdf" + [(set (cc0) + (match_operand:DF 0 "general_operand" "fmF"))] + "TARGET_32081" + "* +{ cc_status.flags |= CC_REVERSED; + operands[1] = dconst0_rtx; + return \"cmpl %1,%0\"; }") + +(define_insn "tstsf" + [(set (cc0) + (match_operand:SF 0 "general_operand" "fmF"))] + "TARGET_32081" + "* +{ cc_status.flags |= CC_REVERSED; + operands[1] = fconst0_rtx; + return \"cmpf %1,%0\"; }") + +;; Put cmpsi first among compare insns so it matches two CONST_INT operands. + +(define_insn "cmpsi" + [(set (cc0) + (compare (match_operand:SI 0 "general_operand" "rmn") + (match_operand:SI 1 "general_operand" "rmn")))] + "" + "* +{ + if (GET_CODE (operands[1]) == CONST_INT) + { + int i = INTVAL (operands[1]); + if (i <= 7 && i >= -8) + { + cc_status.flags |= CC_REVERSED; + return \"cmpqd %1,%0\"; + } + } + cc_status.flags &= ~CC_REVERSED; + if (GET_CODE (operands[0]) == CONST_INT) + { + int i = INTVAL (operands[0]); + if (i <= 7 && i >= -8) + return \"cmpqd %0,%1\"; + } + return \"cmpd %0,%1\"; +}") + +(define_insn "cmphi" + [(set (cc0) + (compare (match_operand:HI 0 "general_operand" "g") + (match_operand:HI 1 "general_operand" "g")))] + "" + "* +{ + if (GET_CODE (operands[1]) == CONST_INT) + { + short i = INTVAL (operands[1]); + if (i <= 7 && i >= -8) + { + cc_status.flags |= CC_REVERSED; + if (INTVAL (operands[1]) > 7) + operands[1] = gen_rtx(CONST_INT, VOIDmode, i); + return \"cmpqw %1,%0\"; + } + } + cc_status.flags &= ~CC_REVERSED; + if (GET_CODE (operands[0]) == CONST_INT) + { + short i = INTVAL (operands[0]); + if (i <= 7 && i >= -8) + { + if (INTVAL (operands[0]) > 7) + operands[0] = gen_rtx(CONST_INT, VOIDmode, i); + return \"cmpqw %0,%1\"; + } + } + return \"cmpw %0,%1\"; +}") + +(define_insn "cmpqi" + [(set (cc0) + (compare (match_operand:QI 0 "general_operand" "g") + (match_operand:QI 1 "general_operand" "g")))] + "" + "* +{ + if (GET_CODE (operands[1]) == CONST_INT) + { + char i = INTVAL (operands[1]); + if (i <= 7 && i >= -8) + { + cc_status.flags |= CC_REVERSED; + if (INTVAL (operands[1]) > 7) + operands[1] = gen_rtx(CONST_INT, VOIDmode, i); + return \"cmpqb %1,%0\"; + } + } + cc_status.flags &= ~CC_REVERSED; + if (GET_CODE (operands[0]) == CONST_INT) + { + char i = INTVAL (operands[0]); + if (i <= 7 && i >= -8) + { + if (INTVAL (operands[0]) > 7) + operands[0] = gen_rtx(CONST_INT, VOIDmode, i); + return \"cmpqb %0,%1\"; + } + } + return \"cmpb %0,%1\"; +}") + +(define_insn "cmpdf" + [(set (cc0) + (compare (match_operand:DF 0 "general_operand" "fmF") + (match_operand:DF 1 "general_operand" "fmF")))] + "TARGET_32081" + "cmpl %0,%1") + +(define_insn "cmpsf" + [(set (cc0) + (compare (match_operand:SF 0 "general_operand" "fmF") + (match_operand:SF 1 "general_operand" "fmF")))] + "TARGET_32081" + "cmpf %0,%1") + +(define_insn "movdf" + [(set (match_operand:DF 0 "general_operand" "=&fg<") + (match_operand:DF 1 "general_operand" "fFg"))] + "" + "* +{ + if (FP_REG_P (operands[0])) + { + if (FP_REG_P (operands[1]) || GET_CODE (operands[1]) == CONST_DOUBLE) + return \"movl %1,%0\"; + if (REG_P (operands[1])) + { + rtx xoperands[2]; + xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1); + output_asm_insn (\"movd %1,tos\", xoperands); + output_asm_insn (\"movd %1,tos\", operands); + return \"movl tos,%0\"; + } + return \"movl %1,%0\"; + } + else if (FP_REG_P (operands[1])) + { + if (REG_P (operands[0])) + { + output_asm_insn (\"movl %1,tos\;movd tos,%0\", operands); + operands[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); + return \"movd tos,%0\"; + } + else + return \"movl %1,%0\"; + } + return output_move_double (operands); +}") + +(define_insn "movsf" + [(set (match_operand:SF 0 "general_operand" "=fg<") + (match_operand:SF 1 "general_operand" "fFg"))] + "" + "* +{ + if (FP_REG_P (operands[0])) + { + if (GET_CODE (operands[1]) == REG && REGNO (operands[1]) < 8) + return \"movd %1,tos\;movf tos,%0\"; + else + return \"movf %1,%0\"; + } + else if (FP_REG_P (operands[1])) + { + if (REG_P (operands[0])) + return \"movf %1,tos\;movd tos,%0\"; + return \"movf %1,%0\"; + } +#ifndef GAS_SYNTAX + /* GAS understands floating constants in ordinary movd instructions + * but other assembers might object. + */ + else if (GET_CODE (operands[1]) == CONST_DOUBLE) + { + union {int i[2]; float f; double d;} convrt; + convrt.i[0] = CONST_DOUBLE_LOW (operands[1]); + convrt.i[1] = CONST_DOUBLE_HIGH (operands[1]); + convrt.f = convrt.d; + + /* Is there a better machine-independent way to to this? */ + operands[1] = gen_rtx (CONST_INT, VOIDmode, convrt.i[0]); + return \"movd %1,%0\"; + } +#endif + else return \"movd %1,%0\"; +}") + +(define_insn "" + [(set (match_operand:TI 0 "memory_operand" "=m") + (match_operand:TI 1 "memory_operand" "m"))] + "" + "movmd %1,%0,4") + +(define_insn "movdi" + [(set (match_operand:DI 0 "general_operand" "=&g<,*f,g") + (match_operand:DI 1 "general_operand" "gF,g,*f"))] + "" + "* +{ + if (FP_REG_P (operands[0])) + { + if (FP_REG_P (operands[1]) || GET_CODE (operands[1]) == CONST_DOUBLE) + return \"movl %1,%0\"; + if (REG_P (operands[1])) + { + rtx xoperands[2]; + xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1); + output_asm_insn (\"movd %1,tos\", xoperands); + output_asm_insn (\"movd %1,tos\", operands); + return \"movl tos,%0\"; + } + return \"movl %1,%0\"; + } + else if (FP_REG_P (operands[1])) + { + if (REG_P (operands[0])) + { + output_asm_insn (\"movl %1,tos\;movd tos,%0\", operands); + operands[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); + return \"movd tos,%0\"; + } + else + return \"movl %1,%0\"; + } + return output_move_double (operands); +}") + +;; This special case must precede movsi. +(define_insn "" + [(set (reg:SI 17) + (match_operand:SI 0 "general_operand" "rmn"))] + "" + "lprd sp,%0") + +(define_insn "movsi" + [(set (match_operand:SI 0 "general_operand" "=g<,*f,g") + (match_operand:SI 1 "general_operand" "gx,g,*f"))] + "" + "* +{ + if (FP_REG_P (operands[0])) + { + if (GET_CODE (operands[1]) == REG && REGNO (operands[1]) < 8) + return \"movd %1,tos\;movf tos,%0\"; + else + return \"movf %1,%0\"; + } + else if (FP_REG_P (operands[1])) + { + if (REG_P (operands[0])) + return \"movf %1,tos\;movd tos,%0\"; + return \"movf %1,%0\"; + } + if (GET_CODE (operands[1]) == CONST_INT) + { + int i = INTVAL (operands[1]); + if (i <= 7 && i >= -8) + return \"movqd %1,%0\"; + if (i < 0x4000 && i >= -0x4000) +#ifdef GNX_V3 + return \"addr %c1,%0\"; +#else + return \"addr @%c1,%0\"; +#endif + return \"movd %1,%0\"; + } + else if (GET_CODE (operands[1]) == REG) + { + if (REGNO (operands[1]) < 16) + return \"movd %1,%0\"; + else if (REGNO (operands[1]) == FRAME_POINTER_REGNUM) + { + if (GET_CODE(operands[0]) == REG) + return \"sprd fp,%0\"; + else + return \"addr 0(fp),%0\" ; + } + else if (REGNO (operands[1]) == STACK_POINTER_REGNUM) + { + if (GET_CODE(operands[0]) == REG) + return \"sprd sp,%0\"; + else + return \"addr 0(sp),%0\" ; + } + else abort (0); + } + else if (GET_CODE (operands[1]) == MEM) + return \"movd %1,%0\"; + /* Check if this effective address can be + calculated faster by pulling it apart. */ + if (REG_P (operands[0]) + && GET_CODE (operands[1]) == MULT + && GET_CODE (XEXP (operands[1], 1)) == CONST_INT + && (INTVAL (XEXP (operands[1], 1)) == 2 + || INTVAL (XEXP (operands[1], 1)) == 4)) + { + rtx xoperands[3]; + xoperands[0] = operands[0]; + xoperands[1] = XEXP (operands[1], 0); + xoperands[2] = gen_rtx (CONST_INT, VOIDmode, INTVAL (XEXP (operands[1], 1)) >> 1); + return output_shift_insn (xoperands); + } + return \"addr %a1,%0\"; +}") + +(define_insn "movhi" + [(set (match_operand:HI 0 "general_operand" "=g<") + (match_operand:HI 1 "general_operand" "g"))] + "" + "* +{ + if (GET_CODE (operands[1]) == CONST_INT) + { + short i = INTVAL (operands[1]); + if (i <= 7 && i >= -8) + { + if (INTVAL (operands[1]) > 7) + operands[1] = + gen_rtx (CONST_INT, VOIDmode, i); + return \"movqw %1,%0\"; + } + } + return \"movw %1,%0\"; +}") + +(define_insn "movstricthi" + [(set (strict_low_part (match_operand:HI 0 "general_operand" "+r")) + (match_operand:HI 1 "general_operand" "g"))] + "" + "* +{ + if (GET_CODE (operands[1]) == CONST_INT + && INTVAL(operands[1]) <= 7 && INTVAL(operands[1]) >= -8) + return \"movqw %1,%0\"; + return \"movw %1,%0\"; +}") + +(define_insn "movqi" + [(set (match_operand:QI 0 "general_operand" "=g<") + (match_operand:QI 1 "general_operand" "g"))] + "" + "* +{ if (GET_CODE (operands[1]) == CONST_INT) + { + char char_val = (char)INTVAL (operands[1]); + if (char_val <= 7 && char_val >= -8) + { + if (INTVAL (operands[1]) > 7) + operands[1] = + gen_rtx (CONST_INT, VOIDmode, char_val); + return \"movqb %1,%0\"; + } + } + return \"movb %1,%0\"; +}") + +(define_insn "movstrictqi" + [(set (strict_low_part (match_operand:QI 0 "general_operand" "+r")) + (match_operand:QI 1 "general_operand" "g"))] + "" + "* +{ + if (GET_CODE (operands[1]) == CONST_INT + && INTVAL(operands[1]) < 8 && INTVAL(operands[1]) > -9) + return \"movqb %1,%0\"; + return \"movb %1,%0\"; +}") + +;; The definition of this insn does not really explain what it does, +;; but it should suffice +;; that anything generated as this insn will be recognized as one +;; and that it won't successfully combine with anything. +(define_insn "movstrsi" + [(set (match_operand:BLK 0 "general_operand" "=g") + (match_operand:BLK 1 "general_operand" "g")) + (use (match_operand:SI 2 "general_operand" "rmn")) + (clobber (reg:SI 0)) + (clobber (reg:SI 1)) + (clobber (reg:SI 2))] + "" + "* +{ + if (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM) + abort (); + operands[0] = XEXP (operands[0], 0); + operands[1] = XEXP (operands[1], 0); + if (GET_CODE (operands[0]) == MEM) + if (GET_CODE (operands[1]) == MEM) + output_asm_insn (\"movd %0,r2\;movd %1,r1\", operands); + else + output_asm_insn (\"movd %0,r2\;addr %a1,r1\", operands); + else if (GET_CODE (operands[1]) == MEM) + output_asm_insn (\"addr %a0,r2\;movd %1,r1\", operands); + else + output_asm_insn (\"addr %a0,r2\;addr %a1,r1\", operands); + + if (GET_CODE (operands[2]) == CONST_INT && (INTVAL (operands[2]) & 0x3) == 0) + { + operands[2] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[2]) >> 2); + if ((unsigned) INTVAL (operands[2]) <= 7) + return \"movqd %2,r0\;movsd\"; + else + return \"movd %2,r0\;movsd\"; + } + else + { + return \"movd %2,r0\;movsb\"; + } +}") + +;; Extension and truncation insns. +;; Those for integer source operand +;; are ordered widest source type first. + +(define_insn "truncsiqi2" + [(set (match_operand:QI 0 "general_operand" "=g<") + (truncate:QI (match_operand:SI 1 "general_operand" "rmn")))] + "" + "movb %1,%0") + +(define_insn "truncsihi2" + [(set (match_operand:HI 0 "general_operand" "=g<") + (truncate:HI (match_operand:SI 1 "general_operand" "rmn")))] + "" + "movw %1,%0") + +(define_insn "trunchiqi2" + [(set (match_operand:QI 0 "general_operand" "=g<") + (truncate:QI (match_operand:HI 1 "general_operand" "g")))] + "" + "movb %1,%0") + +(define_insn "extendhisi2" + [(set (match_operand:SI 0 "general_operand" "=g<") + (sign_extend:SI (match_operand:HI 1 "general_operand" "g")))] + "" + "movxwd %1,%0") + +(define_insn "extendqihi2" + [(set (match_operand:HI 0 "general_operand" "=g<") + (sign_extend:HI (match_operand:QI 1 "general_operand" "g")))] + "" + "movxbw %1,%0") + +(define_insn "extendqisi2" + [(set (match_operand:SI 0 "general_operand" "=g<") + (sign_extend:SI (match_operand:QI 1 "general_operand" "g")))] + "" + "movxbd %1,%0") + +(define_insn "extendsfdf2" + [(set (match_operand:DF 0 "general_operand" "=fm<") + (float_extend:DF (match_operand:SF 1 "general_operand" "fmF")))] + "TARGET_32081" + "movfl %1,%0") + +(define_insn "truncdfsf2" + [(set (match_operand:SF 0 "general_operand" "=fm<") + (float_truncate:SF (match_operand:DF 1 "general_operand" "fmF")))] + "TARGET_32081" + "movlf %1,%0") + +(define_insn "zero_extendhisi2" + [(set (match_operand:SI 0 "general_operand" "=g<") + (zero_extend:SI (match_operand:HI 1 "general_operand" "g")))] + "" + "movzwd %1,%0") + +(define_insn "zero_extendqihi2" + [(set (match_operand:HI 0 "general_operand" "=g<") + (zero_extend:HI (match_operand:QI 1 "general_operand" "g")))] + "" + "movzbw %1,%0") + +(define_insn "zero_extendqisi2" + [(set (match_operand:SI 0 "general_operand" "=g<") + (zero_extend:SI (match_operand:QI 1 "general_operand" "g")))] + "" + "movzbd %1,%0") + +;; Fix-to-float conversion insns. +;; Note that the ones that start with SImode come first. +;; That is so that an operand that is a CONST_INT +;; (and therefore lacks a specific machine mode). +;; will be recognized as SImode (which is always valid) +;; rather than as QImode or HImode. + +;; Rumor has it that the National part does not correctly convert +;; constant ints to floats. This conversion is therefore disabled. +;; A register must be used to perform the conversion. + +(define_insn "floatsisf2" + [(set (match_operand:SF 0 "general_operand" "=fm<") + (float:SF (match_operand:SI 1 "general_operand" "rm")))] + "TARGET_32081" + "movdf %1,%0") + +(define_insn "floatsidf2" + [(set (match_operand:DF 0 "general_operand" "=fm<") + (float:DF (match_operand:SI 1 "general_operand" "rm")))] + "TARGET_32081" + "movdl %1,%0") + +(define_insn "floathisf2" + [(set (match_operand:SF 0 "general_operand" "=fm<") + (float:SF (match_operand:HI 1 "general_operand" "rm")))] + "TARGET_32081" + "movwf %1,%0") + +(define_insn "floathidf2" + [(set (match_operand:DF 0 "general_operand" "=fm<") + (float:DF (match_operand:HI 1 "general_operand" "rm")))] + "TARGET_32081" + "movwl %1,%0") + +(define_insn "floatqisf2" + [(set (match_operand:SF 0 "general_operand" "=fm<") + (float:SF (match_operand:QI 1 "general_operand" "rm")))] + "TARGET_32081" + "movbf %1,%0") + +; Some assemblers warn that this insn doesn't work. +; Maybe they know something we don't. +;(define_insn "floatqidf2" +; [(set (match_operand:DF 0 "general_operand" "=fm<") +; (float:DF (match_operand:QI 1 "general_operand" "rm")))] +; "TARGET_32081" +; "movbl %1,%0") + +;; Float-to-fix conversion insns. +;; The sequent compiler always generates "trunc" insns. + +(define_insn "fixsfqi2" + [(set (match_operand:QI 0 "general_operand" "=g<") + (fix:QI (fix:SF (match_operand:SF 1 "general_operand" "fm"))))] + "TARGET_32081" + "truncfb %1,%0") + +(define_insn "fixsfhi2" + [(set (match_operand:HI 0 "general_operand" "=g<") + (fix:HI (fix:SF (match_operand:SF 1 "general_operand" "fm"))))] + "TARGET_32081" + "truncfw %1,%0") + +(define_insn "fixsfsi2" + [(set (match_operand:SI 0 "general_operand" "=g<") + (fix:SI (fix:SF (match_operand:SF 1 "general_operand" "fm"))))] + "TARGET_32081" + "truncfd %1,%0") + +(define_insn "fixdfqi2" + [(set (match_operand:QI 0 "general_operand" "=g<") + (fix:QI (fix:DF (match_operand:DF 1 "general_operand" "fm"))))] + "TARGET_32081" + "trunclb %1,%0") + +(define_insn "fixdfhi2" + [(set (match_operand:HI 0 "general_operand" "=g<") + (fix:HI (fix:DF (match_operand:DF 1 "general_operand" "fm"))))] + "TARGET_32081" + "trunclw %1,%0") + +(define_insn "fixdfsi2" + [(set (match_operand:SI 0 "general_operand" "=g<") + (fix:SI (fix:DF (match_operand:DF 1 "general_operand" "fm"))))] + "TARGET_32081" + "truncld %1,%0") + +;; Unsigned + +(define_insn "fixunssfqi2" + [(set (match_operand:QI 0 "general_operand" "=g<") + (unsigned_fix:QI (fix:SF (match_operand:SF 1 "general_operand" "fm"))))] + "TARGET_32081" + "truncfb %1,%0") + +(define_insn "fixunssfhi2" + [(set (match_operand:HI 0 "general_operand" "=g<") + (unsigned_fix:HI (fix:SF (match_operand:SF 1 "general_operand" "fm"))))] + "TARGET_32081" + "truncfw %1,%0") + +(define_insn "fixunssfsi2" + [(set (match_operand:SI 0 "general_operand" "=g<") + (unsigned_fix:SI (fix:SF (match_operand:SF 1 "general_operand" "fm"))))] + "TARGET_32081" + "truncfd %1,%0") + +(define_insn "fixunsdfqi2" + [(set (match_operand:QI 0 "general_operand" "=g<") + (unsigned_fix:QI (fix:DF (match_operand:DF 1 "general_operand" "fm"))))] + "TARGET_32081" + "trunclb %1,%0") + +(define_insn "fixunsdfhi2" + [(set (match_operand:HI 0 "general_operand" "=g<") + (unsigned_fix:HI (fix:DF (match_operand:DF 1 "general_operand" "fm"))))] + "TARGET_32081" + "trunclw %1,%0") + +(define_insn "fixunsdfsi2" + [(set (match_operand:SI 0 "general_operand" "=g<") + (unsigned_fix:SI (fix:DF (match_operand:DF 1 "general_operand" "fm"))))] + "TARGET_32081" + "truncld %1,%0") + +;;; These are not yet used by GCC +(define_insn "fix_truncsfqi2" + [(set (match_operand:QI 0 "general_operand" "=g<") + (fix:QI (match_operand:SF 1 "general_operand" "fm")))] + "TARGET_32081" + "truncfb %1,%0") + +(define_insn "fix_truncsfhi2" + [(set (match_operand:HI 0 "general_operand" "=g<") + (fix:HI (match_operand:SF 1 "general_operand" "fm")))] + "TARGET_32081" + "truncfw %1,%0") + +(define_insn "fix_truncsfsi2" + [(set (match_operand:SI 0 "general_operand" "=g<") + (fix:SI (match_operand:SF 1 "general_operand" "fm")))] + "TARGET_32081" + "truncfd %1,%0") + +(define_insn "fix_truncdfqi2" + [(set (match_operand:QI 0 "general_operand" "=g<") + (fix:QI (match_operand:DF 1 "general_operand" "fm")))] + "TARGET_32081" + "trunclb %1,%0") + +(define_insn "fix_truncdfhi2" + [(set (match_operand:HI 0 "general_operand" "=g<") + (fix:HI (match_operand:DF 1 "general_operand" "fm")))] + "TARGET_32081" + "trunclw %1,%0") + +(define_insn "fix_truncdfsi2" + [(set (match_operand:SI 0 "general_operand" "=g<") + (fix:SI (match_operand:DF 1 "general_operand" "fm")))] + "TARGET_32081" + "truncld %1,%0") + +;;- All kinds of add instructions. + +(define_insn "adddf3" + [(set (match_operand:DF 0 "general_operand" "=fm") + (plus:DF (match_operand:DF 1 "general_operand" "%0") + (match_operand:DF 2 "general_operand" "fmF")))] + "TARGET_32081" + "addl %2,%0") + + +(define_insn "addsf3" + [(set (match_operand:SF 0 "general_operand" "=fm") + (plus:SF (match_operand:SF 1 "general_operand" "%0") + (match_operand:SF 2 "general_operand" "fmF")))] + "TARGET_32081" + "addf %2,%0") + +(define_insn "" + [(set (reg:SI 17) + (plus:SI (reg:SI 17) + (match_operand:SI 0 "immediate_operand" "i")))] + "GET_CODE (operands[0]) == CONST_INT" + "* +{ +#ifndef SEQUENT_ADJUST_STACK + if (INTVAL (operands[0]) == 8) + return \"cmpd tos,tos\"; + if (INTVAL (operands[0]) == 4) + return \"cmpqd %$0,tos\"; +#endif + if (INTVAL (operands[0]) < 64 && INTVAL (operands[0]) > -64) + return \"adjspb %$%n0\"; + else if (INTVAL (operands[0]) < 8192 && INTVAL (operands[0]) >= -8192) + return \"adjspw %$%n0\"; + return \"adjspd %$%n0\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=g<") + (plus:SI (reg:SI 16) + (match_operand:SI 1 "immediate_operand" "i")))] + "GET_CODE (operands[1]) == CONST_INT" + "addr %c1(fp),%0") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=g<") + (plus:SI (reg:SI 17) + (match_operand:SI 1 "immediate_operand" "i")))] + "GET_CODE (operands[1]) == CONST_INT" + "addr %c1(sp),%0") + +(define_insn "addsi3" + [(set (match_operand:SI 0 "general_operand" "=g,=g<") + (plus:SI (match_operand:SI 1 "general_operand" "%0,%r") + (match_operand:SI 2 "general_operand" "rmn,n")))] + "" + "* +{ + if (which_alternative == 1) + { + int i = INTVAL (operands[2]); + if ( i < 0x40000000 && i >= -0x40000000 ) + return \"addr %c2(%1),%0\"; + else + return \"movd %1,%0\;addd %2,%0\"; + } + if (GET_CODE (operands[2]) == CONST_INT) + { + int i = INTVAL (operands[2]); + + if (i <= 7 && i >= -8) + return \"addqd %2,%0\"; + else if (GET_CODE (operands[0]) == REG + && i < 0x4000 && i >= -0x4000) + return \"addr %c2(%0),%0\"; + } + return \"addd %2,%0\"; +}") + +(define_insn "addhi3" + [(set (match_operand:HI 0 "general_operand" "=g") + (plus:HI (match_operand:HI 1 "general_operand" "%0") + (match_operand:HI 2 "general_operand" "g")))] + "" + "* +{ if (GET_CODE (operands[2]) == CONST_INT) + { + int i = INTVAL (operands[2]); + if (i <= 7 && i >= -8) + return \"addqw %2,%0\"; + } + return \"addw %2,%0\"; +}") + +(define_insn "" + [(set (strict_low_part (match_operand:HI 0 "general_operand" "=r")) + (plus:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "g")))] + "" + "* +{ + if (GET_CODE (operands[1]) == CONST_INT + && INTVAL (operands[1]) >-9 && INTVAL(operands[1]) < 8) + return \"addqw %1,%0\"; + return \"addw %1,%0\"; +}") + +(define_insn "addqi3" + [(set (match_operand:QI 0 "general_operand" "=g") + (plus:QI (match_operand:QI 1 "general_operand" "%0") + (match_operand:QI 2 "general_operand" "g")))] + "" + "* +{ if (GET_CODE (operands[2]) == CONST_INT) + { + int i = INTVAL (operands[2]); + if (i <= 7 && i >= -8) + return \"addqb %2,%0\"; + } + return \"addb %2,%0\"; +}") + +(define_insn "" + [(set (strict_low_part (match_operand:QI 0 "general_operand" "=r")) + (plus:QI (match_operand:QI 1 "general_operand" "0") + (match_operand:QI 2 "general_operand" "g")))] + "" + "* +{ + if (GET_CODE (operands[1]) == CONST_INT + && INTVAL (operands[1]) >-9 && INTVAL(operands[1]) < 8) + return \"addqb %1,%0\"; + return \"addb %1,%0\"; +}") + +;;- All kinds of subtract instructions. + +(define_insn "subdf3" + [(set (match_operand:DF 0 "general_operand" "=fm") + (minus:DF (match_operand:DF 1 "general_operand" "0") + (match_operand:DF 2 "general_operand" "fmF")))] + "TARGET_32081" + "subl %2,%0") + +(define_insn "subsf3" + [(set (match_operand:SF 0 "general_operand" "=fm") + (minus:SF (match_operand:SF 1 "general_operand" "0") + (match_operand:SF 2 "general_operand" "fmF")))] + "TARGET_32081" + "subf %2,%0") + +(define_insn "" + [(set (reg:SI 17) + (minus:SI (reg:SI 17) + (match_operand:SI 0 "immediate_operand" "i")))] + "GET_CODE (operands[0]) == CONST_INT" + "* +{ + if (GET_CODE(operands[0]) == CONST_INT && INTVAL(operands[0]) < 64 + && INTVAL(operands[0]) > -64) + return \"adjspb %0\"; + return \"adjspd %0\"; +}") + +(define_insn "subsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (minus:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "rmn")))] + "" + "* +{ if (GET_CODE (operands[2]) == CONST_INT) + { + int i = INTVAL (operands[2]); + + if (i <= 8 && i >= -7) + return \"addqd %$%n2,%0\"; + } + return \"subd %2,%0\"; +}") + +(define_insn "subhi3" + [(set (match_operand:HI 0 "general_operand" "=g") + (minus:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "g")))] + "" + "* +{ if (GET_CODE (operands[2]) == CONST_INT) + { + int i = INTVAL (operands[2]); + + if (i <= 8 && i >= -7) + return \"addqw %$%n2,%0\"; + } + return \"subw %2,%0\"; +}") + +(define_insn "" + [(set (strict_low_part (match_operand:HI 0 "general_operand" "=r")) + (minus:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "g")))] + "" + "* +{ + if (GET_CODE (operands[1]) == CONST_INT + && INTVAL (operands[1]) >-8 && INTVAL(operands[1]) < 9) + return \"addqw %$%n1,%0\"; + return \"subw %1,%0\"; +}") + +(define_insn "subqi3" + [(set (match_operand:QI 0 "general_operand" "=g") + (minus:QI (match_operand:QI 1 "general_operand" "0") + (match_operand:QI 2 "general_operand" "g")))] + "" + "* +{ if (GET_CODE (operands[2]) == CONST_INT) + { + int i = INTVAL (operands[2]); + + if (i <= 8 && i >= -7) + return \"addqb %$%n2,%0\"; + } + return \"subb %2,%0\"; +}") + +(define_insn "" + [(set (strict_low_part (match_operand:QI 0 "general_operand" "=r")) + (minus:QI (match_operand:QI 1 "general_operand" "0") + (match_operand:QI 2 "general_operand" "g")))] + "" + "* +{ + if (GET_CODE (operands[1]) == CONST_INT + && INTVAL (operands[1]) >-8 && INTVAL(operands[1]) < 9) + return \"addqb %$%n1,%0\"; + return \"subb %1,%0\"; +}") + +;;- Multiply instructions. + +(define_insn "muldf3" + [(set (match_operand:DF 0 "general_operand" "=fm") + (mult:DF (match_operand:DF 1 "general_operand" "%0") + (match_operand:DF 2 "general_operand" "fmF")))] + "TARGET_32081" + "mull %2,%0") + +(define_insn "mulsf3" + [(set (match_operand:SF 0 "general_operand" "=fm") + (mult:SF (match_operand:SF 1 "general_operand" "%0") + (match_operand:SF 2 "general_operand" "fmF")))] + "TARGET_32081" + "mulf %2,%0") + +(define_insn "mulsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (mult:SI (match_operand:SI 1 "general_operand" "%0") + (match_operand:SI 2 "general_operand" "rmn")))] + "" + "muld %2,%0") + +(define_insn "mulhi3" + [(set (match_operand:HI 0 "general_operand" "=g") + (mult:HI (match_operand:HI 1 "general_operand" "%0") + (match_operand:HI 2 "general_operand" "g")))] + "" + "mulw %2,%0") + +(define_insn "mulqi3" + [(set (match_operand:QI 0 "general_operand" "=g") + (mult:QI (match_operand:QI 1 "general_operand" "%0") + (match_operand:QI 2 "general_operand" "g")))] + "" + "mulb %2,%0") + +(define_insn "umulsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (umult:SI (match_operand:SI 1 "general_operand" "%0") + (match_operand:SI 2 "general_operand" "rmn")))] + "" + "muld %2,%0") + +(define_insn "umulhi3" + [(set (match_operand:HI 0 "general_operand" "=g") + (umult:HI (match_operand:HI 1 "general_operand" "%0") + (match_operand:HI 2 "general_operand" "g")))] + "" + "mulw %2,%0") + +(define_insn "umulqi3" + [(set (match_operand:QI 0 "general_operand" "=g") + (umult:QI (match_operand:QI 1 "general_operand" "%0") + (match_operand:QI 2 "general_operand" "g")))] + "" + "mulb %2,%0") + +(define_insn "umulsidi3" + [(set (match_operand:DI 0 "general_operand" "=g") + (umult:DI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "rmn")))] + "" + "meid %2,%0") + +;;- Divide instructions. + +(define_insn "divdf3" + [(set (match_operand:DF 0 "general_operand" "=fm") + (div:DF (match_operand:DF 1 "general_operand" "0") + (match_operand:DF 2 "general_operand" "fmF")))] + "TARGET_32081" + "divl %2,%0") + +(define_insn "divsf3" + [(set (match_operand:SF 0 "general_operand" "=fm") + (div:SF (match_operand:SF 1 "general_operand" "0") + (match_operand:SF 2 "general_operand" "fmF")))] + "TARGET_32081" + "divf %2,%0") + +(define_insn "divsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (div:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "rmn")))] + "" + "quod %2,%0") + +(define_insn "divhi3" + [(set (match_operand:HI 0 "general_operand" "=g") + (div:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "g")))] + "" + "quow %2,%0") + +(define_insn "divqi3" + [(set (match_operand:QI 0 "general_operand" "=g") + (div:QI (match_operand:QI 1 "general_operand" "0") + (match_operand:QI 2 "general_operand" "g")))] + "" + "quob %2,%0") + +(define_insn "udivsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (udiv:SI (subreg:SI (match_operand:DI 1 "reg_or_mem_operand" "0") 0) + (match_operand:SI 2 "general_operand" "rmn")))] + "" + "* +{ + operands[1] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); + return \"deid %2,%0\;movd %1,%0\"; +}") + +(define_insn "udivhi3" + [(set (match_operand:HI 0 "register_operand" "=r") + (udiv:HI (subreg:HI (match_operand:DI 1 "reg_or_mem_operand" "0") 0) + (match_operand:HI 2 "general_operand" "g")))] + "" + "* +{ + operands[1] = gen_rtx (REG, HImode, REGNO (operands[0]) + 1); + return \"deiw %2,%0\;movw %1,%0\"; +}") + +(define_insn "udivqi3" + [(set (match_operand:QI 0 "register_operand" "=r") + (udiv:QI (subreg:QI (match_operand:DI 1 "reg_or_mem_operand" "0") 0) + (match_operand:QI 2 "general_operand" "g")))] + "" + "* +{ + operands[1] = gen_rtx (REG, QImode, REGNO (operands[0]) + 1); + return \"deib %2,%0\;movb %1,%0\"; +}") + +;; Remainder instructions. + +(define_insn "modsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (mod:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "rmn")))] + "" + "remd %2,%0") + +(define_insn "modhi3" + [(set (match_operand:HI 0 "general_operand" "=g") + (mod:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "g")))] + "" + "remw %2,%0") + +(define_insn "modqi3" + [(set (match_operand:QI 0 "general_operand" "=g") + (mod:QI (match_operand:QI 1 "general_operand" "0") + (match_operand:QI 2 "general_operand" "g")))] + "" + "remb %2,%0") + +(define_insn "umodsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (umod:SI (subreg:SI (match_operand:DI 1 "reg_or_mem_operand" "0") 0) + (match_operand:SI 2 "general_operand" "rmn")))] + "" + "deid %2,%0") + +(define_insn "umodhi3" + [(set (match_operand:HI 0 "register_operand" "=r") + (umod:HI (subreg:HI (match_operand:DI 1 "reg_or_mem_operand" "0") 0) + (match_operand:HI 2 "general_operand" "g")))] + "" + "deiw %2,%0") + +(define_insn "umodqi3" + [(set (match_operand:QI 0 "register_operand" "=r") + (umod:QI (subreg:QI (match_operand:DI 1 "reg_or_mem_operand" "0") 0) + (match_operand:QI 2 "general_operand" "g")))] + "" + "deib %2,%0") + +; This isn't be usable in its current form. +;(define_insn "udivmoddisi4" +; [(set (subreg:SI (match_operand:DI 0 "general_operand" "=r") 1) +; (udiv:SI (match_operand:DI 1 "general_operand" "0") +; (match_operand:SI 2 "general_operand" "rmn"))) +; (set (subreg:SI (match_dup 0) 0) +; (umod:SI (match_dup 1) (match_dup 2)))] +; "" +; "deid %2,%0") + +;;- Logical Instructions: AND + +(define_insn "andsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (and:SI (match_operand:SI 1 "general_operand" "%0") + (match_operand:SI 2 "general_operand" "rmn")))] + "" + "* +{ + if (GET_CODE (operands[2]) == CONST_INT) + { + if ((INTVAL (operands[2]) | 0xff) == 0xffffffff) + { + if (INTVAL (operands[2]) == 0xffffff00) + return \"movqb %$0,%0\"; + else + { + operands[2] = gen_rtx (CONST_INT, VOIDmode, + INTVAL (operands[2]) & 0xff); + return \"andb %2,%0\"; + } + } + if ((INTVAL (operands[2]) | 0xffff) == 0xffffffff) + { + if (INTVAL (operands[2]) == 0xffff0000) + return \"movqw %$0,%0\"; + else + { + operands[2] = gen_rtx (CONST_INT, VOIDmode, + INTVAL (operands[2]) & 0xffff); + return \"andw %2,%0\"; + } + } + } + return \"andd %2,%0\"; +}") + +(define_insn "andhi3" + [(set (match_operand:HI 0 "general_operand" "=g") + (and:HI (match_operand:HI 1 "general_operand" "%0") + (match_operand:HI 2 "general_operand" "g")))] + "" + "* +{ + if (GET_CODE (operands[2]) == CONST_INT + && (INTVAL (operands[2]) | 0xff) == 0xffffffff) + { + if (INTVAL (operands[2]) == 0xffffff00) + return \"movqb %$0,%0\"; + else + { + operands[2] = gen_rtx (CONST_INT, VOIDmode, + INTVAL (operands[2]) & 0xff); + return \"andb %2,%0\"; + } + } + return \"andw %2,%0\"; +}") + +(define_insn "andqi3" + [(set (match_operand:QI 0 "general_operand" "=g") + (and:QI (match_operand:QI 1 "general_operand" "%0") + (match_operand:QI 2 "general_operand" "g")))] + "" + "andb %2,%0") + +(define_insn "andcbsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (and:SI (match_operand:SI 1 "general_operand" "0") + (not:SI (match_operand:SI 2 "general_operand" "rmn"))))] + "" + "* +{ + if (GET_CODE (operands[2]) == CONST_INT) + { + if ((INTVAL (operands[2]) & 0xffffff00) == 0) + return \"bicb %2,%0\"; + if ((INTVAL (operands[2]) & 0xffff0000) == 0) + return \"bicw %2,%0\"; + } + return \"bicd %2,%0\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=g") + (and:SI (not:SI (match_operand:SI 1 "general_operand" "rmn")) + (match_operand:SI 2 "general_operand" "0")))] + "" + "* +{ + if (GET_CODE (operands[1]) == CONST_INT) + { + if ((INTVAL (operands[1]) & 0xffffff00) == 0) + return \"bicb %1,%0\"; + if ((INTVAL (operands[1]) & 0xffff0000) == 0) + return \"bicw %1,%0\"; + } + return \"bicd %1,%0\"; +}") + +(define_insn "andcbhi3" + [(set (match_operand:HI 0 "general_operand" "=g") + (and:HI (match_operand:HI 1 "general_operand" "0") + (not:HI (match_operand:HI 2 "general_operand" "g"))))] + "" + "* +{ + if (GET_CODE (operands[2]) == CONST_INT + && (INTVAL (operands[2]) & 0xffffff00) == 0) + return \"bicb %2,%0\"; + return \"bicw %2,%0\"; +}") + +(define_insn "" + [(set (match_operand:HI 0 "general_operand" "=g") + (and:HI (not:HI (match_operand:HI 1 "general_operand" "g")) + (match_operand:HI 2 "general_operand" "0")))] + "" + "* +{ + if (GET_CODE (operands[1]) == CONST_INT + && (INTVAL (operands[1]) & 0xffffff00) == 0) + return \"bicb %1,%0\"; + return \"bicw %1,%0\"; +}") + +(define_insn "andcbqi3" + [(set (match_operand:QI 0 "general_operand" "=g") + (and:QI (match_operand:QI 1 "general_operand" "0") + (not:QI (match_operand:QI 2 "general_operand" "g"))))] + "" + "bicb %2,%0") + +(define_insn "" + [(set (match_operand:QI 0 "general_operand" "=g") + (and:QI (not:QI (match_operand:QI 1 "general_operand" "g")) + (match_operand:QI 2 "general_operand" "0")))] + "" + "bicb %1,%0") + +;;- Bit set instructions. + +(define_insn "iorsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (ior:SI (match_operand:SI 1 "general_operand" "%0") + (match_operand:SI 2 "general_operand" "rmn")))] + "" + "* +{ + if (GET_CODE (operands[2]) == CONST_INT) { + if ((INTVAL (operands[2]) & 0xffffff00) == 0) + return \"orb %2,%0\"; + if ((INTVAL (operands[2]) & 0xffff0000) == 0) + return \"orw %2,%0\"; + } + return \"ord %2,%0\"; +}") + +(define_insn "iorhi3" + [(set (match_operand:HI 0 "general_operand" "=g") + (ior:HI (match_operand:HI 1 "general_operand" "%0") + (match_operand:HI 2 "general_operand" "g")))] + "" + "* +{ + if (GET_CODE(operands[2]) == CONST_INT && + (INTVAL(operands[2]) & 0xffffff00) == 0) + return \"orb %2,%0\"; + return \"orw %2,%0\"; +}") + +(define_insn "iorqi3" + [(set (match_operand:QI 0 "general_operand" "=g") + (ior:QI (match_operand:QI 1 "general_operand" "%0") + (match_operand:QI 2 "general_operand" "g")))] + "" + "orb %2,%0") + +;;- xor instructions. + +(define_insn "xorsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (xor:SI (match_operand:SI 1 "general_operand" "%0") + (match_operand:SI 2 "general_operand" "rmn")))] + "" + "* +{ + if (GET_CODE (operands[2]) == CONST_INT) { + if ((INTVAL (operands[2]) & 0xffffff00) == 0) + return \"xorb %2,%0\"; + if ((INTVAL (operands[2]) & 0xffff0000) == 0) + return \"xorw %2,%0\"; + } + return \"xord %2,%0\"; +}") + +(define_insn "xorhi3" + [(set (match_operand:HI 0 "general_operand" "=g") + (xor:HI (match_operand:HI 1 "general_operand" "%0") + (match_operand:HI 2 "general_operand" "g")))] + "" + "* +{ + if (GET_CODE(operands[2]) == CONST_INT && + (INTVAL(operands[2]) & 0xffffff00) == 0) + return \"xorb %2,%0\"; + return \"xorw %2,%0\"; +}") + +(define_insn "xorqi3" + [(set (match_operand:QI 0 "general_operand" "=g") + (xor:QI (match_operand:QI 1 "general_operand" "%0") + (match_operand:QI 2 "general_operand" "g")))] + "" + "xorb %2,%0") + +(define_insn "negdf2" + [(set (match_operand:DF 0 "general_operand" "=fm<") + (neg:DF (match_operand:DF 1 "general_operand" "fmF")))] + "TARGET_32081" + "negl %1,%0") + +(define_insn "negsf2" + [(set (match_operand:SF 0 "general_operand" "=fm<") + (neg:SF (match_operand:SF 1 "general_operand" "fmF")))] + "TARGET_32081" + "negf %1,%0") + +(define_insn "negsi2" + [(set (match_operand:SI 0 "general_operand" "=g<") + (neg:SI (match_operand:SI 1 "general_operand" "rmn")))] + "" + "negd %1,%0") + +(define_insn "neghi2" + [(set (match_operand:HI 0 "general_operand" "=g<") + (neg:HI (match_operand:HI 1 "general_operand" "g")))] + "" + "negw %1,%0") + +(define_insn "negqi2" + [(set (match_operand:QI 0 "general_operand" "=g<") + (neg:QI (match_operand:QI 1 "general_operand" "g")))] + "" + "negb %1,%0") + +(define_insn "one_cmplsi2" + [(set (match_operand:SI 0 "general_operand" "=g<") + (not:SI (match_operand:SI 1 "general_operand" "rmn")))] + "" + "comd %1,%0") + +(define_insn "one_cmplhi2" + [(set (match_operand:HI 0 "general_operand" "=g<") + (not:HI (match_operand:HI 1 "general_operand" "g")))] + "" + "comw %1,%0") + +(define_insn "one_cmplqi2" + [(set (match_operand:QI 0 "general_operand" "=g<") + (not:QI (match_operand:QI 1 "general_operand" "g")))] + "" + "comb %1,%0") + +;; arithmetic left and right shift operations + +(define_insn "ashlsi3" + [(set (match_operand:SI 0 "general_operand" "=g,g") + (ashift:SI (match_operand:SI 1 "general_operand" "r,0") + (match_operand:SI 2 "general_operand" "I,rmn")))] + "" + "* return output_shift_insn (operands);") + +(define_insn "ashlhi3" + [(set (match_operand:HI 0 "general_operand" "=g") + (ashift:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "rmn")))] + "" + "* +{ if (GET_CODE (operands[2]) == CONST_INT) + if (INTVAL (operands[2]) == 1) + return \"addw %0,%0\"; + else if (INTVAL (operands[2]) == 2) + return \"addw %0,%0\;addw %0,%0\"; + return \"ashw %2,%0\"; +}") + +(define_insn "ashlqi3" + [(set (match_operand:QI 0 "general_operand" "=g") + (ashift:QI (match_operand:QI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "rmn")))] + "" + "* +{ if (GET_CODE (operands[2]) == CONST_INT) + if (INTVAL (operands[2]) == 1) + return \"addb %1,%0\"; + else if (INTVAL (operands[2]) == 2) + return \"addb %1,%0\;addb %0,%0\"; + return \"ashb %2,%0\"; +}") + +;; Arithmetic right shift on the 32k works by negating the shift count. +(define_expand "ashrsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (ashift:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")))] + "" + " +{ + operands[2] = negate_rtx (SImode, operands[2]); +}") + +(define_expand "ashrhi3" + [(set (match_operand:HI 0 "general_operand" "=g") + (ashift:HI (match_operand:HI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")))] + "" + " +{ + operands[2] = negate_rtx (SImode, operands[2]); +}") + +(define_expand "ashrqi3" + [(set (match_operand:QI 0 "general_operand" "=g") + (ashift:QI (match_operand:QI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")))] + "" + " +{ + operands[2] = negate_rtx (SImode, operands[2]); +}") + +;; logical shift instructions + +(define_insn "lshlsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (lshift:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "rmn")))] + "" + "lshd %2,%0") + +(define_insn "lshlhi3" + [(set (match_operand:HI 0 "general_operand" "=g") + (lshift:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "rmn")))] + "" + "lshw %2,%0") + +(define_insn "lshlqi3" + [(set (match_operand:QI 0 "general_operand" "=g") + (lshift:QI (match_operand:QI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "rmn")))] + "" + "lshb %2,%0") + +;; Logical right shift on the 32k works by negating the shift count. +(define_expand "lshrsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (lshift:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")))] + "" + " +{ + operands[2] = negate_rtx (SImode, operands[2]); +}") + +(define_expand "lshrhi3" + [(set (match_operand:HI 0 "general_operand" "=g") + (lshift:HI (match_operand:HI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")))] + "" + " +{ + operands[2] = negate_rtx (SImode, operands[2]); +}") + +(define_expand "lshrqi3" + [(set (match_operand:QI 0 "general_operand" "=g") + (lshift:QI (match_operand:QI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")))] + "" + " +{ + operands[2] = negate_rtx (SImode, operands[2]); +}") + +;; Rotate instructions + +(define_insn "rotlsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (rotate:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "rmn")))] + "" + "rotd %2,%0") + +(define_insn "rotlhi3" + [(set (match_operand:HI 0 "general_operand" "=g") + (rotate:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "rmn")))] + "" + "rotw %2,%0") + +(define_insn "rotlqi3" + [(set (match_operand:QI 0 "general_operand" "=g") + (rotate:QI (match_operand:QI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "rmn")))] + "" + "rotb %2,%0") + +;; Right rotate on the 32k works by negating the shift count. +(define_expand "rotrsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (rotate:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")))] + "" + " +{ + operands[2] = negate_rtx (SImode, operands[2]); +}") + +(define_expand "rotrhi3" + [(set (match_operand:HI 0 "general_operand" "=g") + (rotate:HI (match_operand:HI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")))] + "" + " +{ + operands[2] = negate_rtx (SImode, operands[2]); +}") + +(define_expand "rotrqi3" + [(set (match_operand:QI 0 "general_operand" "=g") + (rotate:QI (match_operand:QI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")))] + "" + " +{ + operands[2] = negate_rtx (SImode, operands[2]); +}") + +;;- load or push effective address +;; These come after the move, add, and multiply patterns +;; because we don't want pushl $1 turned into pushad 1. + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=g<") + (match_operand:QI 1 "address_operand" "p"))] + "" + "* +{ + if (REG_P (operands[0]) + && GET_CODE (operands[1]) == MULT + && GET_CODE (XEXP (operands[1], 1)) == CONST_INT + && (INTVAL (XEXP (operands[1], 1)) == 2 + || INTVAL (XEXP (operands[1], 1)) == 4)) + { + rtx xoperands[3]; + xoperands[0] = operands[0]; + xoperands[1] = XEXP (operands[1], 0); + xoperands[2] = gen_rtx (CONST_INT, VOIDmode, INTVAL (XEXP (operands[1], 1)) >> 1); + return output_shift_insn (xoperands); + } + return \"addr %a1,%0\"; +}") + +;;; Index insns. These are about the same speed as multiply-add counterparts. +;;; but slower then using power-of-2 shifts if we can use them +; +;(define_insn "" +; [(set (match_operand:SI 0 "register_operand" "=r") +; (plus:SI (match_operand:SI 1 "general_operand" "rmn") +; (mult:SI (match_operand:SI 2 "register_operand" "0") +; (plus:SI (match_operand:SI 3 "general_operand" "rmn") (const_int 1)))))] +; "GET_CODE (operands[3]) != CONST_INT || INTVAL (operands[3]) > 8" +; "indexd %0,%3,%1") +; +;(define_insn "" +; [(set (match_operand:SI 0 "register_operand" "=r") +; (plus:SI (mult:SI (match_operand:SI 1 "register_operand" "0") +; (plus:SI (match_operand:SI 2 "general_operand" "rmn") (const_int 1))) +; (match_operand:SI 3 "general_operand" "rmn")))] +; "GET_CODE (operands[2]) != CONST_INT || INTVAL (operands[2]) > 8" +; "indexd %0,%2,%3") + +;; Set, Clear, and Invert bit + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=g") + (ior:SI + (ashift:SI (const_int 1) + (match_operand:SI 1 "general_operand" "rmn")) + (match_dup 0)))] + "" + "sbitd %1,%0") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=g") + (ior:SI + (match_dup 0) + (ashift:SI (const_int 1) + (match_operand:SI 1 "general_operand" "rmn"))))] + "" + "sbitd %1,%0") + +(define_insn "" + [(set (match_operand:QI 0 "general_operand" "=g") + (ior:QI + (subreg:QI + (ashift:SI (const_int 1) + (match_operand:QI 1 "general_operand" "rmn")) 0) + (match_dup 0)))] + "" + "sbitb %1,%0") + +(define_insn "" + [(set (match_operand:QI 0 "general_operand" "=g") + (ior:QI + (match_dup 0) + (subreg:QI + (ashift:SI (const_int 1) + (match_operand:QI 1 "general_operand" "rmn")) 0)))] + "" + "sbitb %1,%0") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=g") + (and:SI + (not:SI + (ashift:SI (const_int 1) + (match_operand:SI 1 "general_operand" "rmn"))) + (match_dup 0)))] + "" + "cbitd %1,%0") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=g") + (and:SI + (match_dup 0) + (not:SI + (ashift:SI (const_int 1) + (match_operand:SI 1 "general_operand" "rmn")))))] + "" + "cbitd %1,%0") + +(define_insn "" + [(set (match_operand:QI 0 "general_operand" "=g") + (and:QI + (subreg:QI + (not:SI + (ashift:SI (const_int 1) + (match_operand:QI 1 "general_operand" "rmn"))) 0) + (match_dup 0)))] + "" + "cbitb %1,%0") + +(define_insn "" + [(set (match_operand:QI 0 "general_operand" "=g") + (and:QI + (match_dup 0) + (subreg:QI + (not:SI + (ashift:SI (const_int 1) + (match_operand:QI 1 "general_operand" "rmn"))) 0)))] + "" + "cbitb %1,%0") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=g") + (xor:SI + (ashift:SI (const_int 1) + (match_operand:SI 1 "general_operand" "rmn")) + (match_dup 0)))] + "" + "ibitd %1,%0") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=g") + (xor:SI + (match_dup 0) + (ashift:SI (const_int 1) + (match_operand:SI 1 "general_operand" "rmn"))))] + "" + "ibitd %1,%0") + +(define_insn "" + [(set (match_operand:QI 0 "general_operand" "=g") + (xor:QI + (subreg:QI + (ashift:SI (const_int 1) + (match_operand:QI 1 "general_operand" "rmn")) 0) + (match_dup 0)))] + "" + "ibitb %1,%0") + +(define_insn "" + [(set (match_operand:QI 0 "general_operand" "=g") + (xor:QI + (match_dup 0) + (subreg:QI + (ashift:SI (const_int 1) + (match_operand:QI 1 "general_operand" "rmn")) 0)))] + "" + "ibitb %1,%0") + +;; Recognize jbs and jbc instructions. + +(define_insn "" + [(set (cc0) + (zero_extract (match_operand:SI 0 "general_operand" "rm") + (const_int 1) + (match_operand:SI 1 "general_operand" "rmn")))] + "" + "* +{ cc_status.flags = CC_Z_IN_F; + return \"tbitd %1,%0\"; +}") + +(define_insn "" + [(set (cc0) + (compare (zero_extract (match_operand:SI 0 "general_operand" "rm") + (const_int 1) + (match_operand:SI 1 "general_operand" "rmn")) + (const_int 1)))] + "" + "* +{ cc_status.flags = CC_Z_IN_NOT_F; + return \"tbitd %1,%0\"; +}") + +(define_insn "" + [(set (cc0) + (zero_extract (match_operand:HI 0 "general_operand" "rm") + (const_int 1) + (match_operand:HI 1 "general_operand" "g")))] + "" + "* +{ cc_status.flags = CC_Z_IN_F; + return \"tbitw %1,%0\"; +}") + +(define_insn "" + [(set (cc0) + (compare (zero_extract (match_operand:HI 0 "general_operand" "rm") + (const_int 1) + (match_operand:HI 1 "general_operand" "g")) + (const_int 1)))] + "" + "* +{ cc_status.flags = CC_Z_IN_NOT_F; + return \"tbitw %1,%0\"; +}") + +(define_insn "" + [(set (cc0) + (zero_extract (match_operand:QI 0 "general_operand" "rm") + (const_int 1) + (match_operand:QI 1 "general_operand" "g")))] + "" + "* +{ cc_status.flags = CC_Z_IN_F; + return \"tbitb %1,%0\"; +}") + +(define_insn "" + [(set (cc0) + (compare (zero_extract:SI (match_operand:QI 0 "general_operand" "rm") + (const_int 1) + (match_operand:QI 1 "general_operand" "rmn")) + (const_int 1)))] + "" + "* +{ cc_status.flags = CC_Z_IN_NOT_F; + return \"tbitb %1,%0\"; +}") + +(define_insn "" + [(set (cc0) + (and:SI (match_operand:SI 0 "general_operand" "rm") + (match_operand:SI 1 "immediate_operand" "i")))] + "GET_CODE (operands[1]) == CONST_INT + && exact_log2 (INTVAL (operands[1])) >= 0" + "* +{ + operands[1] + = gen_rtx (CONST_INT, VOIDmode, exact_log2 (INTVAL (operands[1]))); + cc_status.flags = CC_Z_IN_F; + return \"tbitd %1,%0\"; +}") + +;; extract(base, width, offset) +;; Signed bitfield extraction is not supported in hardware on the +;; NS 32032. It is therefore better to let GCC figure out a +;; good strategy for generating the proper instruction sequence +;; and represent it as rtl. + +;; Optimize the case of extracting a byte or word from a register. +;; Otherwise we must load a register with the offset of the +;; chunk we want, and perform an extract insn (each of which +;; is very expensive). Since we use the stack to do our bit-twiddling +;; we cannot use it for a destination. Perhaps things are fast +;; enough on the 32532 that such hacks are not needed. + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=ro") + (zero_extract:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "const_int" "i") + (match_operand:SI 3 "const_int" "i")))] + "(INTVAL (operands[2]) == 8 || INTVAL (operands[2]) == 16) + && (INTVAL (operands[3]) == 8 || INTVAL (operands[3]) == 16 || INTVAL (operands[3]) == 24)" + "* +{ + output_asm_insn (\"movd %1,tos\", operands); + if (INTVAL (operands[2]) == 16) + { + if (INTVAL (operands[3]) == 8) + output_asm_insn (\"movzwd 1(sp),%0\", operands); + else + output_asm_insn (\"movzwd 2(sp),%0\", operands); + } + else + { + if (INTVAL (operands[3]) == 8) + output_asm_insn (\"movzbd 1(sp),%0\", operands); + else if (INTVAL (operands[3]) == 16) + output_asm_insn (\"movzbd 2(sp),%0\", operands); + else + output_asm_insn (\"movzbd 3(sp),%0\", operands); + } + return \"cmpqd %$0,tos\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=ro") + (zero_extract:SI (match_operand:HI 1 "register_operand" "r") + (match_operand:SI 2 "const_int" "i") + (match_operand:SI 3 "const_int" "i")))] + "INTVAL (operands[2]) == 8 && INTVAL (operands[3]) == 8" + "movw %1,tos\;movzbd 1(sp),%0\;adjspb %$-2") + +(define_insn "extzv" + [(set (match_operand:SI 0 "general_operand" "=g<,g<") + (zero_extract:SI (match_operand:SI 1 "general_operand" "rm,o") + (match_operand:SI 2 "const_int" "i,i") + (match_operand:SI 3 "general_operand" "rK,n")))] + "" + "* +{ if (GET_CODE (operands[3]) == CONST_INT) + { + if (INTVAL (operands[3]) >= 8) + operands[1] = adj_offsettable_operand (operands[1], + INTVAL (operands[3]) >> 3); + return \"extsd %1,%0,%3,%2\"; + } + else return \"extd %3,%1,%0,%2\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=g<,g<") + (zero_extract:SI (match_operand:HI 1 "general_operand" "rm,o") + (match_operand:SI 2 "const_int" "i,i") + (match_operand:SI 3 "general_operand" "rK,n")))] + "" + "* +{ if (GET_CODE (operands[3]) == CONST_INT) + { + if (INTVAL (operands[3]) >= 8) + operands[1] = adj_offsettable_operand (operands[1], + INTVAL (operands[3]) >> 3); + return \"extsd %1,%0,%3,%2\"; + } + else return \"extd %3,%1,%0,%2\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=g<") + (zero_extract:SI (match_operand:QI 1 "general_operand" "g") + (match_operand:SI 2 "const_int" "i") + (match_operand:SI 3 "general_operand" "rn")))] + "" + "* +{ if (GET_CODE (operands[3]) == CONST_INT) + return \"extsd %1,%0,%3,%2\"; + else return \"extd %3,%1,%0,%2\"; +}") + +(define_insn "insv" + [(set (zero_extract:SI (match_operand:SI 0 "general_operand" "+g,o") + (match_operand:SI 1 "const_int" "i,i") + (match_operand:SI 2 "general_operand" "rK,n")) + (match_operand:SI 3 "general_operand" "rm,rm"))] + "" + "* +{ if (GET_CODE (operands[2]) == CONST_INT) + { + if (GET_CODE (operands[0]) == MEM && INTVAL (operands[2]) >= 8) + { + operands[0] = adj_offsettable_operand (operands[0], + INTVAL (operands[2]) / 8); + operands[2] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[2]) % 8); + } + if (INTVAL (operands[1]) <= 8) + return \"inssb %3,%0,%2,%1\"; + else if (INTVAL (operands[1]) <= 16) + return \"inssw %3,%0,%2,%1\"; + else + return \"inssd %3,%0,%2,%1\"; + } + return \"insd %2,%3,%0,%1\"; +}") + +(define_insn "" + [(set (zero_extract:SI (match_operand:HI 0 "general_operand" "+g,o") + (match_operand:SI 1 "const_int" "i,i") + (match_operand:SI 2 "general_operand" "rK,n")) + (match_operand:SI 3 "general_operand" "rm,rm"))] + "" + "* +{ if (GET_CODE (operands[2]) == CONST_INT) + { + if (GET_CODE (operands[0]) == MEM && INTVAL (operands[2]) >= 8) + { + operands[0] = adj_offsettable_operand (operands[0], + INTVAL (operands[2]) / 8); + operands[2] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[2]) % 8); + } + if (INTVAL (operands[1]) <= 8) + return \"inssb %3,%0,%2,%1\"; + else if (INTVAL (operands[1]) <= 16) + return \"inssw %3,%0,%2,%1\"; + else + return \"inssd %3,%0,%2,%1\"; + } + return \"insd %2,%3,%0,%1\"; +}") + +(define_insn "" + [(set (zero_extract:SI (match_operand:QI 0 "general_operand" "=g") + (match_operand:SI 1 "const_int" "i") + (match_operand:SI 2 "general_operand" "rn")) + (match_operand:SI 3 "general_operand" "rm"))] + "" + "* +{ if (GET_CODE (operands[2]) == CONST_INT) + if (INTVAL (operands[1]) <= 8) + return \"inssb %3,%0,%2,%1\"; + else if (INTVAL (operands[1]) <= 16) + return \"inssw %3,%0,%2,%1\"; + else + return \"inssd %3,%0,%2,%1\"; + return \"insd %2,%3,%0,%1\"; +}") + + +(define_insn "jump" + [(set (pc) + (label_ref (match_operand 0 "" "")))] + "" + "br %l0") + +(define_insn "beq" + [(set (pc) + (if_then_else (eq (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +{ if (cc_prev_status.flags & CC_Z_IN_F) + return \"bfc %l0\"; + else if (cc_prev_status.flags & CC_Z_IN_NOT_F) + return \"bfs %l0\"; + else return \"beq %l0\"; +}") + +(define_insn "bne" + [(set (pc) + (if_then_else (ne (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +{ if (cc_prev_status.flags & CC_Z_IN_F) + return \"bfs %l0\"; + else if (cc_prev_status.flags & CC_Z_IN_NOT_F) + return \"bfc %l0\"; + else return \"bne %l0\"; +}") + +(define_insn "bgt" + [(set (pc) + (if_then_else (gt (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "bgt %l0") + +(define_insn "bgtu" + [(set (pc) + (if_then_else (gtu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "bhi %l0") + +(define_insn "blt" + [(set (pc) + (if_then_else (lt (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "blt %l0") + +(define_insn "bltu" + [(set (pc) + (if_then_else (ltu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "blo %l0") + +(define_insn "bge" + [(set (pc) + (if_then_else (ge (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "bge %l0") + +(define_insn "bgeu" + [(set (pc) + (if_then_else (geu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "bhs %l0") + +(define_insn "ble" + [(set (pc) + (if_then_else (le (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "ble %l0") + +(define_insn "bleu" + [(set (pc) + (if_then_else (leu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "bls %l0") + +(define_insn "" + [(set (pc) + (if_then_else (eq (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* +{ if (cc_prev_status.flags & CC_Z_IN_F) + return \"bfs %l0\"; + else if (cc_prev_status.flags & CC_Z_IN_NOT_F) + return \"bfc %l0\"; + else return \"bne %l0\"; +}") + +(define_insn "" + [(set (pc) + (if_then_else (ne (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* +{ if (cc_prev_status.flags & CC_Z_IN_F) + return \"bfc %l0\"; + else if (cc_prev_status.flags & CC_Z_IN_NOT_F) + return \"bfs %l0\"; + else return \"beq %l0\"; +}") + +(define_insn "" + [(set (pc) + (if_then_else (gt (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "ble %l0") + +(define_insn "" + [(set (pc) + (if_then_else (gtu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "bls %l0") + +(define_insn "" + [(set (pc) + (if_then_else (lt (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "bge %l0") + +(define_insn "" + [(set (pc) + (if_then_else (ltu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "bhs %l0") + +(define_insn "" + [(set (pc) + (if_then_else (ge (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "blt %l0") + +(define_insn "" + [(set (pc) + (if_then_else (geu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "blo %l0") + +(define_insn "" + [(set (pc) + (if_then_else (le (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "bgt %l0") + +(define_insn "" + [(set (pc) + (if_then_else (leu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "bhi %l0") + +;; Subtract-and-jump and Add-and-jump insns. +;; These can actually be used for adding numbers in the range -8 to 7 + +(define_insn "" + [(set (pc) + (if_then_else + (ne (minus:SI (match_operand:SI 0 "general_operand" "+g") + (match_operand:SI 1 "general_operand" "i")) + (const_int 0)) + (label_ref (match_operand 2 "" "")) + (pc))) + (set (match_dup 0) + (minus:SI (match_dup 0) + (match_dup 1)))] + "GET_CODE (operands[1]) == CONST_INT + && INTVAL (operands[1]) > -8 && INTVAL (operands[1]) <= 8" + "acbd %$%n1,%0,%l2") + +(define_insn "" + [(set (pc) + (if_then_else + (ne (plus:SI (match_operand:SI 0 "general_operand" "+g") + (match_operand:SI 1 "general_operand" "i")) + (const_int 0)) + (label_ref (match_operand 2 "" "")) + (pc))) + (set (match_dup 0) + (plus:SI (match_dup 0) + (match_dup 1)))] + "GET_CODE (operands[1]) == CONST_INT + && INTVAL (operands[1]) >= -8 && INTVAL (operands[1]) < 8" + "acbd %1,%0,%l2") + +;; Reversed + +(define_insn "" + [(set (pc) + (if_then_else + (eq (minus:SI (match_operand:SI 0 "general_operand" "+g") + (match_operand:SI 1 "general_operand" "i")) + (const_int 0)) + (pc) + (label_ref (match_operand 2 "" "")))) + (set (match_dup 0) + (minus:SI (match_dup 0) + (match_dup 1)))] + "GET_CODE (operands[1]) == CONST_INT + && INTVAL (operands[1]) > -8 && INTVAL (operands[1]) <= 8" + "acbd %$%n1,%0,%l2") + +(define_insn "" + [(set (pc) + (if_then_else + (eq (plus:SI (match_operand:SI 0 "general_operand" "+g") + (match_operand:SI 1 "general_operand" "i")) + (const_int 0)) + (pc) + (label_ref (match_operand 2 "" "")))) + (set (match_dup 0) + (plus:SI (match_dup 0) + (match_dup 1)))] + "GET_CODE (operands[1]) == CONST_INT + && INTVAL (operands[1]) >= -8 && INTVAL (operands[1]) < 8" + "acbd %1,%0,%l2") + +(define_insn "call" + [(call (match_operand:QI 0 "general_operand" "g") + (match_operand:QI 1 "general_operand" "g"))] + "" + "* +{ +#ifndef JSR_ALWAYS + if (GET_CODE (operands[0]) == MEM) + { + rtx temp = XEXP (operands[0], 0); + if (CONSTANT_ADDRESS_P (temp)) + { +#ifdef GAS_SYNTAX + operands[0] = temp; + return \"bsr %0\"; +#else +#ifdef GNX_V3 + return \"bsr %0\"; +#else + return \"bsr %?%a0\"; +#endif +#endif + } + if (GET_CODE (XEXP (operands[0], 0)) == REG) +#if defined(GNX_V3) || defined(GAS_SYNTAX) + return \"jsr %0\"; +#else + return \"jsr %a0\"; +#endif + } +#endif /* not JSR_ALWAYS */ + return \"jsr %0\"; +}") + +(define_insn "call_value" + [(set (match_operand 0 "" "=fg") + (call (match_operand:QI 1 "general_operand" "g") + (match_operand:QI 2 "general_operand" "g")))] + "" + "* +{ +#ifndef JSR_ALWAYS + if (GET_CODE (operands[0]) == MEM) + { + rtx temp = XEXP (operands[0], 0); + if (CONSTANT_ADDRESS_P (temp)) + { +#ifdef GAS_SYNTAX + operands[0] = temp; + return \"bsr %1\"; +#else +#ifdef GNX_V3 + return \"bsr %1\"; +#else + return \"bsr %?%a1\"; +#endif +#endif + } + if (GET_CODE (XEXP (operands[0], 0)) == REG) +#if defined(GNX_V3) || defined(GAS_SYNTAX) + return \"jsr %1\"; +#else + return \"jsr %a1\"; +#endif + } +#endif /* not JSR_ALWAYS */ + return \"jsr %1\"; +}") + +(define_insn "return" + [(return)] + "0" + "ret 0") + +(define_insn "abssf2" + [(set (match_operand:SF 0 "general_operand" "=fm<") + (abs:SF (match_operand:SF 1 "general_operand" "fmF")))] + "TARGET_32081" + "absf %1,%0") + +(define_insn "absdf2" + [(set (match_operand:DF 0 "general_operand" "=fm<") + (abs:DF (match_operand:DF 1 "general_operand" "fmF")))] + "TARGET_32081" + "absl %1,%0") + +(define_insn "abssi2" + [(set (match_operand:SI 0 "general_operand" "=g<") + (abs:SI (match_operand:SI 1 "general_operand" "rmn")))] + "" + "absd %1,%0") + +(define_insn "abshi2" + [(set (match_operand:HI 0 "general_operand" "=g<") + (abs:HI (match_operand:HI 1 "general_operand" "g")))] + "" + "absw %1,%0") + +(define_insn "absqi2" + [(set (match_operand:QI 0 "general_operand" "=g<") + (abs:QI (match_operand:QI 1 "general_operand" "g")))] + "" + "absb %1,%0") + +(define_insn "nop" + [(const_int 0)] + "" + "nop") + +;;(define_insn "tablejump" +;; [(set (pc) +;; (plus:SI (match_operand:SI 0 "general_operand" "g") +;; (pc)))] +;; "" +;; "cased %0") + +(define_insn "tablejump" + [(set (pc) + (plus:SI (pc) (match_operand:HI 0 "general_operand" "g"))) + (use (label_ref (match_operand 1 "" "")))] + "" + "* +{ + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, \"LI\", + CODE_LABEL_NUMBER (operands[1])); + return \"casew %0\"; +}") + +;;(define_insn "" +;; [(set (pc) +;; (plus:SI (match_operand:QI 0 "general_operand" "g") +;; (pc)))] +;; "" +;; "caseb %0") + +;; Scondi instructions +(define_insn "seq" + [(set (match_operand:SI 0 "general_operand" "=g<") + (eq (cc0) (const_int 0)))] + "" + "* +{ if (cc_prev_status.flags & CC_Z_IN_F) + return \"sfcd %0\"; + else if (cc_prev_status.flags & CC_Z_IN_NOT_F) + return \"sfsd %0\"; + else return \"seqd %0\"; +}") + +(define_insn "" + [(set (match_operand:HI 0 "general_operand" "=g<") + (eq (cc0) (const_int 0)))] + "" + "* +{ if (cc_prev_status.flags & CC_Z_IN_F) + return \"sfcw %0\"; + else if (cc_prev_status.flags & CC_Z_IN_NOT_F) + return \"sfsw %0\"; + else return \"seqw %0\"; +}") + +(define_insn "" + [(set (match_operand:QI 0 "general_operand" "=g<") + (eq (cc0) (const_int 0)))] + "" + "* +{ if (cc_prev_status.flags & CC_Z_IN_F) + return \"sfcb %0\"; + else if (cc_prev_status.flags & CC_Z_IN_NOT_F) + return \"sfsb %0\"; + else return \"seqb %0\"; +}") + +(define_insn "sne" + [(set (match_operand:SI 0 "general_operand" "=g<") + (ne (cc0) (const_int 0)))] + "" + "* +{ if (cc_prev_status.flags & CC_Z_IN_F) + return \"sfsd %0\"; + else if (cc_prev_status.flags & CC_Z_IN_NOT_F) + return \"sfcd %0\"; + else return \"sned %0\"; +}") + +(define_insn "" + [(set (match_operand:HI 0 "general_operand" "=g<") + (ne (cc0) (const_int 0)))] + "" + "* +{ if (cc_prev_status.flags & CC_Z_IN_F) + return \"sfsw %0\"; + else if (cc_prev_status.flags & CC_Z_IN_NOT_F) + return \"sfcw %0\"; + else return \"snew %0\"; +}") + +(define_insn "" + [(set (match_operand:QI 0 "general_operand" "=g<") + (ne (cc0) (const_int 0)))] + "" + "* +{ if (cc_prev_status.flags & CC_Z_IN_F) + return \"sfsb %0\"; + else if (cc_prev_status.flags & CC_Z_IN_NOT_F) + return \"sfcb %0\"; + else return \"sneb %0\"; +}") + +(define_insn "sgt" + [(set (match_operand:SI 0 "general_operand" "=g<") + (gt (cc0) (const_int 0)))] + "" + "sgtd %0") + +(define_insn "" + [(set (match_operand:HI 0 "general_operand" "=g<") + (gt (cc0) (const_int 0)))] + "" + "sgtw %0") + +(define_insn "" + [(set (match_operand:QI 0 "general_operand" "=g<") + (gt (cc0) (const_int 0)))] + "" + "sgtb %0") + +(define_insn "sgtu" + [(set (match_operand:SI 0 "general_operand" "=g<") + (gtu (cc0) (const_int 0)))] + "" + "shid %0") + +(define_insn "" + [(set (match_operand:HI 0 "general_operand" "=g<") + (gtu (cc0) (const_int 0)))] + "" + "shiw %0") + +(define_insn "" + [(set (match_operand:QI 0 "general_operand" "=g<") + (gtu (cc0) (const_int 0)))] + "" + "shib %0") + +(define_insn "slt" + [(set (match_operand:SI 0 "general_operand" "=g<") + (lt (cc0) (const_int 0)))] + "" + "sltd %0") + +(define_insn "" + [(set (match_operand:HI 0 "general_operand" "=g<") + (lt (cc0) (const_int 0)))] + "" + "sltw %0") + +(define_insn "" + [(set (match_operand:QI 0 "general_operand" "=g<") + (lt (cc0) (const_int 0)))] + "" + "sltb %0") + +(define_insn "sltu" + [(set (match_operand:SI 0 "general_operand" "=g<") + (ltu (cc0) (const_int 0)))] + "" + "slod %0") + +(define_insn "" + [(set (match_operand:HI 0 "general_operand" "=g<") + (ltu (cc0) (const_int 0)))] + "" + "slow %0") + +(define_insn "" + [(set (match_operand:QI 0 "general_operand" "=g<") + (ltu (cc0) (const_int 0)))] + "" + "slob %0") + +(define_insn "sge" + [(set (match_operand:SI 0 "general_operand" "=g<") + (ge (cc0) (const_int 0)))] + "" + "sged %0") + +(define_insn "" + [(set (match_operand:HI 0 "general_operand" "=g<") + (ge (cc0) (const_int 0)))] + "" + "sgew %0") + +(define_insn "" + [(set (match_operand:QI 0 "general_operand" "=g<") + (ge (cc0) (const_int 0)))] + "" + "sgeb %0") + +(define_insn "sgeu" + [(set (match_operand:SI 0 "general_operand" "=g<") + (geu (cc0) (const_int 0)))] + "" + "shsd %0") + +(define_insn "" + [(set (match_operand:HI 0 "general_operand" "=g<") + (geu (cc0) (const_int 0)))] + "" + "shsw %0") + +(define_insn "" + [(set (match_operand:QI 0 "general_operand" "=g<") + (geu (cc0) (const_int 0)))] + "" + "shsb %0") + +(define_insn "sle" + [(set (match_operand:SI 0 "general_operand" "=g<") + (le (cc0) (const_int 0)))] + "" + "sled %0") + +(define_insn "" + [(set (match_operand:HI 0 "general_operand" "=g<") + (le (cc0) (const_int 0)))] + "" + "slew %0") + +(define_insn "" + [(set (match_operand:QI 0 "general_operand" "=g<") + (le (cc0) (const_int 0)))] + "" + "sleb %0") + +(define_insn "sleu" + [(set (match_operand:SI 0 "general_operand" "=g<") + (leu (cc0) (const_int 0)))] + "" + "slsd %0") + +(define_insn "" + [(set (match_operand:HI 0 "general_operand" "=g<") + (leu (cc0) (const_int 0)))] + "" + "slsw %0") + +(define_insn "" + [(set (match_operand:QI 0 "general_operand" "=g<") + (leu (cc0) (const_int 0)))] + "" + "slsb %0") + +;;- Local variables: +;;- mode:emacs-lisp +;;- comment-start: ";;- " +;;- eval: (set-syntax-table (copy-sequence (syntax-table))) +;;- eval: (modify-syntax-entry ?[ "(]") +;;- eval: (modify-syntax-entry ?] ")[") +;;- eval: (modify-syntax-entry ?{ "(}") +;;- eval: (modify-syntax-entry ?} "){") +;;- End: diff --git a/gcc-1.40/config/out-alliant.c b/gcc-1.40/config/out-alliant.c new file mode 100644 index 0000000..63727ad --- /dev/null +++ b/gcc-1.40/config/out-alliant.c @@ -0,0 +1,291 @@ +/* Subroutines for insn-output.c for Alliant FX computers. + Copyright (C) 1989 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 1, 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. */ + + +/* Some output-actions in alliant.md need these. */ +#include +extern FILE *asm_out_file; + +/* Index into this array by (register number >> 3) to find the + smallest class which contains that register. */ +enum reg_class regno_reg_class[] + = { DATA_REGS, ADDR_REGS, FP_REGS }; + +static rtx find_addr_reg (); + +char * +output_btst (operands, countop, dataop, insn, signpos) + rtx *operands; + rtx countop, dataop; + rtx insn; + int signpos; +{ + operands[0] = countop; + operands[1] = dataop; + + if (GET_CODE (countop) == CONST_INT) + { + register int count = INTVAL (countop); + /* If COUNT is bigger than size of storage unit in use, + advance to the containing unit of same size. */ + if (count > signpos) + { + int offset = (count & ~signpos) / 8; + count = count & signpos; + operands[1] = dataop = adj_offsettable_operand (dataop, offset); + } + if (count == signpos) + cc_status.flags = CC_NOT_POSITIVE | CC_Z_IN_NOT_N; + else + cc_status.flags = CC_NOT_NEGATIVE | CC_Z_IN_NOT_N; + + if (count == 31 + && next_insns_test_no_inequality (insn)) + return "tst%.l %1"; + if (count == 15 + && next_insns_test_no_inequality (insn)) + return "tst%.w %1"; + if (count == 7 + && next_insns_test_no_inequality (insn)) + return "tst%.b %1"; + + cc_status.flags = CC_NOT_NEGATIVE; + } + return "btst %0,%1"; +} + +/* Return the best assembler insn template + for moving operands[1] into operands[0] as a fullword. */ + +static char * +singlemove_string (operands) + rtx *operands; +{ + if (operands[1] != const0_rtx) + return "mov%.l %1,%0"; + if (! ADDRESS_REG_P (operands[0])) + return "clr%.l %0"; + return "sub%.l %0,%0"; +} + +/* Output assembler code to perform a doubleword move insn + with operands OPERANDS. */ + +char * +output_move_double (operands) + rtx *operands; +{ + enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1; + rtx latehalf[2]; + rtx addreg0 = 0, addreg1 = 0; + + /* First classify both operands. */ + + if (REG_P (operands[0])) + optype0 = REGOP; + else if (offsettable_memref_p (operands[0])) + optype0 = OFFSOP; + else if (GET_CODE (XEXP (operands[0], 0)) == POST_INC) + optype0 = POPOP; + else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC) + optype0 = PUSHOP; + else if (GET_CODE (operands[0]) == MEM) + optype0 = MEMOP; + else + optype0 = RNDOP; + + if (REG_P (operands[1])) + optype1 = REGOP; + else if (CONSTANT_P (operands[1]) + || GET_CODE (operands[1]) == CONST_DOUBLE) + optype1 = CNSTOP; + else if (offsettable_memref_p (operands[1])) + optype1 = OFFSOP; + else if (GET_CODE (XEXP (operands[1], 0)) == POST_INC) + optype1 = POPOP; + else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC) + optype1 = PUSHOP; + else if (GET_CODE (operands[1]) == 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) + abort (); + + /* If one operand is decrementing and one is incrementing + decrement the former register explicitly + and change that operand into ordinary indexing. */ + + if (optype0 == PUSHOP && optype1 == POPOP) + { + operands[0] = XEXP (XEXP (operands[0], 0), 0); + output_asm_insn ("subq%.l %#8,%0", operands); + operands[0] = gen_rtx (MEM, DImode, operands[0]); + optype0 = OFFSOP; + } + if (optype0 == POPOP && optype1 == PUSHOP) + { + operands[1] = XEXP (XEXP (operands[1], 0), 0); + output_asm_insn ("subq%.l %#8,%1", operands); + operands[1] = gen_rtx (MEM, DImode, operands[1]); + optype1 = OFFSOP; + } + + /* 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 (operands[0], 0)); + + if (optype1 == MEMOP) + addreg1 = find_addr_reg (XEXP (operands[1], 0)); + + /* Ok, we can do one word at a time. + Normally we do the low-numbered word first, + but if either operand is autodecrementing then we + do the high-numbered word first. + + In either case, set up in LATEHALF the operands to use + for the high-numbered 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 (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); + else if (optype1 == OFFSOP) + latehalf[1] = adj_offsettable_operand (operands[1], 4); + else if (optype1 == CNSTOP) + { + if (CONSTANT_P (operands[1])) + latehalf[1] = const0_rtx; + else if (GET_CODE (operands[1]) == CONST_DOUBLE) + { + latehalf[1] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_HIGH (operands[1])); + operands[1] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_LOW (operands[1])); + } + } + else + latehalf[1] = operands[1]; + + /* If insn is effectively movd N(sp),-(sp) then we will do the + high word first. We should use the adjusted operand 1 (which is N+4(sp)) + for the low word as well, to compensate for the first decrement of sp. */ + if (optype0 == PUSHOP + && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM + && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1])) + operands[1] = latehalf[1]; + + /* If one or both operands autodecrementing, + do the two words, high-numbered first. */ + + /* Likewise, the first move would clobber the source of the second one, + do them in the other order. This happens only for registers; + such overlap can't happen in memory unless the user explicitly + sets it up, and that is an undefined circumstance. */ + + if (optype0 == PUSHOP || optype1 == PUSHOP + || (optype0 == REGOP && optype1 == REGOP + && REGNO (operands[0]) == REGNO (latehalf[1]))) + { + /* Make any unoffsettable addresses point at high-numbered word. */ + if (addreg0) + output_asm_insn ("addql %#4,%0", &addreg0); + if (addreg1) + output_asm_insn ("addql %#4,%0", &addreg1); + + /* Do that word. */ + output_asm_insn (singlemove_string (latehalf), latehalf); + + /* Undo the adds we just did. */ + if (addreg0) + output_asm_insn ("subql %#4,%0", &addreg0); + if (addreg1) + output_asm_insn ("subql %#4,%0", &addreg1); + + /* Do low-numbered word. */ + return singlemove_string (operands); + } + + /* Normal case: do the two words, low-numbered first. */ + + output_asm_insn (singlemove_string (operands), operands); + + /* Make any unoffsettable addresses point at high-numbered word. */ + if (addreg0) + output_asm_insn ("addql %#4,%0", &addreg0); + if (addreg1) + output_asm_insn ("addql %#4,%0", &addreg1); + + /* Do that word. */ + output_asm_insn (singlemove_string (latehalf), latehalf); + + /* Undo the adds we just did. */ + if (addreg0) + output_asm_insn ("subql %#4,%0", &addreg0); + if (addreg1) + output_asm_insn ("subql %#4,%0", &addreg1); + + return ""; +} + +/* 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) + { + if (GET_CODE (XEXP (addr, 0)) == REG) + addr = XEXP (addr, 0); + else if (GET_CODE (XEXP (addr, 1)) == REG) + 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 (); +} + +int +standard_SunFPA_constant_p (x) + rtx x; +{ + return( 0 ); +} + diff --git a/gcc-1.40/config/out-convex.c b/gcc-1.40/config/out-convex.c new file mode 100644 index 0000000..df6fb73 --- /dev/null +++ b/gcc-1.40/config/out-convex.c @@ -0,0 +1,219 @@ +/* Subroutines for insn-output.c for Convex. + Copyright (C) 1989, 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 1, 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. */ + +/* Boolean to keep track of whether the current section is .text or not. + Used by .align handler in tm-convex.h. */ + +int current_section_is_text; + +/* + * set_cmp (left_rtx, right_rtx, [bhwlsd]) + * gen_cmp (label_rtx, cmpop, [tf]) + * + * set_cmp saves the operands of a "cmp" insn, + * along with the type character to be used in the compare instruction. + * + * gen_cmp finds out what comparison is to be performed and + * outputs the necessary instructions, eg, + * "eq.w a1,a2 ! jbra.t L5" + * for (cmpsi a1 a2) (beq L5) + */ + +static rtx xop0, xop1; +static char typech, regch; + +char * +set_cmp (op0, op1, typechr) + rtx op0, op1; + char typechr; +{ + xop0 = op0; + xop1 = op1; + typech = typechr; + if (GET_CODE (op0) == REG) + regch = REGNO_OK_FOR_BASE_P (REGNO (op0)) ? 'a' : 's'; + else if (GET_CODE (op1) == REG) + regch = REGNO_OK_FOR_BASE_P (REGNO (op1)) ? 'a' : 's'; + else abort (); + return ""; +} + +char * +gen_cmp (label, cmpop, tf) + rtx label; + char *cmpop; + char tf; +{ + char buf[80]; + char revop[4]; + rtx ops[3]; + + ops[2] = label; + + /* constant must be first; swap operands if necessary + if lt, le, ltu, leu are swapped, change to le, lt, leu, ltu + and reverse the sense of the jump */ + + if (CONSTANT_P (xop1) || GET_CODE (xop1) == CONST_DOUBLE) + { + ops[0] = xop1; + ops[1] = xop0; + if (cmpop[0] == 'l') + { + bcopy (cmpop, revop, 4); + revop[1] ^= 'e' ^ 't'; + tf ^= 't' ^ 'f'; + cmpop = revop; + } + } + else + { + ops[0] = xop0; + ops[1] = xop1; + } + + sprintf (buf, "%s.%c %%0,%%1\n\tjbr%c.%c %%l2", cmpop, typech, regch, tf); + output_asm_insn (buf, ops); + return ""; +} + +/* + * Routines to look at CONST_DOUBLEs without sinful knowledge of + * what the inside of u.d looks like + * + * const_double_high_int -- high word of machine double or long long + * const_double_low_int -- low word + * const_double_float_int -- the word of a machine float + */ + +static double frexp (); +static void float_extract (); + +int +const_double_high_int (x) + rtx x; +{ + if (GET_MODE (x) == DImode) + return CONST_DOUBLE_HIGH (x); + else + { + int sign, expd, expf; + unsigned fracdh, fracdl, fracf; + float_extract (x, &sign, &expd, &fracdh, &fracdl, &expf, &fracf); + + if (fracdh == 0) + return 0; + if (expd < -01777 || expd > 01777) + return 1 << 31; + return sign << 31 | (expd + 02000) << 20 | fracdh - (1 << 20); + } +} + +int +const_double_low_int (x) + rtx x; +{ + if (GET_MODE (x) == DImode) + return CONST_DOUBLE_LOW (x); + else + { + int sign, expd, expf; + unsigned fracdh, fracdl, fracf; + float_extract (x, &sign, &expd, &fracdh, &fracdl, &expf, &fracf); + return fracdl; + } +} + +int +const_double_float_int (x) + rtx x; +{ + int sign, expd, expf; + unsigned fracdh, fracdl, fracf; + float_extract (x, &sign, &expd, &fracdh, &fracdl, &expf, &fracf); + + if (fracf == 0) + return 0; + if (expf < -0177 || expf > 0177) + return 1 << 31; + return sign << 31 | (expf + 0200) << 20 | fracf - (1 << 23); +} + +#define T21 ((double) (1 << 21)) +#define T24 ((double) (1 << 24)) +#define T53 ((double) (1 << 27) * (double) (1 << 26)) + +static void +float_extract (x, sign, expd, fracdh, fracdl, expf, fracf) + rtx x; + int *sign, *expd, *expf; + unsigned *fracdh, *fracdl, *fracf; +{ + int exp, round; + double d, r; + union real_extract u; + + bcopy (&CONST_DOUBLE_LOW (x), &u, sizeof u); + + /* Get sign and exponent. */ + + if (*sign = u.d < 0) + u.d = -u.d; + d = frexp (u.d, &exp); + + /* Get 21 fraction bits for high word and 32 for low word. */ + + for (round = 0; ; round = 1) + { + r = frexp (round ? d + 1.0 / T53 : d, expd); + *expd += exp; + *fracdh = r * T21; + *fracdl = (r - *fracdh / T21) * T53; + if (round || ((r - *fracdh / T21) - *fracdl / T53) < 0.5 * T53) + break; + } + + /* Get 24 bits for float fraction. */ + + for (round = 0; ; round = 1) + { + r = frexp (round ? d + 1.0 / T24 : d, expf); + *expf += exp; + *fracf = r * T24; + if (round || (r - *fracf / T24) < 0.5 * T24) + break; + } +} + +static double +frexp (d, exp) + double d; + int *exp; +{ + int e = 0; + + if (d > 0) + { + while (d < 0.5) d *= 2.0, e--; + while (d >= 1.0) d /= 2.0, e++; + } + + *exp = e; + return d; +} diff --git a/gcc-1.40/config/out-i386.c b/gcc-1.40/config/out-i386.c new file mode 100644 index 0000000..958d09f --- /dev/null +++ b/gcc-1.40/config/out-i386.c @@ -0,0 +1,1418 @@ +/* Subroutines for insn-output.c for Intel 80386. + Copyright (C) 1988 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 1, 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. */ + +#ifndef FILE +#include +#endif + +#define FP_TOP (gen_rtx(REG, DFmode, FIRST_FLOAT_REG)) + +#define AT_SP(mode) (gen_rtx (MEM, (mode), stack_pointer_rtx)) +#define AT_BP(mode) (gen_rtx (MEM, (mode), frame_pointer_rtx)) + +#define RET return "" + +/* #define RETCOM(X) fprintf (asm_out_file, "%sX fp_pop_level=%d\n", \ + COMMENT_BEGIN, fp_pop_level); RET */ +#define RETCOM(X) return "" + +#define POP_ONE_FP \ + { /* fp_pop_level--; */ \ + fprintf (asm_out_file, "\tfstp %sst (0)\n", RP); } + +extern FILE *asm_out_file; +static char *singlemove_string (); +static void output_movf (); +static void replace_float_constant (); +static int mentions_fp_top (); +static int call_top_dead_p (); +static int fp_top_dead_p1 (); +static rtx via_memory (); +static void output_asm_insn_double_reg_op (); + +/* All output functions must increment or decrement this to indicate + the net number of pops or pushes which they perform. Note that it won't + necessarily balance with the optimize running, since we might have + two different calls with the same pop shared by cross jumping. + However on optimize the reg dead heuristic seems to work. */ + +int fp_pop_level = 0; + +static char *hi_reg_name[] = HI_REGISTER_NAMES; +static char *qi_reg_name[] = QI_REGISTER_NAMES; + +/* for fabs, fch, .. where the argument operand[1] must first be moved to + constraints "=fm" "0" */ + +#define FP_CALL1(op) \ + { if (FP_REG_P (operands[0])) \ + return op; \ + output_movf (FP_TOP, operands[1]); \ + output_asm_insn (op, operands); \ + /* fp_pop_level--; */ \ + return "fstp%z0 %0"; } + +/* handle case of call where op0/op1 is "=mf" and opn is "mrf" + eg. fadd */ +#define FP_CALL(op, rev, n) \ + return fp_call_internal (op, rev, n, operands, insn); + +static char * +fp_call_internal (op, rev, n, operands, insn) + char *op; + char *rev; + int n; + rtx *operands; + rtx insn; +{ + if (!FP_REG_P (operands[0])) + { + /* Here destination is in memory + and source is in the fp stack. */ + output_movf (FP_TOP, operands[0]); + output_asm_insn_double_reg_op (op, rev, insn); + return "fstp%z0 %0"; + } + + if (FP_REG_P (operands[n])) + { + rtx temp = operands[1]; + char *tem1 = op; + operands[1] = operands[n]; + op = rev; + operands[n] = temp; + rev = tem1; + } + + if (REG_P (operands[n])) + { + rtx xops[2]; + via_memory (operands[n]); + operands[n] = AT_SP (GET_MODE (operands[n])); + xops[0] = stack_pointer_rtx; + xops[1] = gen_rtx (CONST_INT, VOIDmode, + GET_MODE_SIZE (GET_MODE (operands[n]))); + output_asm_insn (op, operands + n); + output_asm_insn (AS2 (add%L0,%1,%0), xops); + } + else + output_asm_insn (op, operands + n); + + if (FP_REG_P (operands[0])) + { + /* It turns out not to work to use top_dead_p because + the death notes are not accurate enough. + But this ought to work, because the only thing that can + live across basic blocks is reg 8, and these insns + never involve reg 8 directly. */ + if (fp_top_dead_p1 (insn)) + POP_ONE_FP; + } + + RET; +} + +/* Output assembler code to perform insn OP + with two stack operands, and output on the stack. + + REV is the assembler insn that does the same thing but + effectively interchanges the meanings of the two arguments. + + Somewhat counterintuitively, the "first" operand was pushed last. + + The output replaces either the top-of-stack or both of the arguments, + depending on whether the other argument is wanted after this insn. */ + +static void +output_asm_insn_double_reg_op (op, rev, insn) + char *op; + char *rev; + rtx insn; +{ + fputc ('\t', asm_out_file); + if (top_dead_p (insn)) + { + /* Here we want the "reversed" insn, fsubr or fdivr. + But there is an assembler bug in all 80386 assemblers + which exchanges the meanings of fsubr and fsub, and of fdivr and fdiv! + So use the "unreversed" opcode (which will assemble into + the "reversed" insn). */ + rev = op; + + while (*rev && *rev != '%') + fputc (*rev++, asm_out_file); + /* fp_pop_level--; */ + + fprintf (asm_out_file, AS2 (p,%sst,%sst(1)), RP, RP); + } + else + { + while (*op && *op != '%') + fputc (*op++, asm_out_file); + fprintf (asm_out_file,AS2 ( ,%sst(1),%sst), RP, RP); + } + putc ('\n', asm_out_file); +} + +/* Moves X to memory location 8 below stack pointer + and returns an RTX for that memory location. + X should be a register, in DFmode or SFmode. */ + +static rtx +via_memory (x) + rtx x; +{ + if (!REG_P (x)) + abort (); + if (GET_MODE (x) == DFmode) + { + rtx xops[1]; + xops[0] = gen_rtx (REG, SImode, REGNO (x) + 1); + output_asm_insn ("push%L0 %0", xops); + } + output_asm_insn ("push%L0 %0", &x); +} + +/* Output an insn to copy the SFmode value in fp0 to OPERAND + without clobbering fp0. */ + +void +fp_store_sf (target) + rtx target; +{ + if (REG_P (target)) + { + rtx xoperands[3]; + xoperands[0] = stack_pointer_rtx; + xoperands[1] = AT_SP (Pmode); + xoperands[2] = gen_rtx (CONST_INT, VOIDmode, -4); + output_asm_insn (AS2 (add%L0,%2,%0), xoperands); + output_asm_insn ("fst%S0 %1", xoperands); + output_asm_insn ("pop%L0 %0", &target); + } + else if (GET_CODE (target) == MEM) + output_asm_insn ("fst%S0 %0", &target); +} + +/* Output an insn to pop an SF value from fp0 into TARGET. + This destroys the value of fp0. */ + +void +fp_pop_sf (target) + rtx target; +{ + if (REG_P (target)) + { + rtx xoperands[3]; + xoperands[0] = stack_pointer_rtx; + xoperands[1] = AT_SP (Pmode); + xoperands[2] = gen_rtx (CONST_INT, VOIDmode, -4); + output_asm_insn (AS2 (add%L0,%2,%0), xoperands); + output_asm_insn ("fstp%S0 %1", xoperands); + output_asm_insn ("pop%L0 %0", &target); + /* fp_pop_level--; */ + } + else if (GET_CODE (target) == MEM) + { + /* fp_pop_level--; */ + output_asm_insn ("fstp%S0 %0", &target); + } + else abort (); +} + +/* Copy the top of the fpu stack into TARGET, without popping. */ + +void +fp_store_df (target) + rtx target; +{ + if (REG_P (target)) + { + rtx xoperands[4]; + xoperands[0] = stack_pointer_rtx; + xoperands[1] = gen_rtx (REG, SImode, REGNO (target) + 1); + xoperands[2] = AT_SP (Pmode); + xoperands[3] = gen_rtx (CONST_INT, VOIDmode, -8); + output_asm_insn (AS2 (add%L0,%3,%0), xoperands); + output_asm_insn ("fst%Q0 %2", xoperands); + output_asm_insn ("pop%L0 %0", &target); + output_asm_insn ("pop%L0 %1", xoperands); + } + else if (GET_CODE (target) == MEM) + output_asm_insn ("fst%Q0 %0", &target); +} + +/* Copy the top of the fpu stack into TARGET, with popping. */ + +void +fp_pop_df (target) + rtx target; +{ + if (REG_P (target)) + { + rtx xoperands[4]; + xoperands[0] = stack_pointer_rtx; + xoperands[1] = gen_rtx (REG, SImode, REGNO (target) + 1); + xoperands[2] = AT_SP (Pmode); + xoperands[3] = gen_rtx (CONST_INT, VOIDmode, -8); + output_asm_insn (AS2 (add%L0,%3,%0), xoperands); + /* fp_pop_level--; */ + output_asm_insn ("fstp%Q0 %2", xoperands); + output_asm_insn ("pop%L0 %0", &target); + output_asm_insn ("pop%L0 %1", xoperands); + } + else if (GET_CODE (target) == MEM) + { + /* fp_pop_level--; */ + output_asm_insn ("fstp%z0 %0", &target); + } +} + +#if 0 +/* Pop the fp stack, convert value to integer and store in TARGET. + TARGET may be memory or register, and may have QI, HI or SImode. */ + +void +fp_pop_int (target) + rtx target; +{ + if (REG_P (target) || GET_MODE (target) != SImode) + { + rtx xxops[2]; + xxops[0] = stack_pointer_rtx; + xxops[1] = gen_rtx (CONST_INT, VOIDmode, 4); + output_asm_insn (AS2 (sub%L0,%1,%0), xxops); + xxops[0] = AT_SP (Pmode); + /* fp_pop_level--; */ + output_asm_insn ("fistp%L0 %0", xxops); + output_asm_insn ("pop%L0 %0", &target); + } + else if (GET_CODE (target) == MEM) + { + /* fp_pop_level--; */ + output_asm_insn ("fistp%L0 %0", &target); + } + else abort (); +} +#endif + +/* Push the SFmode value X onto the fpu stack. */ + +void +fp_push_sf (x) + rtx x; +{ + /* fp_pop_level++; */ + if (REG_P (x)) + { + rtx xoperands[2]; + rtx xfops[3]; + output_asm_insn ("push%L0 %0", &x); + xfops[0] = AT_SP (Pmode); + xfops[2] = gen_rtx (CONST_INT, VOIDmode, 4); + xfops[1] = stack_pointer_rtx; + output_asm_insn ("fld%S0 %0 \n\tadd%L0 %2,%1", xfops); + } + else + output_asm_insn ("fld%S0 %0", &x); +} + +/* Push the DFmode value X onto the fpu stack. */ + +void +fp_push_df (x) + rtx x; +{ + /* fp_pop_level++; */ + + if (REG_P (x)) + { + rtx xoperands[2]; + rtx xfops[3]; + xoperands[0] = x; + xoperands[1] = gen_rtx (REG, SImode, REGNO (x) + 1); + output_asm_insn ("push%L0 %1", xoperands); + output_asm_insn ("push%L0 %0", xoperands); + xfops[0] = AT_SP (Pmode); + xfops[2] = gen_rtx (CONST_INT, VOIDmode, 8); + xfops[1] = stack_pointer_rtx; + output_asm_insn ("fld%Q0 %0 \n\tadd%L0 %2,%1", xfops); + } + else if (GET_CODE (x) == MEM) + output_asm_insn ("fld%Q0 %0", &x); +} + +static char *output_move_const_single (); + +static char * +singlemove_string (operands) + rtx *operands; +{ + rtx x; + if (GET_CODE (operands[0]) == MEM + && GET_CODE (x = XEXP (operands[0], 0)) == PRE_DEC) + { + if (XEXP (x, 0) != stack_pointer_rtx) + abort (); + return "push%L0 %1"; + } + else if (GET_CODE (operands[1]) == CONST_DOUBLE) + { + 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])) + return AS2 (mov%L0,%1,%0); + else + { + output_asm_insn ("push%L0 %1", operands); + return "pop%L0 %0"; + } +} + +/* 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) + { + if (GET_CODE (XEXP (addr, 0)) == REG) + addr = XEXP (addr, 0); + else if (GET_CODE (XEXP (addr, 1)) == REG) + 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 an insn to add the constant N to the register X. */ + +static void +asm_add (n, x) + int n; + rtx x; +{ + rtx xops[2]; + xops[1] = x; + if (n < 0) + { + xops[0] = gen_rtx (CONST_INT, VOIDmode, -n); + output_asm_insn (AS2 (sub%L0,%0,%1), xops); + } + else if (n > 0) + { + xops[0] = gen_rtx (CONST_INT, VOIDmode, n); + output_asm_insn (AS2 (add%L0,%0,%1), xops); + } +} + +/* Output assembler code to perform a doubleword move insn + with operands OPERANDS. */ + +char * +output_move_double (operands) + rtx *operands; +{ + enum {REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1; + rtx latehalf[2]; + rtx addreg0 = 0, addreg1 = 0; + + /* First classify both operands. */ + + if (REG_P (operands[0])) + optype0 = REGOP; + else if (offsettable_memref_p (operands[0])) + optype0 = OFFSOP; + else if (GET_CODE (XEXP (operands[0], 0)) == POST_INC) + optype0 = POPOP; + else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC) + optype0 = PUSHOP; + else if (GET_CODE (operands[0]) == MEM) + optype0 = MEMOP; + else + optype0 = RNDOP; + + if (REG_P (operands[1])) + optype1 = REGOP; + else if (CONSTANT_P (operands[1]) + || GET_CODE (operands[1]) == CONST_DOUBLE) + optype1 = CNSTOP; + else if (offsettable_memref_p (operands[1])) + optype1 = OFFSOP; + else if (GET_CODE (XEXP (operands[1], 0)) == POST_INC) + optype1 = POPOP; + else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC) + optype1 = PUSHOP; + else if (GET_CODE (operands[1]) == 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) + abort (); + + /* If one operand is decrementing and one is incrementing + decrement the former register explicitly + and change that operand into ordinary indexing. */ + + if (optype0 == PUSHOP && optype1 == POPOP) + { + operands[0] = XEXP (XEXP (operands[0], 0), 0); + asm_add (-8, operands[0]); + operands[0] = gen_rtx (MEM, DImode, operands[0]); + optype0 = OFFSOP; + } + if (optype0 == POPOP && optype1 == PUSHOP) + { + operands[1] = XEXP (XEXP (operands[1], 0), 0); + asm_add (-8, operands[1]); + operands[1] = gen_rtx (MEM, DImode, operands[1]); + optype1 = OFFSOP; + } + + /* 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 (operands[0], 0)); + + if (optype1 == MEMOP) + addreg1 = find_addr_reg (XEXP (operands[1], 0)); + + /* Ok, we can do one word at a time. + Normally we do the low-numbered word first, + but if either operand is autodecrementing then we + do the high-numbered word first. + + In either case, set up in LATEHALF the operands to use + for the high-numbered 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 (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); + else if (optype1 == OFFSOP) + latehalf[1] = adj_offsettable_operand (operands[1], 4); + else if (optype1 == CNSTOP) + { + if (CONSTANT_P (operands[1])) + latehalf[1] = const0_rtx; + else if (GET_CODE (operands[1]) == CONST_DOUBLE) + { + latehalf[1] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_HIGH (operands[1])); + operands[1] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_LOW (operands[1])); + } + } + else + latehalf[1] = operands[1]; + + /* If insn is effectively movd N (sp),-(sp) then we will do the + high word first. We should use the adjusted operand 1 (which is N+4 (sp)) + for the low word as well, to compensate for the first decrement of sp. */ + if (optype0 == PUSHOP + && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM + && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1])) + operands[1] = latehalf[1]; + + /* If one or both operands autodecrementing, + do the two words, high-numbered first. */ + + /* Likewise, the first move would clobber the source of the second one, + do them in the other order. This happens only for registers; + such overlap can't happen in memory unless the user explicitly + sets it up, and that is an undefined circumstance. */ + + if (optype0 == PUSHOP || optype1 == PUSHOP + || (optype0 == REGOP && optype1 == REGOP + && REGNO (operands[0]) == REGNO (latehalf[1]))) + { + /* Make any unoffsettable addresses point at high-numbered word. */ + if (addreg0) + asm_add (4, addreg0); + if (addreg1) + asm_add (4, addreg1); + + /* Do that word. */ + output_asm_insn (singlemove_string (latehalf), latehalf); + + /* Undo the adds we just did. */ + if (addreg0) + asm_add (-4, addreg0); + if (addreg1) + asm_add (-4, addreg1); + + /* Do low-numbered word. */ + return singlemove_string (operands); + } + + /* Normal case: do the two words, low-numbered first. */ + + output_asm_insn (singlemove_string (operands), operands); + + /* Make any unoffsettable addresses point at high-numbered word. */ + if (addreg0) + asm_add (4, addreg0); + if (addreg1) + asm_add (4, addreg1); + + /* Do that word. */ + output_asm_insn (singlemove_string (latehalf), latehalf); + + /* Undo the adds we just did. */ + if (addreg0) + asm_add (-4, addreg0); + if (addreg1) + asm_add (-4, addreg1); + + return ""; +} + +int +standard_80387_constant_p (x) + rtx x; +{ + union { double d; int i[2];} u; + register double d; + u.i[0] = XINT (x, 0); + u.i[1] = XINT (x, 1); + d = u.d; + + if (d == 0) + return 1; + if (d == 1) + return 2; + /* Note that on the 80387, other constants, such as pi, + are much slower to load as standard constants + than to load from doubles in memory! */ + + return 0; +} + +static char * +output_move_const_double (operands) + rtx *operands; +{ + if (FP_REG_P (operands[0])) + { + int conval = standard_80387_constant_p (operands[1]); + + /* fp_pop_level++; */ + if (conval == 1) + return "fldz"; + if (conval == 2) + return "fld1"; + /* fp_pop_level--; */ + } + + output_move_double (operands); +} + + +static char * +output_move_const_single (operands) + rtx *operands; +{ + if (FP_REG_P (operands[0])) + { + int conval = standard_80387_constant_p (operands[1]); + + /* fp_pop_level++; */ + if (conval == 1) + return "fldz"; + if (conval == 2) + return "fld1"; + /* fp_pop_level--; */ + } + if (GET_CODE (operands[1]) == CONST_DOUBLE) + { + union { int i[2]; double d;} u1; + union { int i; float f;} u2; + u1.i[0] = CONST_DOUBLE_LOW (operands[1]); + u1.i[1] = CONST_DOUBLE_HIGH (operands[1]); + u2.f = u1.d; + operands[1] = gen_rtx (CONST_INT, VOIDmode, u2.i); + } + return singlemove_string (operands); +} + +/* Output an insn to move an SF value from FROM to TO. + The kinds of operands are not restricted + except that they may not both be in memory. */ + +void +output_movsf (to, from) + rtx from, to; +{ + rtx xops[2]; + xops[0] = to; + xops[1] = from; + if (FP_REG_P (from) || FP_REG_P (to)) + { + from = xops[1]; + } + + if (FP_REG_P (from)) + { +#if 0 + { + if (REGNO (from) != REGNO (to)) + { + output_asm_insn ("fld%S0 %1 \n\tfstp%S0 %0", xops); + } + } + else +#endif + + if (! FP_REG_P (to)) + fp_pop_sf (to); + } + else if (FP_REG_P (to)) + fp_push_sf (from); + else + output_asm_insn (singlemove_string (xops), xops); +} + +/* Output an insn to move a DF value from FROM to TO. + The kinds of operands are not restricted + except that they may not both be in memory. */ + +void +output_movdf (to, from) + rtx from, to; +{ + rtx xops[2]; + xops[0] = to; + xops[1] = from; + if (FP_REG_P (from) || FP_REG_P (to)) + { + from = xops[1]; + to = xops[0]; + } + if (FP_REG_P (from)) + { +#if 0 + { + if (REGNO (from) != REGNO (to)) + abort (); +/* output_asm_insn ("fld%Q0 %1 \n\t fstp%Q0 %0", xops);*/ + } + else + { +#endif + if (! FP_REG_P (to)) + fp_pop_df (to); + } + else if (FP_REG_P (to)) + fp_push_df (from); + else + output_asm_insn (output_move_double (xops), xops); +} + +/* does move of FROM to TO where the mode is the minimum of the +two */ + +static void +output_movf (to, from) + rtx to, from; +{ + if (GET_MODE (from) == SFmode || GET_MODE (to) == SFmode) + output_movsf (to, from); + else + output_movdf (to, from); +} + +/* Return the best assembler insn template + for moving operands[1] into operands[0] as a fullword. */ + +void +function_prologue (file, size) + FILE *file; + int size; +{ + register int regno; + int nregs, limit; + rtx xops[4]; + extern int frame_pointer_needed; + + /* fp_pop_level = 0; */ + xops[0] = stack_pointer_rtx; + xops[1] = frame_pointer_rtx; + xops[2] = gen_rtx (CONST_INT, VOIDmode, size); + if (frame_pointer_needed) + { + output_asm_insn ("push%L0 %1", xops); + output_asm_insn (AS2 (mov%L0,%0,%1), xops); + if (size) + output_asm_insn (AS2 (sub%L0,%2,%0), xops); + } + + /* Note If use enter it is NOT reversed args. + This one is not reversed from intel!! + I think enter is slower. Also sdb doesn't like it. + But if you want it the code is: + { + xops[3] = const0_rtx; + output_asm_insn ("enter %2,%3", xops); + } + */ + nregs = 0; + 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]) + { + fprintf (file, "\tpush%s %se%s\n", L_SIZE, RP, hi_reg_name[regno]); + } +} + +void +function_epilogue (file, size) + FILE *file; + int size; +{ + register int regno; + register int nregs, limit; + int assure_sp_pos; + int return_struct_adjust; + extern int frame_pointer_needed; + extern int current_function_pops_args; + extern int current_function_args_size; + extern int flag_pcc_struct_return; + + limit = (frame_pointer_needed ? FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM); + nregs = 0; + + return_struct_adjust = + (current_function_returns_struct +#ifdef STRUCT_RETURN_CALLER_POP + && !flag_pcc_struct_return +#endif + ? 4 : 0); + + for (regno = (limit -1); regno >= 0; regno--) + if (regs_ever_live[regno] && ! call_used_regs[regno]) + nregs++; + + /* sp is often unreliable so we must go off the frame pointer, + */ + + if (nregs && frame_pointer_needed) + { + rtx xops[2]; + xops[0] = adj_offsettable_operand (AT_BP (Pmode), + -size -(nregs*(UNITS_PER_WORD))); + xops[1] = stack_pointer_rtx; + output_asm_insn (AS2 (lea%L0,%0,%1), xops); + } + for (regno = 0; regno < limit; regno++) + { + if (regs_ever_live[regno] && ! call_used_regs[regno]) + { + fprintf (file, "\tpop%s ", L_SIZE); + fprintf (file, "%se%s\n", RP, hi_reg_name[regno]); + } + } + + if (frame_pointer_needed) + fprintf (file, "\tleave\n"); + if (current_function_pops_args && current_function_args_size) + fprintf (file, "\tret %s%d\n", IP, + (current_function_args_size + return_struct_adjust)); + else if (return_struct_adjust) + fprintf (file, "\tret %s%d\n", IP, return_struct_adjust); + else + fprintf (file, "\tret\n"); +} + +int +hard_regno_mode_ok (regno, mode) + int regno; + enum machine_mode mode; +{ + return + (regno < 2 ? 1 + /* Used to reject floating modes here */ + : regno < 4 ? 1 + : regno >= 8 ? mode == DFmode || mode == SFmode + : mode != QImode); +} + +/* Print the name of a register based on its machine mode and number. + If CODE is 'w', pretend the mode is HImode. + If CODE is 'b', pretend the mode is QImode. + If CODE is 'k', pretend the mode is SImode. */ + +#define PRINT_REG(X, CODE, FILE) \ + do { fprintf (FILE, "%s", RP); \ + switch ((CODE == 'w' ? 2 \ + : CODE == 'b' ? 1 \ + : CODE == 'k' ? 4 \ + : GET_MODE_SIZE (GET_MODE (X)))) \ + { \ + case 4: \ + case 8: \ + if (!FP_REG_P (X)) fputs ("e", FILE); \ + case 2: \ + fputs (hi_reg_name[REGNO (X)], FILE); \ + break; \ + case 1: \ + fputs (qi_reg_name[REGNO (X)], FILE); \ + break; \ + } \ + } while (0) + +/* Meaning of CODE: + f -- float insn (print a CONST_DOUBLE as a float rather than in hex). + L,W,B,Q,S -- print the opcode suffix for specified size of operand. + 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. +*/ + +void +print_operand (file, x, code) + FILE *file; + rtx x; + int code; +{ + if (code) + { + switch (code) + { + case '*': + if (USE_STAR) + putc ('*', file); + return; + + case 'L': + PUT_OP_SIZE (code, 'l', file); + return; + + case 'W': + PUT_OP_SIZE (code, 'w', file); + return; + + case 'B': + PUT_OP_SIZE (code, 'b', file); + return; + + case 'Q': + PUT_OP_SIZE (code, 'l', file); + return; + + case 'S': + PUT_OP_SIZE (code, 's', file); + return; + + case 'R': + fprintf (file, "%s", RP); + return; + + case 'z': + /* this is the size of op from size of operand */ + switch (GET_MODE_SIZE (GET_MODE (x))) + { + case 2: + PUT_OP_SIZE ('W', 'w', file); + return; + case 4: + if (GET_MODE (x) == SFmode) + { + PUT_OP_SIZE ('S', 's', file); + return; + } + else + PUT_OP_SIZE ('L', 'l', file); + return; + case 8: + if (!FP_REG_P (x)) PUT_OP_SIZE ('Q', 'l', file); + return; + case 1: + PUT_OP_SIZE ('B', 'b', file); + return; + } + } + } + if (GET_CODE (x) == REG) + { + PRINT_REG (x, code, file); + } + else if (GET_CODE (x) == MEM) + { + PRINT_PTR (x, file); + if (CONSTANT_ADDRESS_P (XEXP (x, 0))) + output_addr_const (file, XEXP (x, 0)); + else + output_address (XEXP (x, 0)); + } + else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == SFmode) + { + union { double d; int i[2]; } u; + union { float f; int i; } u1; + u.i[0] = CONST_DOUBLE_LOW (x); + u.i[1] = CONST_DOUBLE_HIGH (x); + u1.f = u.d; + if (code == 'f') + fprintf (file, "%.22e", u1.f); + else + { + PRINT_IMMED_PREFIX (file); + fprintf (file, "0x%x", u1.i); + } + } + else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == DFmode) + { + union { double d; int i[2]; } u; + u.i[0] = CONST_DOUBLE_LOW (x); + u.i[1] = CONST_DOUBLE_HIGH (x); + fprintf (file, "%.22e", u.d); + } + else + { + if (code != 'c') + { + if (GET_CODE (x) == CONST_INT) + PRINT_IMMED_PREFIX (file); + else if (GET_CODE (x) == CONST || GET_CODE (x) == SYMBOL_REF + || GET_CODE (x) == LABEL_REF) + PRINT_OFFSET_PREFIX (file); + } + output_addr_const (file, x); + } +} + +/* Print a memory operand whose address is ADDR. */ + +void +print_operand_address (file, addr) + FILE *file; + register rtx addr; +{ + register rtx reg1, reg2, breg, ireg; + rtx offset; + + switch (GET_CODE (addr)) + { + case REG: + ADDR_BEG (file); + fprintf (file, "%se", RP); + fputs (hi_reg_name[REGNO (addr)], file); + ADDR_END (file); + break; + + case PLUS: + reg1 = 0; + reg2 = 0; + ireg = 0; + breg = 0; + offset = 0; + if (CONSTANT_ADDRESS_P (XEXP (addr, 0))) + { + offset = XEXP (addr, 0); + addr = XEXP (addr, 1); + } + else if (CONSTANT_ADDRESS_P (XEXP (addr, 1))) + { + offset = XEXP (addr, 1); + addr = XEXP (addr, 0); + } + if (GET_CODE (addr) != PLUS) ; + else if (GET_CODE (XEXP (addr, 0)) == MULT) + { + reg1 = XEXP (addr, 0); + addr = XEXP (addr, 1); + } + else if (GET_CODE (XEXP (addr, 1)) == MULT) + { + reg1 = XEXP (addr, 1); + addr = XEXP (addr, 0); + } + else if (GET_CODE (XEXP (addr, 0)) == REG) + { + reg1 = XEXP (addr, 0); + addr = XEXP (addr, 1); + } + else if (GET_CODE (XEXP (addr, 1)) == REG) + { + 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; + addr = 0; + } + if (offset != 0) + { + if (addr != 0) abort (); + addr = offset; + } + if ((reg1 && GET_CODE (reg1) == MULT) + || (reg2 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg2)))) + { + breg = reg2; + ireg = reg1; + } + else if (reg1 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg1))) + { + breg = reg1; + ireg = reg2; + } + + if (ireg != 0 || breg != 0) + { + int scale = 1; + + if (addr != 0) + { + if (GET_CODE (addr) == LABEL_REF) + output_asm_label (addr); + else + output_addr_const (file, addr); + } + + if (ireg != 0 && GET_CODE (ireg) == MULT) + { + scale = INTVAL (XEXP (ireg, 1)); + ireg = XEXP (ireg, 0); + } + /* output breg+ireg*scale */ + PRINT_B_I_S (breg, ireg, scale, file); + break; + } + + case MULT: + { + int scale; + if (GET_CODE (XEXP (addr, 0)) == CONST_INT) + { + scale = INTVAL (XEXP (addr, 0)); + ireg = XEXP (addr, 1); + } + else + { + scale = INTVAL (XEXP (addr, 1)); + ireg = XEXP (addr, 0); + } + output_addr_const (file, const0_rtx); + PRINT_B_I_S ((rtx) 0, ireg, scale, file); + } + break; + + default: + if (GET_CODE (addr) == CONST_INT + && INTVAL (addr) < 0x8000 + && INTVAL (addr) >= -0x8000) + fprintf (file, "%d", INTVAL (addr)); + else + output_addr_const (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, LSHIFT, + ASHIFTRT, and LSHIFTRT instructions set the condition codes usefully. + Also, we assume that jumps and moves don't affect the condition codes. + All else, clobbers the condition codes, by assumption. + + We assume that ALL add, minus, etc. instructions effect the condition + codes. This MUST be consistent with i386.md. */ + +notice_update_cc (exp) + rtx exp; +{ + if (GET_CODE (exp) == SET) + { + /* 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)) + { + 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))) + { + if (cc_status.value1 && GET_CODE (cc_status.value1) == MEM) + cc_status.value1 = 0; + if (cc_status.value2 && GET_CODE (cc_status.value2) == MEM) + 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) + { + CC_STATUS_INIT; + 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 LSHIFT: + /* 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) + { + CC_STATUS_INIT; + break; + } + /* We assume that the CONST_INT is non-zero (this rtx would + have been deleted if it were zero. */ + + case PLUS: case MINUS: case NEG: + case AND: case IOR: case XOR: + cc_status.flags = CC_NO_OVERFLOW; + cc_status.value1 = SET_SRC (exp); + cc_status.value2 = SET_DEST (exp); + break; + + default: + CC_STATUS_INIT; + } + else + { + CC_STATUS_INIT; + } + } + else if (GET_CODE (exp) == PARALLEL + && GET_CODE (XVECEXP (exp, 0, 0)) == SET) + { + if (SET_DEST (XVECEXP (exp, 0, 0)) == pc_rtx) + return; + if (SET_DEST (XVECEXP (exp, 0, 0)) == cc0_rtx) + { + CC_STATUS_INIT; + cc_status.value1 = SET_SRC (XVECEXP (exp, 0, 0)); + return; + } + CC_STATUS_INIT; + } + else + { + CC_STATUS_INIT; + } +} + +/* Nonzero if the top of the fpu stack dies in this insn. */ + +int +top_dead_p (insn) + rtx insn; +{ + extern int optimize; + if (optimize) + return (find_regno_note (insn, REG_DEAD, FIRST_FLOAT_REG) + || find_regno_note (insn, REG_DEAD, FIRST_FLOAT_REG + 1)); + + if (GET_CODE (insn) == CALL_INSN) + return call_top_dead_p (insn); + + return fp_top_dead_p1 (insn); +} + +/* Following is used after a call_value insn + if obey_regdecls there will not be the REG_DEAD notes + to go by (there won't be any cross jumping to worry about + either), and we depend on seeing if the FP_TOP is used + in the next two insn's. Otherwise we depend on the + REG_DEAD notes. + */ + +static int +call_top_dead_p (insn) + rtx insn; +{ + int i; + for (i = 0; i < 3; i++) + { + insn = NEXT_INSN (insn); + if (insn == 0) + return 1; + if (GET_CODE (insn) == NOTE || GET_CODE (insn) == CODE_LABEL) + continue; + if (GET_CODE (insn) == BARRIER) + abort (); + if (GET_CODE (PATTERN (insn)) == SET + && SET_DEST (PATTERN (insn)) != stack_pointer_rtx) + return (!(mentions_fp_top (SET_SRC (PATTERN (insn))))); + if (GET_CODE (PATTERN (insn)) == CALL) + return 1; + if (GET_CODE (PATTERN (insn)) == USE) + return (! FP_REG_P (XEXP (PATTERN (insn), 0))); + } + return 1; +} + +/* Return 1 if current val of fpu top-of-stack appears unused + in rest of this basic block and also through a jump insn. + This is called from top_dead_p and from fp_call_internal. */ + +static int +fp_top_dead_p1 (insn) + rtx insn; +{ + extern int optimize; + + int past_jump = 0; + + for (insn = NEXT_INSN (insn); insn; insn = NEXT_INSN (insn)) + { + switch (GET_CODE (insn)) + { + case CALL_INSN: + /* Function calls clobber this value, so it's dead. */ + return 1; + + case JUMP_INSN: + /* Follow one jump in case of cross-jumping, + which could insert such a jump into one basic block. */ + if (! optimize) + /* Can't use JUMP_LABEL, but there's no cross-jumping either. */ + return 1; + if (JUMP_LABEL (insn) == 0) + return 1; + /* Don't scan past a jump and another jump. */ + if (past_jump) + return 1; + past_jump = 1; + insn = JUMP_LABEL (insn); + case CODE_LABEL: + if (! optimize) + return 1; + break; + + case INSN: + if (GET_CODE (PATTERN (insn)) == SET) + { + if ((mentions_fp_top (SET_SRC (PATTERN (insn))))) + return 0; + else if (mentions_fp_top (SET_DEST (PATTERN (insn)))) + return 1; + } + else if (mentions_fp_top (PATTERN (insn))) + return 0; + break; + } + } + return 1; +} + +/* Return 1 if X involves an FPU register. */ + +static int +mentions_fp_top (x) + rtx x; +{ + register RTX_CODE code; + + code = GET_CODE (x); + switch (code) + { + case LABEL_REF: + case SYMBOL_REF: + case CONST_INT: + case CONST: + case CC0: + case PC: + case CLOBBER: + case MEM: + return 0; + + case REG: + return FP_REGNO_P (REGNO (x)); + } + + /* 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') + { + if (mentions_fp_top (XEXP (x, i))) + return 1; + } + if (fmt[i] == 'E') + { + register int j; + for (j = 0; j < XVECLEN (x, i); j++) + if (mentions_fp_top (XVECEXP (x, i, j))) + return 1; + } + } + } + return 0; +} + +/* Some asm-dependent functions. */ + +#ifdef MASM +#include "masm386.c" +#endif diff --git a/gcc-1.40/config/out-i860.c b/gcc-1.40/config/out-i860.c new file mode 100644 index 0000000..f531810 --- /dev/null +++ b/gcc-1.40/config/out-i860.c @@ -0,0 +1,1507 @@ +/* Subroutines for insn-output.c for Intel 860 + Copyright (C) 1989 Free Software Foundation, Inc. + Derived from out-sparc.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 1, 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. */ + + +/* Global variables for machine-dependend things. */ + +/* This should go away if we pass floats to regs via + the stack instead of the frame, and if we learn how + to renumber all the registers when we don't do a save (hard!). */ +extern int frame_pointer_needed; + +static rtx find_addr_reg (); + +/* Return non-zero only if OP is a register of mode MODE, + or const0_rtx. */ +int +reg_or_0_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + return (op == const0_rtx || register_operand (op, mode) + || op == CONST0_RTX (mode)); +} + +/* Return non-zero if this pattern, can be evaluated safely, even if it + was not asked for. */ +int +safe_insn_src_p (op, mode) + rtx op; + enum machine_mode mode; +{ + /* Just experimenting. */ + + /* No floating point src is safe if it contains an arithmetic + operation, since that operation may trap. */ + switch (GET_CODE (op)) + { + case CONST_INT: + case LABEL_REF: + case SYMBOL_REF: + case CONST: + return 1; + + case REG: + return 1; + + case MEM: + return CONSTANT_ADDRESS_P (XEXP (op, 0)); + + /* We never need to negate or complement constants. */ + case NEG: + return (mode != SFmode && mode != DFmode); + case NOT: + case ZERO_EXTEND: + return 1; + + case EQ: + case NE: + case LT: + case GT: + case LE: + case GE: + case LTU: + case GTU: + case LEU: + case GEU: + case MINUS: + case PLUS: + return (mode != SFmode && mode != DFmode); + case AND: + case IOR: + case XOR: + case LSHIFT: + case ASHIFT: + case ASHIFTRT: + case LSHIFTRT: + if ((GET_CODE (XEXP (op, 0)) == CONST_INT && ! SMALL_INT (XEXP (op, 0))) + || (GET_CODE (XEXP (op, 1)) == CONST_INT && ! SMALL_INT (XEXP (op, 1)))) + return 0; + return 1; + + default: + return 0; + } +} + +/* Return 1 if REG is clobbered in IN. + Return 2 if REG is used in IN. + Return 3 if REG is both used and clobbered in IN. + Return 0 if neither. */ + +static int +reg_clobbered_p (reg, in) + rtx reg; + rtx in; +{ + register enum rtx_code code; + + if (in == 0) + return 0; + + code = GET_CODE (in); + + if (code == SET || code == CLOBBER) + { + rtx dest = SET_DEST (in); + int set = 0; + int used = 0; + + while (GET_CODE (dest) == STRICT_LOW_PART + || GET_CODE (dest) == SUBREG + || GET_CODE (dest) == SIGN_EXTRACT + || GET_CODE (dest) == ZERO_EXTRACT) + dest = XEXP (dest, 0); + + if (dest == reg) + set = 1; + else if (GET_CODE (dest) == REG + && refers_to_regno_p (REGNO (reg), + REGNO (reg) + HARD_REGNO_NREGS (reg, GET_MODE (reg)), + SET_DEST (in), 0)) + { + set = 1; + /* Anything that sets just part of the register + is considered using as well as setting it. + But note that a straight SUBREG of a single-word value + clobbers the entire value. */ + if (dest != SET_DEST (in) + && ! (GET_CODE (SET_DEST (in)) == SUBREG + || UNITS_PER_WORD >= GET_MODE_SIZE (GET_MODE (dest)))) + used = 1; + } + + if (code == SET) + { + if (set) + used = refers_to_regno_p (REGNO (reg), + REGNO (reg) + HARD_REGNO_NREGS (reg, GET_MODE (reg)), + SET_SRC (in), 0); + else + used = refers_to_regno_p (REGNO (reg), + REGNO (reg) + HARD_REGNO_NREGS (reg, GET_MODE (reg)), + in, 0); + } + + return set + used * 2; + } + + if (refers_to_regno_p (REGNO (reg), + REGNO (reg) + HARD_REGNO_NREGS (reg, GET_MODE (reg)), + in, 0)) + return 2; + return 0; +} + +/* Return non-zero if OP can be written to without screwing up + GCC's model of what's going on. It is assumed that this operand + appears in the dest position of a SET insn in a conditional + branch's delay slot. AFTER is the label to start looking from. */ +int +operand_clobbered_before_used_after (op, after) + rtx op; + rtx after; +{ + extern char call_used_regs[]; + + /* Just experimenting. */ + if (GET_CODE (op) == CC0) + return 1; + if (GET_CODE (op) == REG) + { + rtx insn; + + if (op == stack_pointer_rtx) + return 0; + + /* Scan forward from the label, to see if the value of OP + is clobbered before the first use. */ + + for (insn = NEXT_INSN (after); insn; insn = NEXT_INSN (insn)) + { + if (GET_CODE (insn) == NOTE) + continue; + if (GET_CODE (insn) == INSN + || GET_CODE (insn) == JUMP_INSN + || GET_CODE (insn) == CALL_INSN) + { + switch (reg_clobbered_p (op, PATTERN (insn))) + { + default: + return 0; + case 1: + return 1; + case 0: + break; + } + } + /* If we reach another label without clobbering OP, + then we cannot safely write it here. */ + else if (GET_CODE (insn) == CODE_LABEL) + return 0; + if (GET_CODE (insn) == JUMP_INSN) + { + if (condjump_p (insn)) + return 0; + /* This is a jump insn which has already + been mangled. We can't tell what it does. */ + if (GET_CODE (PATTERN (insn)) == PARALLEL) + return 0; + if (! JUMP_LABEL (insn)) + return 0; + /* Keep following jumps. */ + insn = JUMP_LABEL (insn); + } + } + return 1; + } + + /* In both of these cases, the first insn executed + for this op will be a orh whatever%h,r0,r31, + which is tolerable. */ + if (GET_CODE (op) == MEM) + return (CONSTANT_ADDRESS_P (XEXP (op, 0))); + + return 0; +} + +/* Return non-zero if this pattern, as a source to a "SET", + is known to yield an instruction of unit size. */ +int +single_insn_src_p (op, mode) + rtx op; + enum machine_mode mode; +{ + switch (GET_CODE (op)) + { + case CONST_INT: + /* This is not always a single insn src, technically, + but output_delayed_branch knows how to deal with it. */ + return 1; + + case SYMBOL_REF: + case CONST: + /* This is not a single insn src, technically, + but output_delayed_branch knows how to deal with it. */ + return 1; + + case REG: + return 1; + + case MEM: + return 1; + + /* We never need to negate or complement constants. */ + case NEG: + return (mode != DFmode); + case NOT: + case ZERO_EXTEND: + return 1; + + case PLUS: + case MINUS: + /* Detect cases that require multiple instructions. */ + if (CONSTANT_P (XEXP (op, 1)) + && !(GET_CODE (XEXP (op, 1)) == CONST_INT + && SMALL_INT (XEXP (op, 1)))) + return 0; + case EQ: + case NE: + case LT: + case GT: + case LE: + case GE: + case LTU: + case GTU: + case LEU: + case GEU: + /* Not doing floating point, since they probably + take longer than the branch slot they might fill. */ + return (mode != SFmode && mode != DFmode); + + case AND: + if (GET_CODE (XEXP (op, 1)) == NOT) + { + rtx arg = XEXP (XEXP (op, 1), 0); + if (CONSTANT_P (arg) + && !(GET_CODE (arg) == CONST_INT + && (SMALL_INT (arg) + || INTVAL (arg) & 0xffff == 0))) + return 0; + } + case IOR: + case XOR: + /* Both small and round numbers take one instruction; + others take two. */ + if (CONSTANT_P (XEXP (op, 1)) + && !(GET_CODE (XEXP (op, 1)) == CONST_INT + && (SMALL_INT (XEXP (op, 1)) + || INTVAL (XEXP (op, 1)) & 0xffff == 0))) + return 0; + + case LSHIFT: + case ASHIFT: + case ASHIFTRT: + case LSHIFTRT: + return 1; + + case SUBREG: + if (SUBREG_WORD (op) != 0) + return 0; + return single_insn_src_p (SUBREG_REG (op), mode); + + /* Not doing floating point, since they probably + take longer than the branch slot they might fill. */ + case FLOAT_EXTEND: + case FLOAT_TRUNCATE: + case FLOAT: + case FIX: + case UNSIGNED_FLOAT: + case UNSIGNED_FIX: + return 0; + + default: + return 0; + } +} + +/* Nonzero only if this *really* is a single insn operand. */ +int +strict_single_insn_op_p (op, mode) + rtx op; + enum machine_mode mode; +{ + if (mode == VOIDmode) + mode = GET_MODE (op); + + switch (GET_CODE (op)) + { + case CC0: + return 1; + + case CONST_INT: + if (SMALL_INT (op)) + return 1; + /* We can put this set insn into delay slot, because this is one + insn; 'sethi'. */ + if ((INTVAL (op) & 0x3ff) == 0) + return 1; + return 0; + + case SYMBOL_REF: + return 0; + + case REG: +#if 0 + /* This loses when moving an freg to a general reg. */ + return HARD_REGNO_NREGS (REGNO (op), mode) == 1; +#endif + return (mode != DFmode && mode != DImode); + + case MEM: + if (! CONSTANT_ADDRESS_P (XEXP (op, 0))) + return (mode != DFmode && mode != DImode); + return 0; + + /* We never need to negate or complement constants. */ + case NEG: + return (mode != DFmode); + case NOT: + case ZERO_EXTEND: + return 1; + + case PLUS: + case MINUS: + /* Detect cases that require multiple instructions. */ + if (CONSTANT_P (XEXP (op, 1)) + && !(GET_CODE (XEXP (op, 1)) == CONST_INT + && SMALL_INT (XEXP (op, 1)))) + return 0; + case EQ: + case NE: + case LT: + case GT: + case LE: + case GE: + case LTU: + case GTU: + case LEU: + case GEU: + return 1; + + case AND: + if (GET_CODE (XEXP (op, 1)) == NOT) + { + rtx arg = XEXP (XEXP (op, 1), 0); + if (CONSTANT_P (arg) + && !(GET_CODE (arg) == CONST_INT + && (SMALL_INT (arg) + || INTVAL (arg) & 0xffff == 0))) + return 0; + } + case IOR: + case XOR: + /* Both small and round numbers take one instruction; + others take two. */ + if (CONSTANT_P (XEXP (op, 1)) + && !(GET_CODE (XEXP (op, 1)) == CONST_INT + && (SMALL_INT (XEXP (op, 1)) + || INTVAL (XEXP (op, 1)) & 0xffff == 0))) + return 0; + case LSHIFT: + case ASHIFT: + case ASHIFTRT: + case LSHIFTRT: + return 1; + + case SUBREG: + if (SUBREG_WORD (op) != 0) + return 0; + return strict_single_insn_op_p (SUBREG_REG (op), mode); + + case SIGN_EXTEND: + if (GET_CODE (XEXP (op, 0)) == MEM + && ! CONSTANT_ADDRESS_P (XEXP (XEXP (op, 0), 0))) + return 1; + return 0; + + /* Not doing floating point, since they probably + take longer than the branch slot they might fill. */ + case FLOAT_EXTEND: + case FLOAT_TRUNCATE: + case FLOAT: + case FIX: + case UNSIGNED_FLOAT: + case UNSIGNED_FIX: + return 0; + + default: + return 0; + } +} + +/* Return truth value of whether OP is a relational operator. */ +int +relop (op, mode) + rtx op; + enum machine_mode mode; +{ + switch (GET_CODE (op)) + { + case EQ: + case NE: + case GT: + case GE: + case LT: + case LE: + case GTU: + case GEU: + case LTU: + case LEU: + return 1; + } + return 0; +} + +/* Return truth value of whether OP can be used as an operands in a three + address add/subtract insn (such as add %o1,7,%l2) of mode MODE. */ + +int +arith_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + return (register_operand (op, mode) + || (GET_CODE (op) == CONST_INT && SMALL_INT (op))); +} + +/* Return 1 if OP is a valid first operand for a logical insn of mode MODE. */ + +int +logic_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + return (register_operand (op, mode) + || (GET_CODE (op) == CONST_INT && LOGIC_INT (op))); +} + +/* Return 1 if OP is a valid first operand for either a logical insn + or an add insn of mode MODE. */ + +int +compare_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + return (register_operand (op, mode) + || (GET_CODE (op) == CONST_INT && SMALL_INT (op) && LOGIC_INT (op))); +} + +/* Return truth value of whether OP can be used as an operand + of a bte insn. */ + +int +bte_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + return (register_operand (op, mode) + || (GET_CODE (op) == CONST_INT + && (unsigned) INTVAL (op) < 0x20)); +} + +/* Return 1 if OP is an indexed memory reference of mode MODE. */ + +int +indexed_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + return (GET_CODE (op) == MEM && GET_MODE (op) == mode + && GET_CODE (XEXP (op, 0)) == PLUS + && GET_MODE (XEXP (op, 0)) == SImode + && register_operand (XEXP (XEXP (op, 0), 0), SImode) + && register_operand (XEXP (XEXP (op, 0), 1), SImode)); +} + +/* Return 1 if OP is a suitable source operand for a load insn + with mode MODE. */ + +int +load_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + return (memory_operand (op, mode) || indexed_operand (op, mode)); +} + +/* Return truth value of whether OP is a integer which fits the + range constraining immediate operands in add/subtract insns. */ + +int +small_int (op, mode) + rtx op; + enum machine_mode mode; +{ + return (GET_CODE (op) == CONST_INT && SMALL_INT (op)); +} + +/* Return truth value of whether OP is a integer which fits the + range constraining immediate operands in logic insns. */ + +int +logic_int (op, mode) + rtx op; + enum machine_mode mode; +{ + return (GET_CODE (op) == CONST_INT && LOGIC_INT (op)); +} + +/* Return the best assembler insn template + for moving operands[1] into operands[0] as a fullword. */ + +static char * +singlemove_string (operands) + rtx *operands; +{ + if (GET_CODE (operands[0]) == MEM) + { + if (GET_CODE (operands[1]) != MEM) + if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) + { + if (! ((cc_prev_status.flags & CC_KNOW_HI_R31) + && (cc_prev_status.flags & CC_HI_R31_ADJ) + && cc_prev_status.mdep == XEXP (operands[0], 0))) + output_asm_insn ("orh ha%%%m0,r0,r31", operands); + cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ; + cc_status.mdep = XEXP (operands[0], 0); + return "st.l %r1,l%%%m0(r31)"; + } + else + return "st.l %r1,%0"; + else + abort (); +#if 0 + { + rtx xoperands[2]; + + cc_status.flags &= ~CC_F0_IS_0; + xoperands[0] = gen_rtx (REG, SFmode, 32); + xoperands[1] = operands[1]; + output_asm_insn (singlemove_string (xoperands), xoperands); + xoperands[1] = xoperands[0]; + xoperands[0] = operands[0]; + output_asm_insn (singlemove_string (xoperands), xoperands); + return ""; + } +#endif + } + if (GET_CODE (operands[1]) == MEM) + { + if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) + { + if (! ((cc_prev_status.flags & CC_KNOW_HI_R31) + && (cc_prev_status.flags & CC_HI_R31_ADJ) + && cc_prev_status.mdep == XEXP (operands[1], 0))) + output_asm_insn ("orh ha%%%m1,r0,r31", operands); + cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ; + cc_status.mdep = XEXP (operands[1], 0); + return "ld.l l%%%m1(r31),%0"; + } + return "ld.l %1,%0"; + } + return "mov %1,%0"; +} + +/* Output assembler code to perform a doubleword move insn + with operands OPERANDS. */ + +char * +output_move_double (operands) + rtx *operands; +{ + enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1; + rtx latehalf[2]; + rtx addreg0 = 0, addreg1 = 0; + + /* First classify both operands. */ + + if (REG_P (operands[0])) + optype0 = REGOP; + else if (offsettable_memref_p (operands[0])) + optype0 = OFFSOP; + else if (GET_CODE (operands[0]) == MEM) + optype0 = MEMOP; + else + optype0 = RNDOP; + + if (REG_P (operands[1])) + optype1 = REGOP; + else if (CONSTANT_P (operands[1]) + || GET_CODE (operands[1]) == CONST_DOUBLE) + optype1 = CNSTOP; + else if (offsettable_memref_p (operands[1])) + optype1 = OFFSOP; + else if (GET_CODE (operands[1]) == 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) + 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 (operands[0], 0)); + + if (optype1 == MEMOP) + addreg1 = find_addr_reg (XEXP (operands[1], 0)); + +/* ??? Perhaps in some cases move double words + if there is a spare pair of floating regs. */ + + /* Ok, we can do one word at a time. + Normally we do the low-numbered word first, + but if either operand is autodecrementing then we + do the high-numbered word first. + + In either case, set up in LATEHALF the operands to use + for the high-numbered 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 (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); + else if (optype1 == OFFSOP) + latehalf[1] = adj_offsettable_operand (operands[1], 4); + else if (optype1 == CNSTOP) + { + if (CONSTANT_P (operands[1])) + latehalf[1] = const0_rtx; + else if (GET_CODE (operands[1]) == CONST_DOUBLE) + { + latehalf[1] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_HIGH (operands[1])); + operands[1] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_LOW (operands[1])); + } + } + else + latehalf[1] = operands[1]; + + /* If the first move would clobber the source of the second one, + do them in the other order. + + RMS says "This happens only for registers; + such overlap can't happen in memory unless the user explicitly + sets it up, and that is an undefined circumstance." + + but it happens on the sparc when loading parameter registers, + so I am going to define that circumstance, and make it work + as expected. */ + + if (optype0 == REGOP && optype1 == REGOP + && REGNO (operands[0]) == REGNO (latehalf[1])) + { + /* Make any unoffsettable addresses point at high-numbered word. */ + if (addreg0) + output_asm_insn ("adds 0x4,%0,%0", &addreg0); + if (addreg1) + output_asm_insn ("adds 0x4,%0,%0", &addreg1); + + /* Do that word. */ + output_asm_insn (singlemove_string (latehalf), latehalf); + + /* Undo the adds we just did. */ + if (addreg0) + output_asm_insn ("adds -0x4,%0,%0", &addreg0); + if (addreg1) + output_asm_insn ("adds -0x4,%0,%0", &addreg1); + + /* Do low-numbered word. */ + return singlemove_string (operands); + } + else if (optype0 == REGOP && optype1 != REGOP + && reg_overlap_mentioned_p (operands[0], operands[1])) + { + /* Do the late half first. */ + output_asm_insn (singlemove_string (latehalf), latehalf); + /* Then clobber. */ + return singlemove_string (operands); + } + + /* Normal case: do the two words, low-numbered first. */ + + output_asm_insn (singlemove_string (operands), operands); + + /* Make any unoffsettable addresses point at high-numbered word. */ + if (addreg0) + output_asm_insn ("adds 0x4,%0,%0", &addreg0); + if (addreg1) + output_asm_insn ("adds 0x4,%0,%0", &addreg1); + + /* Do that word. */ + output_asm_insn (singlemove_string (latehalf), latehalf); + + /* Undo the adds we just did. */ + if (addreg0) + output_asm_insn ("adds -0x4,%0,%0", &addreg0); + if (addreg1) + output_asm_insn ("adds -0x4,%0,%0", &addreg1); + + return ""; +} + +static char * +output_fp_move_double (operands) + rtx *operands; +{ + if (FP_REG_P (operands[0])) + { + if (FP_REG_P (operands[1])) + return "fmov.dd %1,%0"; + if (GET_CODE (operands[1]) == REG) + { + output_asm_insn ("ixfr %1,%0", operands); + operands[0] = gen_rtx (REG, VOIDmode, REGNO (operands[0]) + 1); + operands[1] = gen_rtx (REG, VOIDmode, REGNO (operands[1]) + 1); + return "ixfr %1,%0"; + } + if (operands[1] == dconst0_rtx) + return "fmov.dd f0,%0"; + if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) + { + if (! ((cc_prev_status.flags & CC_KNOW_HI_R31) + && (cc_prev_status.flags & CC_HI_R31_ADJ) + && cc_prev_status.mdep == XEXP (operands[1], 0))) + output_asm_insn ("orh ha%%%m1,r0,r31", operands); + cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ; + cc_status.mdep = XEXP (operands[1], 0); + return "fld.d l%%%m1(r31),%0"; + } + return "fld.d %1,%0"; + } + else if (FP_REG_P (operands[1])) + { + if (GET_CODE (operands[0]) == REG) + { + output_asm_insn ("fxfr %1,%0", operands); + operands[0] = gen_rtx (REG, VOIDmode, REGNO (operands[0]) + 1); + operands[1] = gen_rtx (REG, VOIDmode, REGNO (operands[1]) + 1); + return "fxfr %1,%0"; + } + if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) + { + if (! ((cc_prev_status.flags & CC_KNOW_HI_R31) + && (cc_prev_status.flags & CC_HI_R31_ADJ) + && cc_prev_status.mdep == XEXP (operands[0], 0))) + output_asm_insn ("orh ha%%%m0,r0,r31", operands); + cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ; + cc_status.mdep = XEXP (operands[0], 0); + return "fst.d %1,l%%%m0(r31)"; + } + return "fst.d %1,%0"; + } + 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) + { + if (GET_CODE (XEXP (addr, 0)) == REG) + addr = XEXP (addr, 0); + else if (GET_CODE (XEXP (addr, 1)) == REG) + 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 (); +} + +/* Return a template for a load instruction with mode MODE and + arguments from the string ARGS. + + This string is in static storage. */ + +static char * +load_opcode (mode, args, reg) + enum machine_mode mode; + char *args; + rtx reg; +{ + static char buf[30]; + char *opcode; + + switch (mode) + { + case QImode: + opcode = "ld.b"; + break; + + case HImode: + opcode = "ld.s"; + break; + + case SImode: + case SFmode: + if (FP_REG_P (reg)) + opcode = "fld.l"; + else + opcode = "ld.l"; + break; + + case DImode: + if (!FP_REG_P (reg)) + abort (); + case DFmode: + opcode = "fld.d"; + break; + + default: + abort (); + } + + sprintf (buf, "%s %s", opcode, args); + return buf; +} + +/* Return a template for a store instruction with mode MODE and + arguments from the string ARGS. + + This string is in static storage. */ + +static char * +store_opcode (mode, args, reg) + enum machine_mode mode; + char *args; + rtx reg; +{ + static char buf[30]; + char *opcode; + + switch (mode) + { + case QImode: + opcode = "st.b"; + break; + + case HImode: + opcode = "st.s"; + break; + + case SImode: + case SFmode: + if (FP_REG_P (reg)) + opcode = "fst.l"; + else + opcode = "st.l"; + break; + + case DImode: + if (!FP_REG_P (reg)) + abort (); + case DFmode: + opcode = "fst.d"; + break; + + default: + abort (); + } + + sprintf (buf, "%s %s", opcode, args); + return buf; +} + +/* Output a store-in-memory whose operands are OPERANDS[0,1]. + OPERANDS[0] is a MEM, and OPERANDS[1] is a reg or zero. + + This function returns a template for an insn. + This is in static storage. + + It may also output some insns directly. + It may alter the values of operands[0] and operands[1]. */ + +char * +output_store (operands) + rtx *operands; +{ + enum machine_mode mode = GET_MODE (operands[0]); + rtx address = XEXP (operands[0], 0); + char *string; + + cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ; + cc_status.mdep = address; + + if (! ((cc_prev_status.flags & CC_KNOW_HI_R31) + && (cc_prev_status.flags & CC_HI_R31_ADJ) + && address == cc_prev_status.mdep)) + { + output_asm_insn ("orh ha%%%m0,r0,r31", operands); + cc_prev_status.mdep = address; + } + + /* Store zero in two parts when appropriate. */ + if (mode == DFmode && operands[1] == dconst0_rtx) + return store_opcode (DFmode, "%r1,l%%%m0(r31)", operands[1]); + + /* Code below isn't smart enough to move a doubleword in two parts, + so use output_move_double to do that in the cases that require it. */ + if ((mode == DImode || mode == DFmode) + && ! FP_REG_P (operands[1])) + return output_move_double (operands); + + return store_opcode (mode, "%r1,l%%%m0(r31)", operands[1]); +} + +/* Output a load-from-memory whose operands are OPERANDS[0,1]. + OPERANDS[0] is a reg, and OPERANDS[1] is a mem. + + This function returns a template for an insn. + This is in static storage. + + It may also output some insns directly. + It may alter the values of operands[0] and operands[1]. */ + +char * +output_load (operands) + rtx *operands; +{ + enum machine_mode mode = GET_MODE (operands[0]); + rtx address = XEXP (operands[1], 0); + + /* We don't bother trying to see if we know %hi(address). + This is because we are doing a load, and if we know the + %hi value, we probably also know that value in memory. */ + cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ; + cc_status.mdep = address; + + if (! ((cc_prev_status.flags & CC_KNOW_HI_R31) + && (cc_prev_status.flags & CC_HI_R31_ADJ) + && address == cc_prev_status.mdep + && cc_prev_status.mdep == cc_status.mdep)) + { + output_asm_insn ("orh ha%%%m1,r0,r31", operands); + cc_prev_status.mdep = address; + } + + /* Code below isn't smart enough to move a doubleword in two parts, + so use output_move_double to do that in the cases that require it. */ + if ((mode == DImode || mode == DFmode) + && ! FP_REG_P (operands[0])) + return output_move_double (operands); + + return load_opcode (mode, "l%%%m1(r31),%0", operands[0]); +} + +/* Load the address specified by OPERANDS[3] into the register + specified by OPERANDS[0]. + + OPERANDS[3] may be the result of a sum, hence it could either be: + + (1) CONST + (2) REG + (2) REG + CONST_INT + (3) REG + REG + CONST_INT + (4) REG + REG (special case of 3). + + Note that (3) is not a legitimate address. + All cases are handled here. */ + +void +output_load_address (operands) + rtx *operands; +{ + rtx base, offset; + + if (CONSTANT_P (operands[3])) + { + output_asm_insn ("mov %3,%0", operands); + return; + } + + if (REG_P (operands[3])) + { + if (REGNO (operands[0]) != REGNO (operands[3])) + output_asm_insn ("mov %3,%0", operands); + return; + } + + if (GET_CODE (operands[3]) != PLUS) + abort (); + + base = XEXP (operands[3], 0); + offset = XEXP (operands[3], 1); + + if (GET_CODE (base) == CONST_INT) + { + rtx tmp = base; + base = offset; + offset = tmp; + } + + if (GET_CODE (offset) != CONST_INT) + { + /* Operand is (PLUS (REG) (REG)). */ + base = operands[3]; + offset = const0_rtx; + } + + if (REG_P (base)) + { + operands[6] = base; + operands[7] = offset; + if (SMALL_INT (offset)) + output_asm_insn ("adds %7,%6,%0", operands); + else + output_asm_insn ("mov %7,%0\n\tadds %0,%6,%0", operands); + } + else if (GET_CODE (base) == PLUS) + { + operands[6] = XEXP (base, 0); + operands[7] = XEXP (base, 1); + operands[8] = offset; + + if (SMALL_INT (offset)) + output_asm_insn ("adds %6,%7,%0\n\tadds %8,%0,%0", operands); + else + output_asm_insn ("mov %8,%0\n\tadds %0,%6,%0\n\tadds %0,%7,%0", operands); + } + else + abort (); +} + +/* Output code to place a size count SIZE in register REG. */ + +static void +output_size_for_block_move (size, reg, align) + rtx size, reg, align; +{ + rtx xoperands[3]; + + xoperands[0] = reg; + xoperands[1] = size; + xoperands[2] = align; + +#if 1 + cc_status.flags &= ~ CC_KNOW_HI_R31; + output_asm_insn ("mov %1,%0", xoperands); +#else + if (GET_CODE (size) == REG) + output_asm_insn ("sub %2,%1,%0", xoperands); + else + { + xoperands[1] + = gen_rtx (CONST_INT, VOIDmode, INTVAL (size) - INTVAL (align)); + cc_status.flags &= ~ CC_KNOW_HI_R31; + output_asm_insn ("mov %1,%0", xoperands); + } +#endif +} + +/* Emit code to perform a block move. + + OPERANDS[0] is the destination. + OPERANDS[1] is the source. + OPERANDS[2] is the size. + OPERANDS[3] is the known safe alignment. + OPERANDS[4..6] are pseudos we can safely clobber as temps. */ + +char * +output_block_move (operands) + rtx *operands; +{ + /* A vector for our computed operands. Note that load_output_address + makes use of (and can clobber) up to the 8th element of this vector. */ + rtx xoperands[10]; + rtx zoperands[10]; + static int movstrsi_label = 0; + int i, j; + rtx temp1 = operands[4]; + rtx alignrtx = operands[3]; + int align = INTVAL (alignrtx); + + xoperands[0] = operands[0]; + xoperands[1] = operands[1]; + xoperands[2] = temp1; + + /* We can't move more than four bytes at a time + because we have only one register to move them through. */ + if (align > 4) + { + align = 4; + alignrtx = gen_rtx (CONST_INT, VOIDmode, 4); + } + + /* Since we clobber untold things, nix the condition codes. */ + CC_STATUS_INIT; + + /* Recognize special cases of block moves. These occur + when GNU C++ is forced to treat something as BLKmode + to keep it in memory, when its mode could be represented + with something smaller. + + We cannot do this for global variables, since we don't know + what pages they don't cross. Sigh. */ + if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) <= 16 + && ! CONSTANT_ADDRESS_P (operands[0]) + && ! CONSTANT_ADDRESS_P (operands[1])) + { + int size = INTVAL (operands[2]); + rtx op0 = xoperands[0]; + rtx op1 = xoperands[1]; + + cc_status.flags &= ~CC_KNOW_HI_R31; + if (align == 1) + { + if (memory_address_p (QImode, plus_constant (op0, size)) + && memory_address_p (QImode, plus_constant (op1, size))) + { + for (i = size-1; i >= 0; i--) + { + xoperands[0] = plus_constant (op0, i); + xoperands[1] = plus_constant (op1, i); + output_asm_insn ("ld.b %a1,r31\n\tst.b r31,%a0", + xoperands); + } + return ""; + } + } + else if (align == 2) + { + if (memory_address_p (HImode, plus_constant (op0, size)) + && memory_address_p (HImode, plus_constant (op1, size))) + { + for (i = (size>>1)-1; i >= 0; i--) + { + xoperands[0] = plus_constant (op0, i * 2); + xoperands[1] = plus_constant (op1, i * 2); + output_asm_insn ("ld.s %a1,r31\n\tst.s r31,%a0", + xoperands); + } + return ""; + } + } + else + { + if (memory_address_p (SImode, plus_constant (op0, size)) + && memory_address_p (SImode, plus_constant (op1, size))) + { + for (i = (size>>2)-1; i >= 0; i--) + { + xoperands[0] = plus_constant (op0, i * 4); + xoperands[1] = plus_constant (op1, i * 4); + output_asm_insn ("ld.l %a1,r31\n\tst.l r31,%a0", + xoperands); + } + return ""; + } + } + } + + /* This is the size of the transfer. + Either use the register which already contains the size, + or use a free register (used by no operands). */ + output_size_for_block_move (operands[2], operands[4], alignrtx); + +#if 0 + /* Also emit code to decrement the size value by ALIGN. */ + zoperands[0] = operands[0]; + zoperands[3] = plus_constant (operands[0], align); + output_load_address (zoperands); +#endif + + /* Generate number for unique label. */ + + xoperands[3] = gen_rtx (CONST_INT, VOIDmode, movstrsi_label++); + + /* Copy the increment (negative) to a register for bla insn. */ + + xoperands[4] = gen_rtx (CONST_INT, VOIDmode, - align); + xoperands[5] = operands[5]; + output_asm_insn ("mov %4,%5", xoperands); + + /* Make available a register which is a temporary. */ + + xoperands[6] = operands[6]; + + /* Now the actual loop. + In xoperands, elements 1 and 0 are the input and output vectors. + Element 2 is the loop index. Element 5 is the increment. */ + + if (align == 1) + { + output_asm_insn ("bla %5,%2,.Lm%3", xoperands); + output_asm_insn ("adds %0,%2,%6\n.Lm%3:", xoperands); + + xoperands[3] = gen_rtx (CONST_INT, VOIDmode, movstrsi_label++); + + output_asm_insn ("adds %1,%2,%1", xoperands); + output_asm_insn ("adds %5,%2,%2\n.Lm%3:", xoperands); + output_asm_insn ("ld.b 0(%1),r31", xoperands); + output_asm_insn ("adds %5,%1,%1", xoperands); + output_asm_insn ("st.b r31,0(%6)", xoperands); + output_asm_insn ("bla %5,%2,.Lm%3", xoperands); + output_asm_insn ("adds %5,%6,%6", xoperands); + } + if (align == 2) + { + output_asm_insn ("bla %5,%2,.Lm%3", xoperands); + output_asm_insn ("adds %0,%2,%6\n.Lm%3:", xoperands); + + xoperands[3] = gen_rtx (CONST_INT, VOIDmode, movstrsi_label++); + + output_asm_insn ("adds %1,%2,%1", xoperands); + output_asm_insn ("adds %5,%2,%2\n.Lm%3:", xoperands); + output_asm_insn ("ld.s 0(%1),r31", xoperands); + output_asm_insn ("adds %5,%1,%1", xoperands); + output_asm_insn ("st.s r31,0(%6)", xoperands); + output_asm_insn ("bla %5,%2,.Lm%3", xoperands); + output_asm_insn ("adds %5,%6,%6", xoperands); + } + if (align == 4) + { + output_asm_insn ("bla %5,%2,.Lm%3", xoperands); + output_asm_insn ("adds %0,%2,%6\n.Lm%3:", xoperands); + + xoperands[3] = gen_rtx (CONST_INT, VOIDmode, movstrsi_label++); + + output_asm_insn ("adds %1,%2,%1", xoperands); + output_asm_insn ("adds %5,%2,%2\n.Lm%3:", xoperands); + output_asm_insn ("ld.l 0(%1),r31", xoperands); + output_asm_insn ("adds %5,%1,%1", xoperands); + output_asm_insn ("st.l r31,0(%6)", xoperands); + output_asm_insn ("bla %5,%2,.Lm%3", xoperands); + output_asm_insn ("adds %5,%6,%6", xoperands); + } + + return ""; +} + +/* Output a delayed branch insn with the delay insn in its + branch slot. The delayed branch insn template is in TEMPLATE, + with operands OPERANDS. The insn in its delay slot is INSN. + + As a special case, since we know that all memory transfers are via + ld/st insns, if we see a (MEM (SYMBOL_REF ...)) we divide the memory + reference around the branch as + + orh ha%x,r0,r31 + b ... + ld/st l%x(r31),... + + As another special case, we handle loading (SYMBOL_REF ...) and + other large constants around branches as well: + + orh h%x,r0,%0 + b ... + or l%x,%0,%1 + + */ + +char * +output_delayed_branch (template, operands, insn) + char *template; + rtx *operands; + rtx insn; +{ + extern rtx recog_operand[]; + rtx src = XVECEXP (PATTERN (insn), 0, 1); + rtx dest = XVECEXP (PATTERN (insn), 0, 0); + + if (GET_CODE (src) == SYMBOL_REF || GET_CODE (src) == CONST + || (GET_CODE (src) == CONST_INT + && !(SMALL_INT (src) || (INTVAL (src) & 0xffff) == 0))) + { + rtx xoperands[2]; + xoperands[0] = dest; + xoperands[1] = src; + + /* Output the `orh' insn. */ + output_asm_insn ("orh h%%%1,r0,%0", xoperands); + + /* Output the branch instruction next. */ + output_asm_insn (template, operands); + + /* Now output the `or' insn. */ + output_asm_insn ("or l%%%1,%0,%0", xoperands); + } + else if ((GET_CODE (src) == MEM + && CONSTANT_ADDRESS_P (XEXP (src, 0))) + || (GET_CODE (dest) == MEM + && CONSTANT_ADDRESS_P (XEXP (dest, 0)))) + { + rtx xoperands[2]; + char *split_template; + xoperands[0] = dest; + xoperands[1] = src; + + /* Output the `orh' insn. */ + if (GET_CODE (src) == MEM) + { + if (! ((cc_prev_status.flags & CC_KNOW_HI_R31) + && (cc_prev_status.flags & CC_HI_R31_ADJ) + && cc_prev_status.mdep == XEXP (operands[1], 0))) + output_asm_insn ("orh ha%%%m1,r0,r31", xoperands); + split_template = load_opcode (GET_MODE (dest), + "l%%%m1(r31),%0", dest); + } + else + { + if (! ((cc_prev_status.flags & CC_KNOW_HI_R31) + && (cc_prev_status.flags & CC_HI_R31_ADJ) + && cc_prev_status.mdep == XEXP (operands[0], 0))) + output_asm_insn ("orh ha%%%m0,r0,r31", xoperands); + split_template = store_opcode (GET_MODE (dest), + "%r1,l%%%m0(r31)", src); + } + + /* Output the branch instruction next. */ + output_asm_insn (template, operands); + + /* Now output the load or store. + No need to do a CC_STATUS_INIT, because we are branching anyway. */ + output_asm_insn (split_template, xoperands); + } + else + { + extern char *insn_template[]; + extern char *(*insn_outfun[])(); + extern int insn_n_operands[]; + extern rtx alter_subreg(); + int insn_code_number; + rtx pat = gen_rtx (SET, VOIDmode, dest, src); + rtx delay_insn = gen_rtx (INSN, VOIDmode, 0, 0, 0, pat, -1, 0, 0); + int i; + + /* Output the branch instruction first. */ + output_asm_insn (template, operands); + + /* Now recognize the insn which we put in its delay slot. + We must do this after outputing the branch insn, + since operands may just be a pointer to `recog_operand'. */ + insn_code_number = recog (pat, delay_insn); + if (insn_code_number == -1) + abort (); + + for (i = 0; i < insn_n_operands[insn_code_number]; i++) + { + if (GET_CODE (recog_operand[i]) == SUBREG) + recog_operand[i] = alter_subreg (recog_operand[i]); + } + + /* Now get the template for what this insn would + have been, without the branch. Its operands are + exactly the same as they would be, so we don't + need to do an insn_extract. */ + template = insn_template[insn_code_number]; + if (template == 0) + template = (*insn_outfun[insn_code_number]) (recog_operand, delay_insn); + output_asm_insn (template, recog_operand); + } + CC_STATUS_INIT; + return ""; +} + +/* Output a newly constructed insn DELAY_INSN. */ +char * +output_delay_insn (delay_insn) + rtx delay_insn; +{ + char *template; + extern rtx recog_operand[]; + extern char call_used_regs[]; + extern char *insn_template[]; + extern int insn_n_operands[]; + extern char *(*insn_outfun[])(); + extern rtx alter_subreg(); + int insn_code_number; + extern int insn_n_operands[]; + int i; + + /* Now recognize the insn which we put in its delay slot. + We must do this after outputing the branch insn, + since operands may just be a pointer to `recog_operand'. */ + insn_code_number = recog_memoized (delay_insn); + if (insn_code_number == -1) + abort (); + + /* Extract the operands of this delay insn. */ + INSN_CODE (delay_insn) = insn_code_number; + insn_extract (delay_insn); + + /* It is possible that this insn has not been properly scaned by final + yet. If this insn's operands don't appear in the peephole's + actual operands, then they won't be fixed up by final, so we + make sure they get fixed up here. -- This is a kludge. */ + for (i = 0; i < insn_n_operands[insn_code_number]; i++) + { + if (GET_CODE (recog_operand[i]) == SUBREG) + recog_operand[i] = alter_subreg (recog_operand[i]); + } + +#ifdef REGISTER_CONSTRAINTS + if (! constrain_operands (insn_code_number)) + abort (); +#endif + + cc_prev_status = cc_status; + + /* Update `cc_status' for this instruction. + The instruction's output routine may change it further. + If the output routine for a jump insn needs to depend + on the cc status, it should look at cc_prev_status. */ + + NOTICE_UPDATE_CC (PATTERN (delay_insn), delay_insn); + + /* Now get the template for what this insn would + have been, without the branch. */ + + template = insn_template[insn_code_number]; + if (template == 0) + template = (*insn_outfun[insn_code_number]) (recog_operand, delay_insn); + output_asm_insn (template, recog_operand); + return ""; +} diff --git a/gcc-1.40/config/out-m68k.c b/gcc-1.40/config/out-m68k.c new file mode 100644 index 0000000..1f05125 --- /dev/null +++ b/gcc-1.40/config/out-m68k.c @@ -0,0 +1,560 @@ +/* Subroutines for insn-output.c for Motorola 68000 family. + Copyright (C) 1987 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 1, 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. */ + + +/* Some output-actions in m68k.md need these. */ +#include +extern FILE *asm_out_file; + +/* Index into this array by (register number >> 3) to find the + smallest class which contains that register. */ +enum reg_class regno_reg_class[] + = { DATA_REGS, ADDR_REGS, FP_REGS, + LO_FPA_REGS, LO_FPA_REGS, FPA_REGS, FPA_REGS }; + +static rtx find_addr_reg (); + +char * +output_btst (operands, countop, dataop, insn, signpos) + rtx *operands; + rtx countop, dataop; + rtx insn; + int signpos; +{ + operands[0] = countop; + operands[1] = dataop; + + if (GET_CODE (countop) == CONST_INT) + { + register int count = INTVAL (countop); + /* If COUNT is bigger than size of storage unit in use, + advance to the containing unit of same size. */ + if (count > signpos) + { + int offset = (count & ~signpos) / 8; + count = count & signpos; + operands[1] = dataop = adj_offsettable_operand (dataop, offset); + } + if (count == signpos) + cc_status.flags = CC_NOT_POSITIVE | CC_Z_IN_NOT_N; + else + cc_status.flags = CC_NOT_NEGATIVE | CC_Z_IN_NOT_N; + + if (count == 31 + && next_insns_test_no_inequality (insn)) + return "tst%.l %1"; + if (count == 15 + && next_insns_test_no_inequality (insn)) + return "tst%.w %1"; + if (count == 7 + && next_insns_test_no_inequality (insn)) + return "tst%.b %1"; + + cc_status.flags = CC_NOT_NEGATIVE; + } + return "btst %0,%1"; +} + +/* Return the best assembler insn template + for moving operands[1] into operands[0] as a fullword. */ + +static char * +singlemove_string (operands) + rtx *operands; +{ + if (FPA_REG_P (operands[0]) || FPA_REG_P (operands[1])) + return "fpmoves %1,%0"; + if (operands[1] != const0_rtx) + return "move%.l %1,%0"; + if (! ADDRESS_REG_P (operands[0])) + return "clr%.l %0"; + return "sub%.l %0,%0"; +} + +/* Output assembler code to perform a doubleword move insn + with operands OPERANDS. */ + +char * +output_move_double (operands) + rtx *operands; +{ + enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1; + rtx latehalf[2]; + rtx addreg0 = 0, addreg1 = 0; + + /* First classify both operands. */ + + if (REG_P (operands[0])) + optype0 = REGOP; + else if (offsettable_memref_p (operands[0])) + optype0 = OFFSOP; + else if (GET_CODE (XEXP (operands[0], 0)) == POST_INC) + optype0 = POPOP; + else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC) + optype0 = PUSHOP; + else if (GET_CODE (operands[0]) == MEM) + optype0 = MEMOP; + else + optype0 = RNDOP; + + if (REG_P (operands[1])) + optype1 = REGOP; + else if (CONSTANT_P (operands[1]) + || GET_CODE (operands[1]) == CONST_DOUBLE) + optype1 = CNSTOP; + else if (offsettable_memref_p (operands[1])) + optype1 = OFFSOP; + else if (GET_CODE (XEXP (operands[1], 0)) == POST_INC) + optype1 = POPOP; + else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC) + optype1 = PUSHOP; + else if (GET_CODE (operands[1]) == 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) + abort (); + + /* If one operand is decrementing and one is incrementing + decrement the former register explicitly + and change that operand into ordinary indexing. */ + + if (optype0 == PUSHOP && optype1 == POPOP) + { + operands[0] = XEXP (XEXP (operands[0], 0), 0); + output_asm_insn ("subq%.l %#8,%0", operands); + operands[0] = gen_rtx (MEM, DImode, operands[0]); + optype0 = OFFSOP; + } + if (optype0 == POPOP && optype1 == PUSHOP) + { + operands[1] = XEXP (XEXP (operands[1], 0), 0); + output_asm_insn ("subq%.l %#8,%1", operands); + operands[1] = gen_rtx (MEM, DImode, operands[1]); + optype1 = OFFSOP; + } + + /* 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 (operands[0], 0)); + + if (optype1 == MEMOP) + addreg1 = find_addr_reg (XEXP (operands[1], 0)); + + /* Ok, we can do one word at a time. + Normally we do the low-numbered word first, + but if either operand is autodecrementing then we + do the high-numbered word first. + + In either case, set up in LATEHALF the operands to use + for the high-numbered 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 (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); + else if (optype1 == OFFSOP) + latehalf[1] = adj_offsettable_operand (operands[1], 4); + else if (optype1 == CNSTOP) + { + if (CONSTANT_P (operands[1])) + latehalf[1] = const0_rtx; + else if (GET_CODE (operands[1]) == CONST_DOUBLE) + { +#ifndef HOST_WORDS_BIG_ENDIAN + latehalf[1] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_LOW (operands[1])); + operands[1] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_HIGH (operands[1])); +#else /* HOST_WORDS_BIG_ENDIAN */ + latehalf[1] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_HIGH (operands[1])); + operands[1] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_LOW (operands[1])); +#endif /* HOST_WORDS_BIG_ENDIAN */ + } + } + else + latehalf[1] = operands[1]; + + /* If insn is effectively movd N(sp),-(sp) then we will do the + high word first. We should use the adjusted operand 1 (which is N+4(sp)) + for the low word as well, to compensate for the first decrement of sp. */ + if (optype0 == PUSHOP + && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM + && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1])) + operands[1] = latehalf[1]; + + /* If one or both operands autodecrementing, + do the two words, high-numbered first. */ + + /* Likewise, the first move would clobber the source of the second one, + do them in the other order. This happens only for registers; + such overlap can't happen in memory unless the user explicitly + sets it up, and that is an undefined circumstance. */ + + if (optype0 == PUSHOP || optype1 == PUSHOP + || (optype0 == REGOP && optype1 == REGOP + && REGNO (operands[0]) == REGNO (latehalf[1]))) + { + /* Make any unoffsettable addresses point at high-numbered word. */ + if (addreg0) + output_asm_insn ("addql %#4,%0", &addreg0); + if (addreg1) + output_asm_insn ("addql %#4,%0", &addreg1); + + /* Do that word. */ + output_asm_insn (singlemove_string (latehalf), latehalf); + + /* Undo the adds we just did. */ + if (addreg0) + output_asm_insn ("subql %#4,%0", &addreg0); + if (addreg1) + output_asm_insn ("subql %#4,%0", &addreg1); + + /* Do low-numbered word. */ + return singlemove_string (operands); + } + + /* Normal case: do the two words, low-numbered first. */ + + output_asm_insn (singlemove_string (operands), operands); + + /* Make any unoffsettable addresses point at high-numbered word. */ + if (addreg0) + output_asm_insn ("addql %#4,%0", &addreg0); + if (addreg1) + output_asm_insn ("addql %#4,%0", &addreg1); + + /* Do that word. */ + output_asm_insn (singlemove_string (latehalf), latehalf); + + /* Undo the adds we just did. */ + if (addreg0) + output_asm_insn ("subql %#4,%0", &addreg0); + if (addreg1) + output_asm_insn ("subql %#4,%0", &addreg1); + + return ""; +} + +/* 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) + { + if (GET_CODE (XEXP (addr, 0)) == REG) + addr = XEXP (addr, 0); + else if (GET_CODE (XEXP (addr, 1)) == REG) + 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 (); +} + +/* Test for -0.0. */ + +int +double_is_minus_zero (arg) + double arg; +{ + union { double d; int i[2];} u; + + u.d = arg; + return (u.i[1] == 0 && u.i[0] == 0x80000000); +} + +char * +output_move_const_double (operands) + rtx *operands; +{ + if (TARGET_FPA && FPA_REG_P(operands[0])) + { + int code = standard_sun_fpa_constant_p (operands[1]); + + if (code != 0) + { + static char buf[40]; + + sprintf (buf, "fpmove%%.d %%%%%d,%%0", code & 0x1ff); + return buf; + } + return "fpmove%.d %1,%0"; + } + else + { + int code = standard_68881_constant_p (operands[1]); + + if (code != 0) + { + static char buf[40]; + + sprintf (buf, "fmovecr %%#0x%x,%%0", code & 0xff); + return buf; + } + return "fmove%.d %1,%0"; + } +} + +char * +output_move_const_single (operands) + rtx *operands; +{ + if (TARGET_FPA) + { + int code = standard_sun_fpa_constant_p (operands[1]); + + if (code != 0) + { + static char buf[40]; + + sprintf (buf, "fpmove%%.s %%%%%d,%%0", code & 0x1ff); + return buf; + } + return "fpmove%.s %1,%0"; + } + else + { + int code = standard_68881_constant_p (operands[1]); + + if (code != 0) + { + static char buf[40]; + + sprintf (buf, "fmovecr %%#0x%x,%%0", code & 0xff); + return buf; + } + return "fmove%.s %f1,%0"; + } +} + +/* Return nonzero if X, a CONST_DOUBLE, has a value that we can get + from the "fmovecr" instruction. + The value, anded with 0xff, gives the code to use in fmovecr + to get the desired constant. */ + +int +standard_68881_constant_p (x) + rtx x; +{ + union {double d; int i[2];} u; + register double d; + +#ifdef HOST_WORDS_BIG_ENDIAN + u.i[0] = CONST_DOUBLE_LOW (x); + u.i[1] = CONST_DOUBLE_HIGH (x); +#else + u.i[0] = CONST_DOUBLE_HIGH (x); + u.i[1] = CONST_DOUBLE_LOW (x); +#endif + d = u.d; + + if (d == 0) + return 0x0f; + /* Note: there are various other constants available + but it is a nuisance to put in their values here. */ + if (d == 1) + return 0x32; + if (d == 10) + return 0x33; + if (d == 100) + return 0x34; + if (d == 10000) + return 0x35; + if (d == 1e8) + return 0x36; + if (GET_MODE (x) == SFmode) + return 0; + if (d == 1e16) + return 0x37; + /* larger powers of ten in the constants ram are not used + because they are not equal to a `double' C constant. */ + return 0; +} + +/* Return nonzero if X, a CONST_DOUBLE, has a value that we can get + from the Sun FPA's constant RAM. + The value returned, anded with 0x1ff, gives the code to use in fpmove + to get the desired constant. */ +#define S_E (2.718281745910644531) +#define D_E (2.718281828459045091) +#define S_PI (3.141592741012573242) +#define D_PI (3.141592653589793116) +#define S_SQRT2 (1.414213538169860840) +#define D_SQRT2 (1.414213562373095145) +#define S_LOG2ofE (1.442695021629333496) +#define D_LOG2ofE (1.442695040888963387) +#define S_LOG2of10 (3.321928024291992188) +#define D_LOG2of10 (3.321928024887362182) +#define S_LOGEof2 (0.6931471824645996094) +#define D_LOGEof2 (0.6931471805599452862) +#define S_LOGEof10 (2.302585124969482442) +#define D_LOGEof10 (2.302585092994045901) +#define S_LOG10of2 (0.3010300099849700928) +#define D_LOG10of2 (0.3010299956639811980) +#define S_LOG10ofE (0.4342944920063018799) +#define D_LOG10ofE (0.4342944819032518167) + +int +standard_sun_fpa_constant_p (x) + rtx x; +{ + union {double d; int i[2];} u; + register double d; + u.i[0] = CONST_DOUBLE_LOW (x); + u.i[1] = CONST_DOUBLE_HIGH (x); + d = u.d; + + if (d == 0.0) + return 0x200; /* 0 once 0x1ff is anded with it */ + if (d == 1.0) + return 0xe; + if (d == 0.5) + return 0xf; + if (d == -1.0) + return 0x10; + if (d == 2.0) + return 0x11; + if (d == 3.0) + return 0xB1; + if (d == 4.0) + return 0x12; + if (d == 8.0) + return 0x13; + if (d == 0.25) + return 0x15; + if (d == 0.125) + return 0x16; + if (d == 10.0) + return 0x17; + if (d == -(1.0/2.0)) + return 0x2E; + +/* + * Stuff that looks different if it's single or double + */ + if (GET_MODE(x) == SFmode) + { + if (d == S_E) + return 0x8; + if (d == (2*S_PI)) + return 0x9; + if (d == S_PI) + return 0xA; + if (d == (S_PI / 2.0)) + return 0xB; + if (d == S_SQRT2) + return 0xC; + if (d == (1.0 / S_SQRT2)) + return 0xD; + /* Large powers of 10 in the constant + ram are not used because they are + not equal to a C double constant */ + if (d == -(S_PI / 2.0)) + return 0x27; + if (d == S_LOG2ofE) + return 0x28; + if (d == S_LOG2of10) + return 0x29; + if (d == S_LOGEof2) + return 0x2A; + if (d == S_LOGEof10) + return 0x2B; + if (d == S_LOG10of2) + return 0x2C; + if (d == S_LOG10ofE) + return 0x2D; + } + else + { + if (d == D_E) + return 0x8; + if (d == (2*D_PI)) + return 0x9; + if (d == D_PI) + return 0xA; + if (d == (D_PI / 2.0)) + return 0xB; + if (d == D_SQRT2) + return 0xC; + if (d == (1.0 / D_SQRT2)) + return 0xD; + /* Large powers of 10 in the constant + ram are not used because they are + not equal to a C double constant */ + if (d == -(D_PI / 2.0)) + return 0x27; + if (d == D_LOG2ofE) + return 0x28; + if (d == D_LOG2of10) + return 0x29; + if (d == D_LOGEof2) + return 0x2A; + if (d == D_LOGEof10) + return 0x2B; + if (d == D_LOG10of2) + return 0x2C; + if (d == D_LOG10ofE) + return 0x2D; + } + return 0x0; +} + +#undef S_E +#undef D_E +#undef S_PI +#undef D_PI +#undef S_SQRT2 +#undef D_SQRT2 +#undef S_LOG2ofE +#undef D_LOG2ofE +#undef S_LOG2of10 +#undef D_LOG2of10 +#undef S_LOGEof2 +#undef D_LOGEof2 +#undef S_LOGEof10 +#undef D_LOGEof10 +#undef S_LOG10of2 +#undef D_LOG10of2 +#undef S_LOG10ofE +#undef D_LOG10ofE diff --git a/gcc-1.40/config/out-m88k.c b/gcc-1.40/config/out-m88k.c new file mode 100644 index 0000000..d02ac86 --- /dev/null +++ b/gcc-1.40/config/out-m88k.c @@ -0,0 +1,605 @@ +/* Subroutines for insn-output.c for Motorola 88000. + Copyright (C) 1987 Free Software Foundation, Inc. + Contributed by Michael Tiemann (tiemann@mcc.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 1, 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. */ + +#ifndef FILE +#include +#endif + +/* This is where the condition code register lives. */ +rtx cc0_reg_rtx; + +static rtx find_addr_reg (); + +#if 0 +char * +output_compare (operands, opcode, exchange_opcode) + rtx *operands; + char *opcode; + char *exchange_opcode; +{ + static char buf[40]; + rtx op1, op2; + + if (GET_CODE (cc_prev_status.value2) == COMPARE) + { + op1 = XEXP (cc_prev_status.value2, 0); + op2 = XEXP (cc_prev_status.value2, 1); + } + else + { + op1 = cc_prev_status.value2; + op2 = const0_rtx; + } + if (GET_CODE (op1) == CONST_INT) + { + operands[2] = op1; + operands[1] = op2; + opcode = exchange_opcode; + } + else + { + operands[1] = op1; + operands[2] = op2; + } + sprintf (buf, "cmp r25,%%1,%%2\n\tbcnd %s,r25,%%l0", opcode); + return buf; +} + +char * +output_fcompare (operands, opcode, exchange_opcode) + rtx *operands; + char *opcode; + char *exchange_opcode; +{ + static char buf[40]; + + rtx op1, op2; + + if (GET_CODE (cc_prev_status.value2) == COMPARE) + { + op1 = XEXP (cc_prev_status.value2, 0); + op2 = XEXP (cc_prev_status.value2, 1); + } + else + { + op1 = cc_prev_status.value2; + op2 = const0_rtx; + } + if (GET_CODE (op1) == CONST_DOUBLE) + { + operands[2] = op1; + operands[1] = op2; + opcode = exchange_opcode; + } + else + { + operands[1] = op1; + operands[2] = op2; + } + sprintf (buf, "cmp r25,%%1,%%2\n\tbcnd %s,r25,%%l0", opcode); + return buf; +} + +char * +output_store (operands, opcode, exchange_opcode) + rtx *operands; + char *opcode; + char *exchange_opcode; +{ + static char buf[40]; + rtx op1, op2; + + if (GET_CODE (cc_prev_status.value2) == COMPARE) + { + op1 = XEXP (cc_prev_status.value2, 0); + op2 = XEXP (cc_prev_status.value2, 1); + } + else + { + op1 = cc_prev_status.value2; + op2 = const0_rtx; + } + + if (GET_CODE (op1) == CONST_INT) + { + operands[2] = op1; + operands[1] = op2; + opcode = exchange_opcode; + } + else + { + operands[1] = op1; + operands[2] = op2; + } + + sprintf (buf, "cmp r25,%%1,%%2\n\textu %%0,r25,1<%s>", opcode); + return buf; +} +#endif + +/* Nonzero if OP is a valid second operand for an arithmetic insn. */ + +int +arith_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + return (register_operand (op, mode) + || (GET_CODE (op) == CONST_INT + && (unsigned) INTVAL (op) < 0x10000)); +} + +int +arith32_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + return (register_operand (op, mode) || GET_CODE (op) == CONST_INT); +} + +int +int5_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + return (GET_CODE (op) == CONST_INT && (unsigned) INTVAL (op) < 0x20); +} + +/* Return the best assembler insn template + for moving operands[1] into operands[0] as a fullword. */ + +static char * +singlemove_string (operands) + rtx *operands; +{ + if (GET_CODE (operands[0]) == MEM) + return "st %r1,%0"; + if (GET_CODE (operands[1]) == MEM) + return "ld %0,%1"; + return "or %0,r0,%1"; +} + +/* Output assembler code to perform a doubleword move insn + with operands OPERANDS. */ + +char * +output_move_double (operands) + rtx *operands; +{ + enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1; + rtx latehalf[2]; + rtx addreg0 = 0, addreg1 = 0; + + /* First classify both operands. */ + + if (REG_P (operands[0])) + optype0 = REGOP; + else if (offsettable_memref_p (operands[0])) + optype0 = OFFSOP; + else if (GET_CODE (operands[0]) == MEM) + optype0 = MEMOP; + else + optype0 = RNDOP; + + if (REG_P (operands[1])) + optype1 = REGOP; + else if (CONSTANT_P (operands[1]) + || GET_CODE (operands[1]) == CONST_DOUBLE) + optype1 = CNSTOP; + else if (offsettable_memref_p (operands[1])) + optype1 = OFFSOP; + else if (GET_CODE (operands[1]) == 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) + 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 (operands[0]); + + if (optype1 == MEMOP) + addreg1 = find_addr_reg (operands[1]); + + /* Ok, we can do one word at a time. + Normally we do the low-numbered word first, + but if either operand is autodecrementing then we + do the high-numbered word first. + + In either case, set up in LATEHALF the operands to use + for the high-numbered 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 (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); + else if (optype1 == OFFSOP) + latehalf[1] = adj_offsettable_operand (operands[1], 4); + else if (optype1 == CNSTOP) + { + if (CONSTANT_P (operands[1])) + latehalf[1] = const0_rtx; + else if (GET_CODE (operands[1]) == CONST_DOUBLE) + { + latehalf[1] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_HIGH (operands[1])); + operands[1] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_LOW (operands[1])); + } + } + else + latehalf[1] = operands[1]; + + /* If the first move would clobber the source of the second one, + do them in the other order. This happens only for registers; + such overlap can't happen in memory unless the user explicitly + sets it up, and that is an undefined circumstance. */ + + if (optype0 == REGOP && optype1 == REGOP + && REGNO (operands[0]) == REGNO (latehalf[1])) + { + /* Make any unoffsettable addresses point at high-numbered word. */ + if (addreg0) + output_asm_insn ("addu %0,%0,4", &addreg0); + if (addreg1) + output_asm_insn ("addu %0,%0,4", &addreg1); + + /* Do that word. */ + output_asm_insn (singlemove_string (latehalf), latehalf); + + /* Undo the adds we just did. */ + if (addreg0) + output_asm_insn ("subu %0,%0,4", &addreg0); + if (addreg1) + output_asm_insn ("subu %0,%0,4", &addreg0); + + /* Do low-numbered word. */ + return singlemove_string (operands); + } + + /* Normal case: do the two words, low-numbered first. */ + + output_asm_insn (singlemove_string (operands), operands); + + /* Make any unoffsettable addresses point at high-numbered word. */ + if (addreg0) + output_asm_insn ("addu %0,%0,4", &addreg0); + if (addreg1) + output_asm_insn ("addu %0,%0,4", &addreg1); + + /* Do that word. */ + output_asm_insn (singlemove_string (latehalf), latehalf); + + /* Undo the adds we just did. */ + if (addreg0) + output_asm_insn ("subu %0,%0,4", &addreg0); + if (addreg1) + output_asm_insn ("subu %0,%0,4", &addreg1); + + return ""; +} + +/* 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) + { + if (GET_CODE (XEXP (addr, 0)) == REG) + addr = XEXP (addr, 0); + if (GET_CODE (XEXP (addr, 1)) == REG) + addr = XEXP (addr, 1); + if (CONSTANT_P (XEXP (addr, 0))) + addr = XEXP (addr, 1); + if (CONSTANT_P (XEXP (addr, 1))) + addr = XEXP (addr, 0); + } + if (GET_CODE (addr) == REG) + return addr; + return 0; +} + +/* Output an ascii string. */ +output_ascii (file, p, size) + FILE *file; + char *p; + int size; +{ + int i; + + fprintf (file, "\tstring \""); + + for (i = 0; i < size; i++) + { + register int c = p[i]; + if (c == '\"' || c == '\\') + putc ('\\', file); + if (c >= ' ' && c < 0177) + putc (c, file); + else + { + fprintf (file, "\\%03o", c); + /* After an octal-escape, if a digit follows, + terminate one string constant and start another. + The Vax assembler fails to stop reading the escape + after three digits, so this is the only way we + can get it to parse the data properly. */ + if (i < size - 1 && p[i + 1] >= '0' && p[i + 1] <= '9') + fprintf (file, "\"\n\tstring \""); + } + } + fprintf (file, "\"\n"); +} + +void +output_load_address (operands) + rtx *operands; +{ + rtx base, offset; + + if (CONSTANT_P (operands[3])) + { + output_asm_insn ("lda %0,%3", operands); + return; + } + + if (REG_P (operands[3])) + { + if (REGNO (operands[0]) != REGNO (operands[3])) + output_asm_insn ("or %0,r0,%3", operands); + return; + } + + base = XEXP (operands[3], 0); + offset = XEXP (operands[3], 1); + + if (GET_CODE (base) == CONST_INT) + { + rtx tmp = base; + base = offset; + offset = tmp; + } + + if (GET_CODE (offset) != CONST_INT) + abort (); + + operands[6] = base; + operands[7] = offset; + + if (REG_P (base)) + if (FITS_16_BITS (offset)) + output_asm_insn ("addu %0,%6,%7", operands); + else if (INT_FITS_16_BITS (- INTVAL (offset))) + output_asm_insn ("subu %0,%6,%7", operands); + else + output_asm_insn ("or.h %0,r0,hi16(%7)\n\tor %0,%0,lo16(%7)\n\tadd %0,%6,%0", operands); + else + { + if (GET_CODE (base) == MULT) + if (GET_MODE (base) == QImode) + output_asm_insn ("lda.b %0,%6"); + else if (GET_MODE (base) == HImode) + output_asm_insn ("lda.h %0,%6"); + else if (GET_MODE (base) == SImode) + output_asm_insn ("lda %0,%6"); + else + output_asm_insn ("lda.d %0,%6"); + else + output_asm_insn ("lda %0,%6"); + + if (FITS_16_BITS (offset)) + output_asm_insn ("addu %0,%7,%0", operands); + else if (INT_FITS_16_BITS (- INTVAL (offset))) + output_asm_insn ("subu %0,%7,%0", operands); + else + output_asm_insn ("or.h r25,r0,hi16(%7)\n\tor r25,r0,lo16(%7)\n\taddu %0,%0r25", operands); + } +} + +char * +output_block_move (operands) + rtx *operands; +{ + static int movstrsi_label = 0; + int align = 4; + + rtx xoperands[9]; + int available[3]; + int i, j; + + /* Since we clobber untold things, nix the condition codes. */ + CC_STATUS_INIT; + + /* Get past the MEMs. */ + operands[0] = XEXP (operands[0], 0); + operands[1] = XEXP (operands[1], 0); + + xoperands[0] = 0; + xoperands[1] = 0; + xoperands[2] = 0; + + available[0] = 1; + available[1] = 1; + available[2] = 1; +#if 1 + /* Prepare to juggle registers if necessary. */ + if (REG_P (operands[0]) && (unsigned) (REGNO (operands[0]) - 10) < 3) + { + xoperands[0] = operands[0]; + available[REGNO (operands[0]) - 10] = 0; + } + if (REG_P (operands[1]) && (unsigned) (REGNO (operands[1]) - 10) < 3) + { + xoperands[1] = operands[1]; + available[REGNO (operands[1]) - 10] = 0; + } + if (REG_P (operands[2]) && (unsigned) (REGNO (operands[2]) - 10) < 3) + { + xoperands[2] = operands[2]; + available[REGNO (operands[2]) - 10] = 0; + } + for (i = 0; i < 3; i++) + { + if (xoperands[i]) + continue; + if (available[0]) + { + xoperands[i] = gen_rtx (REG, SImode, 10); + available[0] = 0; + continue; + } + if (available[1]) + { + xoperands[i] = gen_rtx (REG, SImode, 11); + available[1] = 0; + continue; + } + xoperands[i] = gen_rtx (REG, SImode, 12); + available[2] = 0; + } +#endif + + /* First, figure out best alignment we may assume. */ + if (REG_P (operands[2])) + { + xoperands[5] = operands[2]; + output_asm_insn ("sub %5,%2,1", xoperands); + align = 1; + } + else + { + int i = INTVAL (operands[2]); + + if (i & 1) + align = 1; + else if (i & 3) + { + align = 2; + i >>= 1; + } + else + i >>= 2; + + /* predecrement count. */ + i -= 1; + if (i < 0) abort (); + + xoperands[5] = gen_rtx (CONST_INT, VOIDmode, i); + + if (INT_FITS_16_BITS (i)) + output_asm_insn ("addu %2,r0,%5", xoperands); + else if (INT_FITS_16_BITS (-i)) + { + xoperands[5] = gen_rtx (CONST_INT, VOIDmode, -i); + output_asm_insn ("subu %2,r0,%5", xoperands); + } + else + output_asm_insn ("or.u %2,r0,hi16(%5)\n\tor %2,%2,lo16(%5)", xoperands); + } + /* Now, set up for pipelined operation: dest must contain + a pre-incremented address, because its index is pre-decremented. */ + + xoperands[3] = plus_constant (operands[0], align); + output_load_address (xoperands); + + xoperands[4] = operands[1]; + output_load_address (xoperands+1); + + xoperands[3] = gen_rtx (CONST_INT, VOIDmode, movstrsi_label++); + + if (align == 4) + output_asm_insn ("\n@Lm%3:\n\tld r25,%1[%2]\n\tsubu %2,%2,1\n\tbcnd.n ge0,%2,@Lm%3\n\tst r25,%0[%2]", xoperands); + else if (align == 2) + output_asm_insn ("\n@Lm%3:\n\tld.h r25,%1[%2]\n\tsubu %2,%2,1\n\tbcnd.n ge0,%2,@Lm%3\n\tst.h r25,%0[%2]", xoperands); + else + output_asm_insn ("\n@Lm%3:\n\tld.b r25,%1[%2]\n\tsubu %2,%2,1\n\tbcnd.n ge0,%2,@Lm%3\n\tst.b r25,%0[%2]", xoperands); + return ""; +} + +char * +output_store_const_int (mode, operands) + enum machine_mode mode; + rtx *operands; +{ + int i = INTVAL (operands[1]); + if (INT_FITS_16_BITS (i)) + return "addu %0,r0,%1"; + if (INT_FITS_16_BITS (-i)) + { + operands[1] = gen_rtx (CONST_INT, VOIDmode, -i); + return "subu %0,r0,%1"; + } + if ((i & 0xffff) == 0) + return "or.u %0,r0,hi16(%1)"; + /* Could check to see if number is a contiguous field + of 1's. Then we could use the SET instruction. */ + if (mode == HImode) + { + warning ("truncating constant `%d' to fit in half-word", INTVAL (operands[1])); + return "or %0,r0,lo16(%1)"; + } + if (mode == QImode) + { + warning ("truncating constant `%d' to fit in byte"); + operands[1] = gen_rtx (CONST_INT, VOIDmode, i & 0xff); + return "or %0,r0,%1"; + } + + return "or.u %0,r0,hi16(%1)\n\tor %0,%0,lo16(%1)"; +} + +/* This routine assumes that floating point numbers are represented + in a manner which is consistent between host and target machines. */ +char * +output_store_const_float (mode, operands) + enum machine_mode mode; + rtx *operands; +{ + int i = INTVAL (operands[1]); + if (INT_FITS_16_BITS (i)) + return "addu %0,r0,%1"; + if (INT_FITS_16_BITS (-i)) + { + operands[1] = gen_rtx (CONST_INT, VOIDmode, -i); + return "subu %0,r0,%1"; + } + if ((i & 0xffff) == 0) + return "or.u %0,r0,hi16(%1)"; + /* Could check to see if number is a contiguous field + of 1's. Then we could use the SET instruction. */ + return "or.u %0,r0,hi16(%1)\n\tor %0,%0,lo16(%1)"; +} diff --git a/gcc-1.40/config/out-mips.c b/gcc-1.40/config/out-mips.c new file mode 100644 index 0000000..ab1dac0 --- /dev/null +++ b/gcc-1.40/config/out-mips.c @@ -0,0 +1,1086 @@ +/* Subroutines for insn-output.c for MIPS + Contributed by A. Lichnewsky, lich@inria.inria.fr. + Changes by Michael Meissner, meissner@osf.org. + Copyright (C) 1989, 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 1, 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 +#include +#include +#include "tree.h" +#include "flags.h" + +#ifndef R_OK +#define R_OK 4 +#define W_OK 2 +#define X_OK 1 +#endif + +extern void debug_rtx (); +extern void abort_with_insn (); + +extern FILE *asm_out_file; +extern tree current_function_decl; + +/* Global variables for machine-dependent things. */ + +char *reg_numchar[] = REGISTER_NUMCHAR; + +/* Threshold for data being put into the small data/bss area, instead + of the normal data area (references to the small data/bss area take + 1 instruction, and use the global pointer, references to the normal + data area takes 2 instructions). */ +int mips_section_threshold = -1; + +/* Count the number of .file directives, so that .loc is up to date. */ +int num_source_filenames = 0; + +/* Count the number of words that are pushed to pass arguments. */ +int stack_args_pushed = 0; + +/* # bytes for args preallocated by function_prolog. */ +int stack_args_preallocated = 0; + +/* Count of the number of functions created so far, in order to make + unique labels for omitting the frame pointer. */ +int number_functions_processed = 0; + +/* Count the number of sdb related labels are generated (to find block + start and end boundaries). */ +int sdb_label_count = 0; + +/* Next label # for each statment for Silicon Graphics IRIS systems. */ +int sym_lineno = 0; + +/* Non-zero if inside of a function, because the stupid MIPS asm can't + handle .files inside of functions. */ +int inside_function = 0; + +/* String to be used for the unique name given to the difference between + the stack pointer and frame pointer when the frame pointer is to be + omitted. */ +char *sp_fp_difference = 0; + +/* Files to separate the text and the data output, so that all of the data + can be emitted before the text, which will mean that the assembler will + generate smaller code, based on the global pointer. */ +FILE *asm_out_data_file; +FILE *asm_out_text_file; + +/* Linked list of all externals that are to be emitted when optimizing + for the global pointer if they haven't been declared by the end of + the program with an appropriate .comm or initialization. */ + +struct extern_list { + struct extern_list *next; /* next external */ + char *name; /* name of the external */ + int size; /* size in bytes */ +} *extern_head = 0; + +/* Name of the current function. */ +char *current_function_name; + +/* Size of the frame allocated for this function. */ +int current_function_total_framesize; + +/* Number of bytes used to hold saved registers. */ +int current_function_saved_reg_size; + +/* Return truth value of whether OP can be used as an operands + where a register or 16 bit unsigned integer is needed. */ + +int +uns_arith_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + return (register_operand (op, mode) + || (GET_CODE (op) == CONST_INT && SMALL_INT_UNSIGNED (op))); +} + +/* Return truth value of whether OP can be used as an operands + where a 16 bit integer is needed */ + +int +arith_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + return (register_operand (op, mode) + || (GET_CODE (op) == CONST_INT && SMALL_INT (op))); +} + +/* Return truth value of whether OP can be used as an operand in a two + address arithmetic insn (such as set 123456,%o4) of mode MODE. */ + +int +arith32_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + return (register_operand (op, mode) || GET_CODE (op) == CONST_INT); +} + +/* Return truth value of whether OP is a integer which fits in 16 bits */ + +int +small_int (op, mode) + rtx op; + enum machine_mode mode; +{ + return (GET_CODE (op) == CONST_INT && SMALL_INT (op)); +} + + +/* Argument support functions. */ + +/* Initialize CUMULATIVE_ARGS for a function. */ + +void +init_cumulative_args (cum, fntype) + CUMULATIVE_ARGS cum; /* argument info to initialize */ + tree fntype; /* tree ptr for function decl */ +{ + tree param, next_param; + + if (TARGET_DEBUGE_MODE) + { + fprintf (stderr, "\ninit_cumulative_args\n"); + if (fntype != (tree)0) + { + putc ('\n', stderr); + debug_tree (fntype); + putc ('\n', stderr); + } + } + + cum->gp_reg_found = 0; + cum->arg_number = 0; + cum->arg_words = 0; + + /* Determine if this function has variable arguments. This is + indicated by the last argument being 'void_type_mode' if there + are no variable arguments. The standard MIPS calling sequence + passes all arguments in the general purpose registers in this + case. */ + + for (param = (fntype) ? TYPE_ARG_TYPES (fntype) : 0; + param != (tree)0; + param = next_param) + { + next_param = TREE_CHAIN (param); + if (next_param == (tree)0 && TREE_VALUE (param) != void_type_node) + cum->gp_reg_found = 1; + } + + /* Determine if the function is returning a structure, if so, + advance by one argument. */ + + if (fntype + && (TREE_CODE (fntype) == FUNCTION_TYPE || TREE_CODE (fntype) == METHOD_TYPE) + && TREE_TYPE (fntype) != 0) + { + tree ret_type = TREE_TYPE (fntype); + enum tree_code ret_code = TREE_CODE (ret_type); + + if (ret_code == RECORD_TYPE || ret_code == UNION_TYPE) + { + cum->gp_reg_found = 1; + cum->arg_number = 1; + cum->arg_words = 1; + } + } +} + +/* Advance the argument to the next argument position. */ + +void +function_arg_advance (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 */ +{ + if (TARGET_DEBUGE_MODE) + fprintf (stderr, + "function_adv( {gp reg found = %d, arg # = %2d, words = %2d}, %4s, 0x%.8x, %d )\n", + cum->gp_reg_found, cum->arg_number, cum->arg_words, GET_MODE_NAME (mode), + type, named); + + cum->arg_number++; + switch (mode) + { + default: + error ("Illegal mode given to function_arg_advance"); + break; + + case VOIDmode: + break; + + case BLKmode: + cum->gp_reg_found = 1; + cum->arg_words += (int_size_in_bytes (type) + 3) / 4; + break; + + case SFmode: + cum->arg_words++; + break; + + case DFmode: + cum->arg_words += 2; + break; + + case DImode: + cum->gp_reg_found = 1; + cum->arg_words += 2; + break; + + case QImode: + case HImode: + case SImode: + cum->gp_reg_found = 1; + cum->arg_words++; + break; + } +} + +/* Return a RTL expression containing the register for the given mode, + or 0 if the argument is too be passed on the stack. */ + +struct rtx_def * +function_arg (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 */ +{ + int regbase = -1; + int bias = 0; + + if (TARGET_DEBUGE_MODE) + fprintf (stderr, + "function_arg( {gp reg found = %d, arg # = %2d, words = %2d}, %4s, 0x%.8x, %d ) = ", + cum->gp_reg_found, cum->arg_number, cum->arg_words, GET_MODE_NAME (mode), + type, named); + + switch (mode) + { + default: + error ("Illegal mode given to function_arg"); + break; + + case SFmode: + if (cum->gp_reg_found || cum->arg_number >= 2) + regbase = GP_ARG_FIRST; + else { + regbase = FP_ARG_FIRST; + if (cum->arg_words == 1) /* first arg was float */ + bias = 1; /* use correct reg */ + } + + break; + + case DFmode: + cum->arg_words += (cum->arg_words & 1); + regbase = (cum->gp_reg_found) ? GP_ARG_FIRST : FP_ARG_FIRST; + break; + + case VOIDmode: + case BLKmode: + case QImode: + case HImode: + case SImode: + case DImode: + regbase = GP_ARG_FIRST; + break; + } + + if (cum->arg_words >= MAX_ARGS_IN_REGISTERS) + { + if (TARGET_DEBUGE_MODE) + fprintf (stderr, "\n"); + + return 0; + } + + if (regbase == -1) + abort (); + + if (TARGET_DEBUGE_MODE) + fprintf (stderr, "%s\n", reg_numchar[ regbase + cum->arg_number + bias ]); + + return gen_rtx (REG, mode, regbase + cum->arg_words + bias); +} + + +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 */ +{ + if (mode == BLKmode && cum->arg_words < MAX_ARGS_IN_REGISTERS) + { + int words = (int_size_in_bytes (type) + 3) / 4; + + if (words + cum->arg_words < MAX_ARGS_IN_REGISTERS) + return 0; /* structure fits in registers */ + + if (TARGET_DEBUGE_MODE) + fprintf (stderr, "function_arg_partial_nregs = %d\n", + MAX_ARGS_IN_REGISTERS - cum->arg_words); + + return MAX_ARGS_IN_REGISTERS - cum->arg_words; + } + + else if (mode == DImode && cum->arg_words == MAX_ARGS_IN_REGISTERS-1) + { + if (TARGET_DEBUGE_MODE) + fprintf (stderr, "function_arg_partial_nregs = 1\n"); + + return 1; + } + + return 0; +} + + +/* Routines to merge the compare and branch operators into a single entity. */ + +static rtx branch_cmp_op[2]; +static enum machine_mode branch_cmp_mode; + +/* Save the mode and operands on the current compare operator. */ + +void +compare_collect (mode, op0, op1) + enum machine_mode mode; + rtx op0; + rtx op1; +{ + if (TARGET_DEBUGD_MODE) + { + fprintf (stderr, "compare_collect mode = %s, operands::", + GET_MODE_NAME (mode)); + debug_rtx (op0); + debug_rtx (op1); + } + branch_cmp_op[0] = op0; + branch_cmp_op[1] = op1; + branch_cmp_mode = mode; +} + +/* Return the mode and operands saved with compare_collect for use + in a branch operator. */ + +void +compare_restore (operands, mode, insn) + rtx *operands; + enum machine_mode *mode; + rtx insn; +{ + if (!branch_cmp_op[0] || !branch_cmp_op[1]) + abort_with_insn (insn, "Compare_restore did not follow compare_collect"); + + if (TARGET_DEBUGD_MODE) + { + fprintf (stderr, + "compare_restore returning mode = %s, operands:%X,%X:", + GET_MODE_NAME (branch_cmp_mode), + branch_cmp_op[0], + branch_cmp_op[1]); + + debug_rtx (branch_cmp_op[0]); + debug_rtx (branch_cmp_op[1]); + } + + operands[0] = branch_cmp_op[0]; + operands[1] = branch_cmp_op[1]; + *mode = branch_cmp_mode; + + /* If the next insn is not a JUMP (after accounting for line numbers), + zero out the branch_cmp_array. Switch statements implemented as if's + tend to have multiple jumps. */ + do + { + insn = NEXT_INSN (insn); + } + while (insn && GET_CODE (insn) == NOTE); + + if (!insn || GET_CODE (insn) != JUMP_INSN) + { + branch_cmp_op[0] = NULL; + branch_cmp_op[1] = NULL; + branch_cmp_mode = VOIDmode; + } + +} + +/* Print the options used in the assembly file. */ + +static struct {char *name; int value;} target_switches [] + = TARGET_SWITCHES; + +void +print_options (out) + FILE *out; +{ + int line_len; + int len; + int j; + char **p; + int mask = TARGET_DEFAULT; + extern char **save_argv; + extern char *version_string, *language_string; + +#if 0 + /* Allow assembly language comparisons with -mdebug eliminating the + compiler version number and switch lists. */ + if (!TARGET_DEBUG_MODE) + { + fprintf (out, "\n # %s %s", language_string, version_string); +#ifdef TARGET_VERSION_INTERNAL + TARGET_VERSION_INTERNAL (out); +#endif +#ifdef __GNUC__ + fprintf (out, " compiled by GNU C\n\n"); +#else + fprintf (out, " compiled by CC\n\n"); +#endif + + fprintf (out, " # Cc1 defaults:"); + line_len = 32767; + 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 & mask) == target_switches[j].value) + { + len = strlen (target_switches[j].name) + 1; + if (len + line_len > 79) + { + line_len = 2; + fputs ("\n #", out); + } + fprintf (out, " -m%s", target_switches[j].name); + line_len += len; + } + + fprintf (out, "\n\n # Cc1 arguments (-G value = %d):", + mips_section_threshold); + + line_len = 32767; + for (p = &save_argv[1]; *p != (char *)0; p++) + if (**p == '-') + { + len = strlen (*p) + 1; + if (len + line_len > 79) + { + line_len = 2; + fputs ("\n #", out); + } + fprintf (out, " %s", *p); + line_len += len; + } + fputs ("\n\n", out); + } + +#endif +} + + + +/* Abort after printing out a specific insn. */ + +void +abort_with_insn (insn, reason) + rtx insn; + char *reason; +{ + error (reason); + debug_rtx (insn); + abort (); +} + +/* Write a message to stderr (for use in macros expanded in files that do not + include stdio.h). */ + +void +trace (s, s1, s2) + char *s, *s1, *s2; +{ + fprintf (stderr, s, s1, s2); +} + + +/* Set up the threshold for data to go into the small data area, instead + of the normal data area, and detect any conflicts in the switches. */ + +void +overide_options () +{ + register int i; + + i = TARGET_GVALUE; + if (i >= 6) + i += 3; + mips_section_threshold = (i != 0) ? 1 << i : 0; +} + +/* Compute a string to use as a temporary file name. */ + +static FILE * +make_temp_file () +{ + char *temp_filename; + FILE *stream; + extern char *getenv (); + 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; + else +#endif + if (access ("/usr/tmp", R_OK | W_OK) == 0) + base = "/usr/tmp/"; + else + base = "/tmp/"; + } + + len = strlen (base); + temp_filename = (char *) alloca (len + sizeof("/ccXXXXXX")); + strcpy (temp_filename, base); + if (len > 0 && temp_filename[len-1] != '/') + temp_filename[len++] = '/'; + + strcpy (temp_filename + len, "ccXXXXXX"); + mktemp (temp_filename); + + stream = fopen (temp_filename, "w+"); + if (!stream) + pfatal_with_name (temp_filename); + + unlink (temp_filename); + return stream; +} + +/* Output at beginning of assembler file. + If we are optimizing to use the global pointer, create a temporary + file to hold all of the text stuff, and write it out to the end. + This is needed because the MIPS assembler is evidently one pass, + and if it hasn't seen the relevant .comm/.lcomm/.extern/.sdata + declaration when the code is processed, it generates a two + instruction sequence. */ + +void +mips_asm_file_start (stream) + FILE *stream; +{ + if (TARGET_NAME_REGS) + fprintf (stream, "#include \n"); + + ASM_OUTPUT_SOURCE_FILENAME (stream, main_input_filename); + + print_options (stream); + data_section (); /* put gcc_compiled. in data, not text*/ + + if (TARGET_GP_OPT) + { + asm_out_data_file = stream; + asm_out_text_file = make_temp_file (); + } + else + asm_out_data_file = asm_out_text_file = stream; + +} + +/* If optimizing for the global pointer, keep track of all of + the externs, so that at the end of the file, we can emit + the appropriate .extern declaration for them, before writing + out the text section. We assume that all names passed to + us are in the permanent obstack, so that they will be valid + at the end of the compilation. + + If we have -G 0, or the extern size is unknown, don't bother + emitting the .externs. */ + +int +mips_output_external (file, decl, name) + FILE *file; + tree decl; + char *name; +{ + extern char *permalloc (); + register struct extern_list *p; + int len; + + if (TARGET_GP_OPT + && mips_section_threshold != 0 + && ((TREE_CODE (decl)) != FUNCTION_DECL) + && ((len = int_size_in_bytes (TREE_TYPE (decl))) > 0)) + { + p = (struct extern_list *)permalloc ((long) sizeof (struct extern_list)); + p->next = extern_head; + p->name = name; + p->size = len; + extern_head = p; + } + return 0; +} + +/* If we are optimizing the global pointer, emit the text section now + and any small externs which did not have .comm, etc that are + needed. Also, give a warning if the data area is more than 32K and + -pic because 3 instructions are needed to reference the data + pointers. */ + +int +mips_asm_file_end (file) + FILE *file; +{ + char buffer[8192]; + tree name_tree; + struct extern_list *p; + int len; + extern tree lookup_name (); + + if (TARGET_GP_OPT) + { + if (extern_head) + fputs ("\n", file); + + for (p = extern_head; p != 0; p = p->next) + { + name_tree = get_identifier (p->name); + if (!TREE_ADDRESSABLE (name_tree)) + { + TREE_ADDRESSABLE (name_tree) = 1; + fprintf (file, "\t.extern\t%s, %d\n", p->name, p->size); + } + } + + fprintf (file, "\n\t.text\n"); + rewind (asm_out_text_file); + if (ferror (asm_out_text_file)) + fatal_io_error ("write of text assembly file in mips_asm_file_end"); + + while ((len = fread (buffer, 1, sizeof (buffer), asm_out_text_file)) > 0) + if (fwrite (buffer, 1, len, file) != len) + pfatal_with_name ("write of final assembly file in mips_asm_file_end"); + + if (len < 0) + pfatal_with_name ("read of text assembly file in mips_asm_file_end"); + + if (fclose (asm_out_text_file) != 0) + pfatal_with_name ("close of tempfile in mips_asm_file_end"); + } +} + +/* Fix references to the frame pointer to be off of the stack pointer. */ + +struct rtx_def * +mips_fix_frame_pointer (oldaddr, depth) + rtx oldaddr; + int depth; +{ + rtx newaddr; + rtx sp_diff_rtx; + char temp[40]; + int frame_offset = 0; + extern rtx eliminate_constant_term (); + + newaddr = eliminate_constant_term (oldaddr, &frame_offset); + if (newaddr != frame_pointer_rtx) + return oldaddr; + + if (sp_fp_difference == (char *)0) + { + sprintf (temp, "$Ls%d", number_functions_processed); + sp_fp_difference = IDENTIFIER_POINTER (get_identifier (temp)); + } + + sp_diff_rtx = gen_rtx (SYMBOL_REF, SImode, sp_fp_difference); + if (frame_offset + depth == 0) + newaddr = gen_rtx (PLUS, Pmode, stack_pointer_rtx, sp_diff_rtx); + else + newaddr = gen_rtx (PLUS, Pmode, + stack_pointer_rtx, + gen_rtx (CONST, Pmode, + gen_rtx (PLUS, Pmode, + sp_diff_rtx, + gen_rtx (CONST_INT, VOIDmode, + frame_offset + depth)))); + + if (TARGET_DEBUGC_MODE) + { + fprintf (stderr, + "\n==================== FIX_FRAME, depth = %d, sp prealloc = %d, offset = %d\n", + depth, stack_args_preallocated, frame_offset); + + fprintf (stderr, "old INSN:"); + debug_rtx (oldaddr); + + fprintf (stderr, "\nnew INSN:"); + debug_rtx (newaddr); + } + + return newaddr; +} + + +/* Set up the stack and frame (if desired) for the function. */ + +void +function_prologue (file, size) + FILE *file; + int size; +{ + extern char call_used_regs[]; + extern char *reg_numchar[]; + extern tree current_function_decl; + int regno; + int mask; + int fmask; + int push_loc; + int tsize; + int num_regs; + char **reg_name_ptr = (TARGET_NAME_REGS) ? reg_names : reg_numchar; + char *base_str; + char *sp_str = reg_name_ptr[STACK_POINTER_REGNUM]; + char *fp_str = (!frame_pointer_needed) + ? sp_str + : reg_name_ptr[FRAME_POINTER_REGNUM]; + tree fndecl = current_function_decl; /* current... is tooo long */ + tree fntype = TREE_TYPE (fndecl); + tree fnargs = (TREE_CODE (fntype) != METHOD_TYPE) + ? DECL_ARGUMENTS (fndecl) + : 0; + tree next_arg; + tree cur_arg; + char *arg_name = (char *)0; + CUMULATIVE_ARGS args_so_far; + + + inside_function = 1; + + + if (write_symbols != NO_DEBUG) + ASM_OUTPUT_SOURCE_LINE (file, + DECL_SOURCE_LINE (current_function_decl)); + + fprintf (file, "\t.ent\t%s\n%s:\n", current_function_name, + current_function_name); + + fprintf (file, " #PROLOGUE\n"); + + /* Determine the last argument, and get it's name. */ + for (cur_arg = fnargs; cur_arg != (tree)0; cur_arg = next_arg) + { + next_arg = TREE_CHAIN (cur_arg); + if (next_arg == (tree)0) + { + if (DECL_NAME (cur_arg)) + arg_name = IDENTIFIER_POINTER (DECL_NAME (cur_arg)); + + break; + } + } + + /* If this function is a varargs function, store any registers that + would normally hold arguments ($4 - $7) on the stack. */ + if ((TYPE_ARG_TYPES (fntype) != 0 + && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype))) != void_type_node)) + || (arg_name + && (strcmp (arg_name, "__builtin_va_alist") == 0 + || strcmp (arg_name, "va_alist") == 0))) + { + tree parm; + + regno = 4; + INIT_CUMULATIVE_ARGS (args_so_far, fntype); + + for (parm = fnargs; (parm && (regno <= 7)); parm = TREE_CHAIN (parm)) + { + rtx entry_parm; + enum machine_mode passed_mode; + tree type; + + type = DECL_ARG_TYPE (parm); + passed_mode = TYPE_MODE (type); + entry_parm = FUNCTION_ARG (args_so_far, passed_mode, + DECL_ARG_TYPE (parm), 1); + + if (entry_parm) + { + int words; + + /* passed in a register, so will get homed automatically */ + if (GET_MODE (entry_parm) == BLKmode) + words = (int_size_in_bytes (type) + 3) / 4; + else + words = (GET_MODE_SIZE (GET_MODE (entry_parm)) + 3) / 4; + + regno = REGNO (entry_parm) + words - 1; + } + else + { + regno = 8; + break; + } + + FUNCTION_ARG_ADVANCE (args_so_far, passed_mode, + DECL_ARG_TYPE (parm), 1); + } + + switch (regno) + { + case 4: + fprintf(file, "\tsd\t%s,0(%s)\t#varargs: home regs 4-5\n", + reg_name_ptr[4], sp_str); + + fprintf(file, "\tsd\t%s,8(%s)\t#varargs: home regs 6-7\n", + reg_name_ptr[6], sp_str); + break; + + case 5: + fprintf(file, "\tsw\t%s,4(%s)\t#varargs: home reg 5\n", + reg_name_ptr[5], sp_str); + + fprintf(file, "\tsd\t%s,8(%s)\t#varargs: home regs 6-7\n", + reg_name_ptr[6], sp_str); + break; + + case 6: + fprintf(file, "\tsd\t%s,8(%s)\t#varargs: home regs 6-7\n", + reg_name_ptr[6], sp_str); + break; + + case 7: + fprintf(file, "\tsw\t%s,12(%s)\t#varargs: home reg 7\n", + reg_name_ptr[7], sp_str); + break; + + default: + break; + } + } + + mask = 0; + fmask = 0; + num_regs = 0; + push_loc = stack_args_preallocated; + tsize = AL_ADJUST_ALIGN (size) + stack_args_preallocated; + + for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++) + if (MUST_SAVE_REGISTER (regno)) + { + tsize += 4; + num_regs += 4; + mask |= 1 << (regno - GP_REG_FIRST); + } + + tsize = AL_ADJUST_ALIGN (tsize); + num_regs = AL_ADJUST_ALIGN (num_regs); + for (regno = FP_REG_FIRST; regno <= FP_REG_LAST; regno += 2) + if (regs_ever_live[regno] && !call_used_regs[regno]) + { + tsize += 8; + num_regs += 8; + fmask |= 1 << (regno - FP_REG_FIRST); + } + + if (tsize) + tsize -= STARTING_FRAME_OFFSET; + + + if (!frame_pointer_needed && sp_fp_difference != (char *)0) + fprintf (file,"%s\t= %d\t\t\t#Difference between SP & FP\n\n", + sp_fp_difference, tsize); + + current_function_total_framesize = tsize; + current_function_saved_reg_size = num_regs; + if (tsize > 0) + { + if (tsize <= 32767) + fprintf (file, + "\tsubu\t%s,%s,%d\t# temp= %d, regs= %d, args= %d, sfo= %d\n", + sp_str, sp_str, tsize, size, num_regs, + stack_args_preallocated, STARTING_FRAME_OFFSET); + else + fprintf (file, + "\tli\t%s,%d\n\tsubu\t%s,%s,%s\t# temp= %d, regs= %d, args= %d, sfo= %d\n", + reg_name_ptr[MIPS_TEMP1_REGNUM], tsize, sp_str, sp_str, + reg_name_ptr[MIPS_TEMP1_REGNUM], size, num_regs, + stack_args_preallocated, STARTING_FRAME_OFFSET); + } + + fprintf (file, "\t.frame\t%s,%d,%s\n", fp_str, + (frame_pointer_needed) ? 0 : tsize, + reg_name_ptr[31]); + + if (push_loc > 32767 && num_regs > 0) + { + if ((tsize - (push_loc + num_regs)) <= 32767) + { + base_str = reg_name_ptr[MIPS_TEMP1_REGNUM]; + push_loc = tsize - push_loc; + } + else + { + base_str = reg_name_ptr[MIPS_TEMP2_REGNUM]; + fprintf (file, "\tli\t%s,%d\n", base_str, push_loc); + push_loc = 0; + } + } + else + base_str = sp_str; + + for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++) + if ((mask & (1 << (regno - GP_REG_FIRST))) != 0) + { + fprintf (file, "\tsw\t%s,%d(%s)\n", reg_name_ptr[regno], push_loc, + base_str); + push_loc += 4; + } + + fprintf (file, "\t.mask\t0x%08x,%d\n", mask, push_loc - tsize - 4); + + push_loc = AL_ADJUST_ALIGN (push_loc); + for (regno = FP_REG_FIRST; regno <= FP_REG_LAST; regno += 2) + if ((fmask & (1 << (regno - FP_REG_FIRST))) != 0) + { + fprintf (file, "\ts.d\t%s,%d(%s)\n", reg_name_ptr[regno], push_loc, + base_str); + push_loc += 8; + } + + fprintf (file, "\t.fmask\t0x%08x,%d\n", fmask, push_loc - tsize - 4); + + if (frame_pointer_needed) + { + if (tsize <= 32767) + fprintf (file, "\taddu\t%s,%s,%d\t# set up frame pointer\n", fp_str, sp_str, tsize); + else + fprintf (file, "\taddu\t%s,%s,%s\t# set up frame pointer\n", fp_str, sp_str, + reg_name_ptr[MIPS_TEMP1_REGNUM]); + } + + fprintf (file," #END PROLOGUE\n"); +} + + +/* Do any necessary cleanup after a function to restore stack, frame, and regs. */ + +void +function_epilogue (file, size) + FILE *file; + int size; +{ + extern FILE *asm_out_data_file, *asm_out_file; + extern char call_used_regs[]; + extern char *reg_numchar[]; + extern char *current_function_name; + extern int frame_pointer_needed; + int regno; + int push_loc = stack_args_preallocated; + int tsize = current_function_total_framesize; + int num_regs = current_function_saved_reg_size; + char **reg_name_ptr = (TARGET_NAME_REGS) ? reg_names : reg_numchar; + char *sp_str = reg_name_ptr[STACK_POINTER_REGNUM]; + char *t1_str = reg_name_ptr[MIPS_TEMP1_REGNUM]; + char *base_str; + + + fprintf (file," #EPILOGUE\n"); + + if (tsize > 32767) + fprintf (file, "\tli\t%s,%d\n", t1_str, tsize); + + if (frame_pointer_needed) + { + char *fp_str = reg_name_ptr[FRAME_POINTER_REGNUM]; + if (tsize > 32767) + fprintf (file,"\tsubu\t%s,%s,%s\t# sp not trusted here\n", + sp_str, fp_str, t1_str); + else + fprintf (file,"\tsubu\t%s,%s,%d\t# sp not trusted here\n", + sp_str, fp_str, tsize); + } + + if (push_loc > 32767 && num_regs > 0) + { + if ((tsize - (push_loc + num_regs)) <= 32767) + { + base_str = t1_str; + push_loc = tsize - push_loc; + } + else + { + base_str = reg_name_ptr[MIPS_TEMP2_REGNUM]; + fprintf (file, "\tli\t%s,%d\n", base_str, push_loc); + push_loc = 0; + } + } + else + base_str = sp_str; + + for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++) + if (MUST_SAVE_REGISTER (regno)) + { + fprintf (file,"\tlw\t%s,%d(%s)\n", reg_name_ptr[regno], push_loc, + base_str); + push_loc += 4; + } + + push_loc = AL_ADJUST_ALIGN (push_loc); + for (regno = FP_REG_FIRST; regno <= FP_REG_LAST; regno += 2) + if (regs_ever_live[regno] && !call_used_regs[regno]) + { + fprintf (file, "\tl.d\t%s,%d(%s)\n", reg_name_ptr[regno], push_loc, + base_str); + push_loc += 8; + } + + if (tsize > 32767) + fprintf (file, "\taddu\t%s,%s,%s\n", sp_str, sp_str, t1_str); + + else if (tsize > 0) + fprintf (file, "\taddu\t%s,%s,%d\n", sp_str, sp_str, tsize); + + fprintf (file,"\tj\t%s\n", reg_name_ptr[31]); + fprintf (file," #END EPILOGUE\n"); + fprintf (file,"\t.end\t%s\n", current_function_name); + + /* Reset state info for each function. */ + stack_args_pushed = 0; + stack_args_preallocated = 0; + inside_function = 0; + sp_fp_difference = (char *)0; + number_functions_processed++; + + /* Restore the output file if optimizing the GP (optimizing the GP causes + the text to be diverted to a tempfile, so that data decls come before + references to the data). */ + + if (TARGET_GP_OPT) + asm_out_file = asm_out_data_file; +} diff --git a/gcc-1.40/config/out-ns32k.c b/gcc-1.40/config/out-ns32k.c new file mode 100644 index 0000000..e3df4fe --- /dev/null +++ b/gcc-1.40/config/out-ns32k.c @@ -0,0 +1,575 @@ +/* Subroutines for assembler code output on the NS32000. + Copyright (C) 1988 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 1, 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. */ + +/* Some output-actions in ns32k.md need these. */ +#include +extern FILE *asm_out_file; + +#define FP_REG_P(X) (GET_CODE (X) == REG && REGNO (X) > 7 && REGNO (X) < 16) + +/* Generate the rtx that comes from an address expression in the md file */ +/* The expression to be build is BASE[INDEX:SCALE]. To recognize this, + scale must be converted from an exponent (from ASHIFT) to a + muliplier (for MULT). */ +rtx +gen_indexed_expr (base, index, scale) + rtx base, index, scale; +{ + rtx addr; + + /* This generates an illegal addressing mode, if BASE is + fp or sp. This is handled by PRINT_OPERAND_ADDRESS. */ + if (GET_CODE (base) != REG && GET_CODE (base) != CONST_INT) + base = gen_rtx (MEM, SImode, base); + addr = gen_rtx (MULT, SImode, index, + gen_rtx (CONST_INT, VOIDmode, 1 << INTVAL (scale))); + addr = gen_rtx (PLUS, SImode, base, addr); + return addr; +} + +/* Return 1 if OP is a valid constant int. These can be modeless + (void mode), so we do not mess with their modes. + + The main use of this function is as a predicate in match_operand + expressions in the machine description. */ + +int +const_int (op, mode) + register rtx op; + enum machine_mode mode; +{ + return (GET_CODE (op) == CONST_INT); +} + +/* Return 1 if OP is a valid operand of mode MODE. This + predicate rejects operands which do not have a mode + (such as CONST_INT which are VOIDmode). */ +int +reg_or_mem_operand (op, mode) + register rtx op; + enum machine_mode mode; +{ + return (GET_MODE (op) == mode + && (GET_CODE (op) == REG + || GET_CODE (op) == SUBREG + || GET_CODE (op) == MEM)); +} + +/* Return the best assembler insn template + for moving operands[1] into operands[0] as a fullword. */ + +static char * +singlemove_string (operands) + rtx *operands; +{ + if (GET_CODE (operands[1]) == CONST_INT + && INTVAL (operands[1]) <= 7 + && INTVAL (operands[1]) >= -8) + return "movqd %1,%0"; + return "movd %1,%0"; +} + +char * +output_move_double (operands) + rtx *operands; +{ + enum anon1 { REGOP, OFFSOP, POPOP, CNSTOP, RNDOP } optype0, optype1; + rtx latehalf[2]; + + /* First classify both operands. */ + + if (REG_P (operands[0])) + optype0 = REGOP; + else if (offsettable_memref_p (operands[0])) + optype0 = OFFSOP; + else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC) + optype0 = POPOP; + else + optype0 = RNDOP; + + if (REG_P (operands[1])) + optype1 = REGOP; + else if (CONSTANT_ADDRESS_P (operands[1]) + || GET_CODE (operands[1]) == CONST_DOUBLE) + optype1 = CNSTOP; + else if (offsettable_memref_p (operands[1])) + optype1 = OFFSOP; + else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC) + optype1 = POPOP; + 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) + abort (); + + /* Ok, we can do one word at a time. + Normally we do the low-numbered word first, + but if either operand is autodecrementing then we + do the high-numbered word first. + + In either case, set up in LATEHALF the operands to use + for the high-numbered 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 (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); + else if (optype1 == OFFSOP) + latehalf[1] = adj_offsettable_operand (operands[1], 4); + else if (optype1 == CNSTOP) + { + if (CONSTANT_ADDRESS_P (operands[1])) + latehalf[1] = const0_rtx; + else if (GET_CODE (operands[1]) == CONST_DOUBLE) + { + latehalf[1] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_HIGH (operands[1])); + operands[1] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_LOW (operands[1])); + } + } + else + latehalf[1] = operands[1]; + + /* If one or both operands autodecrementing, + do the two words, high-numbered first. */ + + if (optype0 == POPOP || optype1 == POPOP) + { + output_asm_insn (singlemove_string (latehalf), latehalf); + return singlemove_string (operands); + } + + /* Not autodecrementing. Do the two words, low-numbered first. */ + + output_asm_insn (singlemove_string (operands), operands); + + operands[0] = latehalf[0]; + operands[1] = latehalf[1]; + return singlemove_string (operands); +} + +int +check_reg (oper, reg) + rtx oper; + int reg; +{ + register int i; + + if (oper == 0) + return 0; + switch (GET_CODE(oper)) + { + case REG: + return (REGNO(oper) == reg) ? 1 : 0; + case MEM: + return check_reg(XEXP(oper, 0), reg); + case PLUS: + case MULT: + return check_reg(XEXP(oper, 0), reg) || check_reg(XEXP(oper, 1), reg); + } + return 0; +} + +/* PRINT_OPERAND_ADDRESS is defined to call this function, + which is easier to debug than putting all the code in + a macro definition in tm-ns32k.h . */ + +/* Nonzero if we have printed a base register. + If zero, on some systems, it means `(sb)' must be printed. */ +int paren_base_reg_printed = 0; + +print_operand_address (file, addr) + register FILE *file; + register rtx addr; +{ + register rtx reg1, reg2, breg, ireg; + rtx offset; + static char scales[] = { 'b', 'w', 'd', 0, 'q', }; + + retry: + switch (GET_CODE (addr)) + { + case MEM: + addr = XEXP (addr, 0); + if (GET_CODE (addr) == REG) + if (REGNO (addr) == STACK_POINTER_REGNUM) + { fprintf (file, "tos"); break; } + else + { fprintf (file, "%s", reg_names[REGNO (addr)]); break; } + else if (CONSTANT_P (addr)) + { output_addr_const (file, addr); break; } + else if (GET_CODE (addr) == MULT) + { fprintf (file, "@0"); ireg = addr; goto print_index; } + else if (GET_CODE (addr) == MEM) + { + addr = XEXP (addr, 0); + if (GET_CODE (addr) == PLUS) + { + offset = XEXP (addr, 1); + addr = XEXP (addr, 0); + } + else + { + offset = const0_rtx; + } + output_addr_const (file, offset); + fprintf (file, "(%s)", reg_names[REGNO (addr)]); + break; + } + + if (GET_CODE (addr) != PLUS) + abort (); + + goto retry; + + case REG: + if (REGNO (addr) == STACK_POINTER_REGNUM) + fprintf (file, "tos"); + else + fprintf (file, "0(%s)", reg_names[REGNO (addr)]); + break; + + case PRE_DEC: + case POST_INC: + fprintf (file, "tos"); + break; + + case MULT: + fprintf (file, "@0"); + ireg = addr; /* [rX:Y] */ + goto print_index; + break; + + case PLUS: + reg1 = 0; reg2 = 0; + ireg = 0; breg = 0; + offset = const0_rtx; + if (CONSTANT_ADDRESS_P (XEXP (addr, 0))) + { + offset = XEXP (addr, 0); + addr = XEXP (addr, 1); + } + else if (CONSTANT_ADDRESS_P (XEXP (addr, 1))) + { + offset = XEXP (addr, 1); + addr = XEXP (addr, 0); + } + if (GET_CODE (addr) != PLUS) ; + else if (GET_CODE (XEXP (addr, 0)) == MULT) + { + reg1 = XEXP (addr, 0); + addr = XEXP (addr, 1); + } + else if (GET_CODE (XEXP (addr, 1)) == MULT) + { + reg1 = XEXP (addr, 1); + addr = XEXP (addr, 0); + } + /* The case for memory is somewhat tricky: to get + a MEM here, the only RTX formats that could + get here are either (modulo commutativity) + (PLUS (PLUS (REG *MEM)) CONST) -or- + (PLUS (PLUS (CONST REG/MULT)) *MEM) + We take advantage of that knowledge here. */ + else if (GET_CODE (XEXP (addr, 0)) == MEM + || GET_CODE (XEXP (addr, 1)) == MEM) + { + rtx temp; + + if (GET_CODE (XEXP (addr, 0)) == MEM) + { + temp = XEXP (addr, 1); + addr = XEXP (addr, 0); + } + else + { + temp = XEXP (addr, 0); + addr = XEXP (addr, 1); + } + + if (GET_CODE (temp) == REG) + { + reg1 = temp; + } + else + { + if (GET_CODE (temp) != PLUS) + abort (); + + if (GET_CODE (XEXP (temp, 0)) == MULT) + { + reg1 = XEXP (temp, 0); + offset = XEXP (temp, 1); + } + if (GET_CODE (XEXP (temp, 1)) == MULT) + { + reg1 = XEXP (temp, 1); + offset = XEXP (temp, 0); + } + else + abort (); + } + } + else if (GET_CODE (XEXP (addr, 0)) == REG + || GET_CODE (XEXP (addr, 1)) == REG) + { + rtx temp; + + if (GET_CODE (XEXP (addr, 0)) == REG) + { + temp = XEXP (addr, 0); + addr = XEXP (addr, 1); + } + else + { + temp = XEXP (addr, 1); + addr = XEXP (addr, 0); + } + + if (GET_CODE (addr) == REG) + { + if (REGNO (temp) >= FRAME_POINTER_REGNUM) + { reg1 = addr; addr = temp; } + else + { reg1 = temp; } + } + else if (CONSTANT_P (addr)) + { + if (GET_CODE (offset) == CONST_INT + && INTVAL (offset)) + offset = plus_constant (addr, INTVAL (offset)); + addr = temp; + } + else if (GET_CODE (addr) != PLUS) + abort (); + else + { + if (CONSTANT_ADDRESS_P (XEXP (addr, 0))) + { + offset = XEXP (addr, 0); + addr = XEXP (addr, 1); + } + else if (CONSTANT_ADDRESS_P (XEXP (addr, 1))) + { + offset = XEXP (addr, 1); + addr = XEXP (addr, 0); + } + else abort (); + + if (GET_CODE (addr) == REG) + { + if (REGNO (temp) >= FRAME_POINTER_REGNUM) + { reg1 = addr; addr = temp; } + else + { reg1 = temp; } + } + else + reg1 = temp; + } + } + + if (GET_CODE (addr) == REG || GET_CODE (addr) == MULT) + { if (reg1 == 0) reg1 = addr; else reg2 = addr; addr = 0; } + if (addr != 0) + { + if (CONSTANT_P (addr) && reg1) + { + /* OFFSET comes second, to prevent outputting + operands of the form INT+SYMBOL+INT. + The Genix assembler dies on them. */ + output_addr_const (file, addr); + if (offset != const0_rtx) + { + putc ('+', file); + output_addr_const (file, offset); + } + ireg = reg1; + goto print_index; + } + else if (GET_CODE (addr) != MEM) + abort (); + + output_addr_const (file, offset); +#ifndef SEQUENT_ADDRESS_BUG + putc ('(', file); + paren_base_reg_printed = 0; + output_address (addr); +#ifdef SEQUENT_BASE_REGS + if (!paren_base_reg_printed) + fprintf (file, "(sb)"); +#endif + putc (')', file); +#else /* SEQUENT_ADDRESS_BUG */ + if ((GET_CODE (offset) == SYMBOL_REF + || GET_CODE (offset) == CONST) + && GET_CODE (addr) == REG) + { + if (reg1) abort (); + fprintf (file, "[%s:b]", reg_names[REGNO (addr)]); + } + else + { + putc ('(', file); + paren_base_reg_printed = 0; + output_address (addr); +#ifdef SEQUENT_BASE_REGS + if (!paren_base_reg_printed) + fprintf (file, "(sb)"); +#endif + putc (')', file); + } +#endif /* SEQUENT_ADDRESS_BUG */ + ireg = reg1; + goto print_index; + } + else addr = offset; + if (reg1 && GET_CODE (reg1) == MULT) + { breg = reg2; ireg = reg1; } + else if (reg2 && GET_CODE (reg2) == MULT) + { breg = reg1; ireg = reg2; } + else if (reg2 || GET_CODE (addr) == MEM) + { breg = reg2; ireg = reg1; } + else + { breg = reg1; ireg = reg2; } + if (ireg != 0 && breg == 0 && GET_CODE (addr) == LABEL_REF) + { + int scale; + if (GET_CODE (ireg) == MULT) + { + scale = INTVAL (XEXP (ireg, 1)) >> 1; + ireg = XEXP (ireg, 0); + } + else scale = 0; + output_asm_label (addr); + fprintf (file, "[%s:%c]", + reg_names[REGNO (ireg)], scales[scale]); + break; + } + if (ireg && breg && offset == const0_rtx) + fprintf (file, "0(%s)", reg_names[REGNO (breg)]); + else + { + if (addr != 0) + { + if (ireg != 0 && breg == 0 + && GET_CODE (offset) == CONST_INT) putc('@', file); + output_addr_const (file, offset); + } + if (breg != 0) + { + if (GET_CODE (breg) != REG) abort (); +#ifndef SEQUENT_ADDRESS_BUG + fprintf (file, "(%s)", reg_names[REGNO (breg)]); + paren_base_reg_printed = -1; +#else + if (GET_CODE (offset) == SYMBOL_REF || GET_CODE (offset) == CONST) + { + if (ireg) abort (); + fprintf (file, "[%s:b]", reg_names[REGNO (breg)]); + } + else + { + fprintf (file, "(%s)", reg_names[REGNO (breg)]); + paren_base_reg_printed = -1; + } +#endif + } + } + print_index: + if (ireg != 0) + { + int scale; + if (GET_CODE (ireg) == MULT) + { + scale = INTVAL (XEXP (ireg, 1)) >> 1; + ireg = XEXP (ireg, 0); + } + else scale = 0; + if (GET_CODE (ireg) != REG) abort (); + fprintf (file, "[%s:%c]", + reg_names[REGNO (ireg)], + scales[scale]); + } + break; + default: + output_addr_const (file, addr); + } +} + +/* National 32032 shifting is so bad that we can get + better performance in many common cases by using other + techniques. */ +char * +output_shift_insn (operands) + rtx *operands; +{ + if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) > 0 + && INTVAL (operands[2]) <= 3) + if (GET_CODE (operands[0]) == REG) + { + if (GET_CODE (operands[1]) == REG) + { + if (REGNO (operands[0]) == REGNO (operands[1])) + { + if (operands[2] == const1_rtx) + return "addd %0,%0"; + else if (INTVAL (operands[2]) == 2) + return "addd %0,%0\n\taddd %0,%0"; + } + if (operands[2] == const1_rtx) + return "movd %1,%0\n\taddd %0,%0"; + + operands[1] = gen_indexed_expr (const0_rtx, operands[1], operands[2]); + return "addr %a1,%0"; + } + if (operands[2] == const1_rtx) + return "movd %1,%0\n\taddd %0,%0"; + } + else if (GET_CODE (operands[1]) == REG) + { + operands[1] = gen_indexed_expr (const0_rtx, operands[1], operands[2]); + return "addr %a1,%0"; + } + else if (INTVAL (operands[2]) == 1 + && GET_CODE (operands[1]) == MEM + && rtx_equal_p (operands [0], operands[1])) + { + rtx temp = XEXP (operands[1], 0); + + if (GET_CODE (temp) == REG + || (GET_CODE (temp) == PLUS + && GET_CODE (XEXP (temp, 0)) == REG + && GET_CODE (XEXP (temp, 1)) == CONST_INT)) + return "addd %0,%0"; + } + else return "ashd %2,%0"; + return "ashd %2,%0"; +} diff --git a/gcc-1.40/config/out-pyr.c b/gcc-1.40/config/out-pyr.c new file mode 100644 index 0000000..c6e85a8 --- /dev/null +++ b/gcc-1.40/config/out-pyr.c @@ -0,0 +1,849 @@ +/* Subroutines for insn-output.c for Pyramid 90 Series. + Copyright (C) 1989 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 1, 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. */ + +/* Some output-actions in pyr.md need these. */ +#include + +extern FILE *asm_out_file; +#include "tree.h" + +/* + * Do FUNCTION_ARG. + * This cannot be defined as a macro on pyramids, because Pyramid Technology's + * C compiler dies on (several equivalent definitions of) this macro. + * The only way around this cc bug was to make this a function. + * While it would be possible to use a macro version for gcc, it seems + * more reliable to have a single version of the code. + */ +void * +pyr_function_arg(cum, mode, type, named) + CUMULATIVE_ARGS cum; + enum machine_mode mode; + tree type; +{ + return (void *)(FUNCTION_ARG_HELPER (cum, mode,type,named)); +} + +/* Do the hard part of PARAM_SAFE_FOR_REG_P. + * This cannot be defined as a macro on pyramids, because Pyramid Technology's + * C compiler dies on (several equivalent definitions of) this macro. + * The only way around this cc bug was to make this a function. + */ +int +inner_param_safe_helper (type) + tree type; +{ + return (INNER_PARAM_SAFE_HELPER(type)); +} + + +/* Return 1 if OP is a non-indexed operand of mode MODE. + This is either a register reference, a memory reference, + or a constant. In the case of a memory reference, the address + is checked to make sure it isn't indexed. + + Register and memory references must have mode MODE in order to be valid, + but some constants have no machine mode and are valid for any mode. + + If MODE is VOIDmode, OP is checked for validity for whatever mode + it has. + + The main use of this function is as a predicate in match_operand + expressions in the machine description. + + It is useful to compare this with general_operand(). They should + be identical except for one line. + + This function seems necessary because of the non-orthogonality of + Pyramid insns. + For any 2-operand insn, and any combination of operand modes, + if indexing is valid for the isn's second operand, it is invalid + for the first operand to be indexed. */ + +extern int volatile_ok; + +int +nonindexed_operand(op, mode) + register rtx op; + enum machine_mode mode; +{ + register RTX_CODE code = GET_CODE (op); + int mode_altering_drug = 0; + + if (mode == VOIDmode) + mode = GET_MODE (op); + + if (CONSTANT_P (op)) + return ((GET_MODE (op) == VOIDmode || GET_MODE (op) == mode) + && LEGITIMATE_CONSTANT_P (op)); + + /* Except for certain constants with VOIDmode, already checked for, + OP's mode must match MODE if MODE specifies a mode. */ + + if (GET_MODE (op) != mode) + return 0; + + while (code == SUBREG) + { + op = SUBREG_REG (op); + code = GET_CODE (op); +#if 0 + /* No longer needed, since (SUBREG (MEM...)) + will load the MEM into a reload reg in the MEM's own mode. */ + mode_altering_drug = 1; +#endif + } + if (code == REG) + return 1; + if (code == CONST_DOUBLE) + return LEGITIMATE_CONSTANT_P (op); + if (code == MEM) + { + register rtx y = XEXP (op, 0); + if (! volatile_ok && MEM_VOLATILE_P (op)) + return 0; + GO_IF_NONINDEXED_ADDRESS (y, win); + } + return 0; + + win: + if (mode_altering_drug) + return ! mode_dependent_address_p (XEXP (op, 0)); + return 1; +} + +/* Return non-zero if the rtx OP has an immediate component. An + immediate component or additive term equal to zero is rejected + due to assembler problems. */ + +int +has_direct_base (op) + rtx op; +{ + if ((CONSTANT_ADDRESS_P (op) + && op != const0_rtx) + || (GET_CODE (op) == PLUS + && ((CONSTANT_ADDRESS_P (XEXP (op, 1)) + && XEXP (op, 1) != const0_rtx) + || (CONSTANT_ADDRESS_P (XEXP (op, 0)) + && XEXP (op, 0) != const0_rtx)))) + return 1; + + return 0; +} + +int +has_index (op) + rtx op; +{ + if (GET_CODE (op) == PLUS + && (GET_CODE (XEXP (op, 0)) == MULT + || (GET_CODE (XEXP (op, 1)) == MULT))) + return 1; + else + return 0; +} + +int swap_operands; + +/* weird_memory_memory -- return 1 if OP1 and OP2 can be compared (or + exchanged with xchw) with one instruction. If the operands need to + be swapped, set the global variable SWAP_OPERANDS. This function + silently assumes that both OP0 and OP1 are valid memory references. + */ + +int +weird_memory_memory (op0, op1) + rtx op0, op1; +{ + int ret; + int c; + RTX_CODE code0, code1; + + op0 = XEXP (op0, 0); + op1 = XEXP (op1, 0); + code0 = GET_CODE (op0); + code1 = GET_CODE (op1); + + swap_operands = 0; + + if (code1 == REG || code1 == SUBREG) + { + return 1; + } + if (code0 == REG || code0 == SUBREG) + { + swap_operands = 1; + return 1; + } + if (has_direct_base (op0) && has_direct_base (op1)) + { + if (has_index (op1)) + { + if (has_index (op0)) + return 0; + swap_operands = 1; + } + + return 1; + } + return 0; +} + +int +signed_comparison (x, mode) + rtx x; + enum machine_mode mode; +{ + return ! TRULY_UNSIGNED_COMPARE_P (GET_CODE (x)); +} + +extern rtx force_reg (); +rtx test_op0, test_op1; +enum machine_mode test_mode; + +/* Sign-extend or zero-extend constant X from FROM_MODE to TO_MODE. */ + +rtx +extend_const (x, extop, from_mode, to_mode) + rtx x; + RTX_CODE extop; + enum machine_mode from_mode, to_mode; +{ + int val; + int negative; + if (from_mode == to_mode) + return x; + if (GET_CODE (x) != CONST_INT) + abort (); + val = INTVAL (x); + negative = val & (1 << (GET_MODE_BITSIZE (from_mode) - 1)); + if (GET_MODE_BITSIZE (from_mode) == HOST_BITS_PER_INT) + abort (); + if (negative && extop == SIGN_EXTEND) + val = val | ((-1) << (GET_MODE_BITSIZE (from_mode))); + else + val = val & ~((-1) << (GET_MODE_BITSIZE (from_mode))); + if (GET_MODE_BITSIZE (to_mode) == HOST_BITS_PER_INT) + return gen_rtx (CONST_INT, VOIDmode, val); + return gen_rtx (CONST_INT, VOIDmode, + val & ~((-1) << (GET_MODE_BITSIZE (to_mode)))); +} + +rtx +ensure_extended (op, extop, from_mode) + rtx op; + RTX_CODE extop; + enum machine_mode from_mode; +{ + if (GET_CODE (op) == CONST_INT) + return extend_const (op, extop, from_mode, SImode); + else + return force_reg (SImode, gen_rtx (extop, SImode, op)); +} + +/* Emit rtl for a branch, as well as any delayed (integer) compare insns. + The compare insn to perform is determined by the global variables + test_op0 and test_op1. */ + +void +extend_and_branch (extop) + RTX_CODE extop; +{ + rtx op0, op1; + RTX_CODE code0, code1; + + op0 = test_op0, op1 = test_op1; + if (op0 == 0) + return; + + code0 = GET_CODE (op0); + if (op1 != 0) + code1 = GET_CODE (op1); + test_op0 = test_op1 = 0; + + if (op1 == 0) + { + op0 = ensure_extended (op0, extop, test_mode); + emit_insn (gen_rtx (SET, VOIDmode, cc0_rtx, op0)); + } + else + { + if (CONSTANT_P (op0) && CONSTANT_P (op1)) + { + op0 = ensure_extended (op0, extop, test_mode); + op1 = ensure_extended (op1, extop, test_mode); + } + else if (extop == ZERO_EXTEND && test_mode == HImode) + { + /* Pyramids have no unsigned "cmphi" instructions. We need to + zero extend unsigned halfwords into temporary registers. */ + op0 = ensure_extended (op0, extop, test_mode); + op1 = ensure_extended (op1, extop, test_mode); + } + else if (CONSTANT_P (op0)) + { + op0 = ensure_extended (op0, extop, test_mode); + op1 = ensure_extended (op1, extop, test_mode); + } + else if (CONSTANT_P (op1)) + { + op1 = ensure_extended (op1, extop, test_mode); + op0 = ensure_extended (op0, extop, test_mode); + } + else if ((code0 == REG || code0 == SUBREG) + && (code1 == REG || code1 == SUBREG)) + { + /* I could do this case without extension, by using the virtual + register address (but that would lose for global regs). */ + op0 = ensure_extended (op0, extop, test_mode); + op1 = ensure_extended (op1, extop, test_mode); + } + else if (code0 == MEM && code1 == MEM) + { + /* Load into a reg if the address combination can't be handled + directly. */ + if (! weird_memory_memory (op0, op1)) + op0 = force_reg (test_mode, op0); + } + + emit_insn (gen_rtx (SET, VOIDmode, cc0_rtx, + gen_rtx (COMPARE, VOIDmode, op0, op1))); + } +} + +/* Return non-zero if the two single-word moves with operands[0] + and operands[1] for the first single-word move, and operands[2] + and operands[3] for the second single-word move, is possible to + combine to a double word move. + + The criterion is whether the operands are in consecutive memory cells, + registers, etc. */ + +int +movdi_possible (operands) + rtx operands[]; +{ + int cnst_diff0, cnst_diff1; + RTX_CODE code0 = GET_CODE (operands[0]); + RTX_CODE code1 = GET_CODE (operands[1]); + + /* Don't dare to combine (possibly overlapping) memory -> memory moves. */ + /* It would be possible to detect the cases where we dare, by using + constant_diff (operands[0], operands[1])!!! */ + if (code0 == MEM && code1 == MEM) + return 0; + + cnst_diff0 = consecutive_operands (operands[0], operands[2]); + if (cnst_diff0 == 0) + return 0; + + cnst_diff1 = consecutive_operands (operands[1], operands[3]); + if (cnst_diff1 == 0) + return 0; + + if (cnst_diff0 & cnst_diff1) + { + /* The source and destination operands are consecutive. */ + + /* If the first move writes into the source of the second move, + we cannot combine. */ + if ((code0 == REG + && reg_overlap_mentioned_p (operands[0], operands[3])) + || (code0 == SUBREG + && subreg_overlap_mentioned_p (operands[0], operands[3]))) + return 0; + + if (cnst_diff0 & 1) + /* operands[0],[1] has higher addresses than operands[2],[3]. */ + swap_operands = 0; + else + /* operands[0],[1] has lower addresses than operands[2],[3]. */ + swap_operands = 1; + return 1; + } + return 0; +} + +/* Like reg_overlap_mentioned_p, but accepts a subreg rtx instead + of a reg. */ + +int +subreg_overlap_mentioned_p (subreg, x) + rtx subreg, x; +{ + rtx reg = SUBREG_REG (subreg); + int regno = REGNO (reg) + SUBREG_WORD (subreg); + int endregno = regno + HARD_REGNO_NREGS (regno, GET_MODE (subreg)); + return refers_to_regno_p (regno, endregno, x, 0); +} + +/* Return 1 if OP0 is a consecutive operand to OP1, 2 if OP1 is a + consecutive operand to OP0. + + This function is used to determine if addresses are consecutive, + and therefore possible to combine to fewer instructions. */ + +int +consecutive_operands (op0, op1) + rtx op0, op1; +{ + RTX_CODE code0, code1; + int cnst_diff; + int regno_off0, regno_off1; + + code0 = GET_CODE (op0); + code1 = GET_CODE (op1); + + regno_off0 = 0; + if (code0 == SUBREG) + { + if (GET_MODE_SIZE (GET_MODE (SUBREG_REG (op0))) <= UNITS_PER_WORD) + return 0; + regno_off0 = SUBREG_WORD (op0); + op0 = SUBREG_REG (op0); + code0 = REG; + } + + regno_off1 = 0; + if (code1 == SUBREG) + { + if (GET_MODE_SIZE (GET_MODE (SUBREG_REG (op1))) <= UNITS_PER_WORD) + return 0; + regno_off1 = SUBREG_WORD (op1); + op1 = SUBREG_REG (op1); + code1 = REG; + } + + if (code0 != code1) + return 0; + + switch (code0) + { + case CONST_INT: + /* Cannot permit any symbolic constants, even if the consecutive + operand is 0, since a movl really performs sign extension. */ + if (code1 != CONST_INT) + return 0; + if ((INTVAL (op0) == 0 && INTVAL (op1) == 0) + || (INTVAL (op0) == -1 && INTVAL (op1) == -1)) + return 3; + if ((INTVAL (op0) == 0 && INTVAL (op1) > 0) + || (INTVAL (op0) == -1 && INTVAL (op1) < 0)) + return 2; + if ((INTVAL (op1) == 0 && INTVAL (op0) > 0) + || (INTVAL (op1) == -1 && INTVAL (op0) < 0)) + return 1; + break; + + case REG: + regno_off0 = REGNO (op0) + regno_off0; + regno_off1 = REGNO (op1) + regno_off1; + + cnst_diff = regno_off0 - regno_off1; + if (cnst_diff == 1) + { + /* movl with the highest numbered parameter (local) register as + source or destination, doesn't wrap to the lowest numbered local + (temporary) register. */ + + if (regno_off0 % 16 != 0) + return 1; + else + return 0; + } + else if (cnst_diff == -1) + { + if (regno_off1 % 16 != 0) + return 2; + else + return 0; + } + break; + + case MEM: + op0 = XEXP (op0, 0); + op1 = XEXP (op1, 0); + if (GET_CODE (op0) == CONST) + op0 = XEXP (op0, 0); + if (GET_CODE (op1) == CONST) + op1 = XEXP (op1, 0); + + cnst_diff = constant_diff (op0, op1); + if (cnst_diff) + { + if (cnst_diff == 4) + return 1; + else if (cnst_diff == -4) + return 2; + } + break; + } + return 0; +} + +/* Return the constant difference of the rtx expressions OP0 and OP1, + or 0 if they don't have a constant difference. + + This function is used to determine if addresses are consecutive, + and therefore possible to combine to fewer instructions. */ + +int +constant_diff (op0, op1) + rtx op0, op1; +{ + RTX_CODE code0, code1; + int cnst_diff; + + code0 = GET_CODE (op0); + code1 = GET_CODE (op1); + + if (code0 != code1) + { + if (code0 == PLUS) + { + if (GET_CODE (XEXP (op0, 1)) == CONST_INT + && rtx_equal_p (op1, XEXP (op0, 0))) + return INTVAL (XEXP (op0, 1)); + } + else if (code1 == PLUS) + { + if (GET_CODE (XEXP (op1, 1)) == CONST_INT + && rtx_equal_p (op0, XEXP (op1, 0))) + return -INTVAL (XEXP (op1, 1)); + } + return 0; + } + + if (code0 == CONST_INT) + return INTVAL (op0) - INTVAL (op1); + + if (code0 == PLUS) + { + cnst_diff = constant_diff (XEXP (op0, 0), XEXP (op1, 0)); + if (cnst_diff) + return (rtx_equal_p (XEXP (op0, 1), XEXP (op1, 1))) + ? cnst_diff : 0; + cnst_diff = constant_diff (XEXP (op0, 1), XEXP (op1, 1)); + if (cnst_diff) + return (rtx_equal_p (XEXP (op0, 0), XEXP (op1, 0))) + ? cnst_diff : 0; + } + + return 0; +} + +int +already_sign_extended (insn, from_mode, op) + rtx insn; + enum machine_mode from_mode; + rtx op; +{ + rtx xinsn, xdest, xsrc; + + for (;;) + { + insn = PREV_INSN (insn); + if (insn == 0) + return 0; + if (GET_CODE (insn) == NOTE || GET_CODE (insn) == JUMP_INSN) + continue; + if (GET_CODE (insn) == CALL_INSN && ! call_used_regs[REGNO (op)]) + continue; + if (GET_CODE (insn) != INSN) + return 0; + xinsn = PATTERN (insn); + + if (GET_CODE (xinsn) != SET) + return 0; + + xdest = SET_DEST (xinsn); + xsrc = SET_SRC (xinsn); + + if (GET_CODE (xdest) == SUBREG) + abort (); + + if ( ! REG_P (xdest)) + continue; + + if (REGNO (op) == REGNO (xdest) + && ((GET_CODE (xsrc) == SIGN_EXTEND + && GET_MODE (XEXP (xsrc, 0)) == from_mode) + || (GET_CODE (xsrc) == MEM + && GET_MODE (xsrc) == from_mode))) + return 1; + + /* The register is modified by another operation. */ + if (reg_overlap_mentioned_p (xdest, op)) + return 0; + } +} + +char * +output_move_double (operands) + rtx *operands; +{ + if (GET_CODE (operands[1]) == CONST_DOUBLE) + { + if (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_INT) + { + /* In an integer, the low-order word is in CONST_DOUBLE_LOW. */ + rtx const_op = operands[1]; + if ((CONST_DOUBLE_HIGH (const_op) == 0 + && CONST_DOUBLE_LOW (const_op) >= 0) + || (CONST_DOUBLE_HIGH (const_op) == -1 + && CONST_DOUBLE_LOW (const_op) < 0)) + { + operands[1] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_LOW (const_op)); + return "movl %1,%0"; + } + operands[1] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_HIGH (const_op)); + output_asm_insn ("movw %1,%0", operands); + operands[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); + operands[1] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_LOW (const_op)); + return "movw %1,%0"; + } + else + { + /* In a real, the low-address word is in CONST_DOUBLE_LOW. */ + rtx const_op = operands[1]; + if ((CONST_DOUBLE_LOW (const_op) == 0 + && CONST_DOUBLE_HIGH (const_op) >= 0) + || (CONST_DOUBLE_LOW (const_op) == -1 + && CONST_DOUBLE_HIGH (const_op) < 0)) + { + operands[1] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_HIGH (const_op)); + return "movl %1,%0"; + } + operands[1] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_LOW (const_op)); + output_asm_insn ("movw %1,%0", operands); + operands[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); + operands[1] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_HIGH (const_op)); + return "movw %1,%0"; + } + } + + return "movl %1,%0"; +} + +/* Output a shift insns, after having reduced integer arguments to + avoid as warnings. */ + +char * +output_shift (pattern, op2, mod) + char *pattern; + rtx op2; + int mod; +{ + if (GET_CODE (op2) == CONST_INT) + { + int cnt = INTVAL (op2) % mod; + if (cnt == 0) + { + cc_status = cc_prev_status; + return ""; + } + op2 = gen_rtx (CONST_INT, VOIDmode, cnt); + } + return pattern; +} + +/* Return non-zero if the code of this rtx pattern is a relop. */ + +int +relop (op, mode) + rtx op; + enum machine_mode mode; +{ + switch (GET_CODE (op)) + { + case EQ: + case NE: + case LT: + case LE: + case GE: + case GT: + case LTU: + case LEU: + case GEU: + case GTU: + return 1; + } + return 0; +} + +void +notice_update_cc (EXP, INSN) + rtx EXP, INSN; +{ + switch (GET_CODE (EXP)) + { + case SET: + switch (GET_CODE (SET_DEST (EXP))) + { + case CC0: + cc_status.mdep = 0; + cc_status.flags = 0; + cc_status.value1 = 0; + cc_status.value2 = SET_SRC (EXP); + break; + + case PC: + break; + + case REG: + switch (GET_CODE (SET_SRC (EXP))) + { + case CALL: + goto call; + case MEM: + if (GET_MODE (SET_SRC (EXP)) == QImode + || GET_MODE (SET_SRC (EXP)) == HImode) + { + cc_status.mdep = 0; + cc_status.flags = CC_NO_OVERFLOW; + cc_status.value1 = SET_DEST (EXP); + cc_status.value2 = SET_SRC (EXP); + break; + } + /* else: Fall through. */ + case CONST_INT: + case SYMBOL_REF: + case LABEL_REF: + case CONST: + case CONST_DOUBLE: + case REG: + 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; + break; + + case UDIV: + case UMOD: + cc_status.mdep = CC_VALID_FOR_UNSIGNED; + cc_status.flags = CC_NO_OVERFLOW; + cc_status.value1 = SET_DEST (EXP); + cc_status.value2 = SET_SRC (EXP); + break; + default: + cc_status.mdep = 0; + cc_status.flags = CC_NO_OVERFLOW; + cc_status.value1 = SET_DEST (EXP); + cc_status.value2 = SET_SRC (EXP); + break; + } + break; + + case MEM: + switch (GET_CODE (SET_SRC (EXP))) + { + case REG: + if (GET_MODE (SET_SRC (EXP)) == QImode + || GET_MODE (SET_SRC (EXP)) == HImode) + { + cc_status.flags = CC_NO_OVERFLOW; + cc_status.value1 = SET_DEST (EXP); + cc_status.value2 = SET_SRC (EXP); + cc_status.mdep = 0; + break; + } + /* else: Fall through. */ + case CONST_INT: + case SYMBOL_REF: + case LABEL_REF: + case CONST: + case CONST_DOUBLE: + case MEM: + /* Need to forget cc_status about memory positions each + time a memory store is made, even if the memory store + insns in question doesn't modify the condition codes. */ + if (cc_status.value1 && + GET_CODE (cc_status.value1) == MEM) + cc_status.value1 = 0; + if (cc_status.value2 && + GET_CODE (cc_status.value2) == MEM) + cc_status.value2 = 0; + break; + case SIGN_EXTEND: + case FLOAT_EXTEND: + case FLOAT_TRUNCATE: + case FLOAT: + case FIX: + cc_status.flags = CC_NO_OVERFLOW; + cc_status.value1 = SET_DEST (EXP); + cc_status.value2 = SET_SRC (EXP); + cc_status.mdep = 0; + break; + + default: + abort (); + } + break; + + default: + abort (); + } + break; + + case CALL: + call: + CC_STATUS_INIT; + break; + /* Do calls preserve the condition codes? (At least forget + cc_status expressions if they refer to registers + not preserved across calls. Also forget expressions + about memory contents.) */ + if (cc_status.value1 + && (refers_to_regno_p (PYR_TREG (0), PYR_TREG (15), + cc_status.value1, 0) + || GET_CODE (cc_status.value1) == MEM)) + cc_status.value1 = 0; + if (cc_status.value2 + && (refers_to_regno_p (PYR_TREG (0), PYR_TREG (15), + cc_status.value2, 0) + || GET_CODE (cc_status.value2) == MEM)) + cc_status.value2 = 0; + break; + + default: + CC_STATUS_INIT; + } +} + +void +forget_cc_if_dependent (op) + rtx op; +{ + cc_status = cc_prev_status; + if (cc_status.value1 && reg_overlap_mentioned_p (op, cc_status.value1)) + cc_status.value1 = 0; + if (cc_status.value2 && reg_overlap_mentioned_p (op, cc_status.value2)) + cc_status.value2 = 0; +} diff --git a/gcc-1.40/config/out-sparc.c b/gcc-1.40/config/out-sparc.c new file mode 100644 index 0000000..d180b1f --- /dev/null +++ b/gcc-1.40/config/out-sparc.c @@ -0,0 +1,2092 @@ +/* Subroutines for insn-output.c for Sun SPARC. + Copyright (C) 1987, 1988, 1989 Free Software Foundation, Inc. + Contributed by Michael Tiemann (tiemann@mcc.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 1, 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. */ + +/* Global variables for machine-dependend things. */ + +/* This should go away if we pass floats to regs via + the stack instead of the frame, and if we learn how + to renumber all the registers when we don't do a save (hard!). */ +extern int frame_pointer_needed; + +static rtx find_addr_reg (); + +rtx next_real_insn_no_labels (); + +/* Return non-zero only if OP is a register of mode MODE, + or const0_rtx. */ +int +reg_or_0_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + return (op == const0_rtx || register_operand (op, mode)); +} + +/* Return non-zero if INSN is a conditional insn with a predicate + valid after an addcc or subcc instruction. */ + +int +ignore_overflow_conditional_p (insn) + rtx insn; +{ + rtx x = SET_SRC (PATTERN (insn)); + RTX_CODE code; + if (GET_CODE (x) == IF_THEN_ELSE) + x = XEXP (x, 0); + code = GET_CODE (x); + return code == EQ || code == NE || code == GE || code == LT; +} + +/* Return non-zero if this pattern, can be evaluated safely, even if it + was not asked for. */ +int +safe_insn_src_p (op, mode) + rtx op; + enum machine_mode mode; +{ + /* Just experimenting. */ + + /* No floating point src is safe if it contains an arithmetic + operation, since that operation may trap. */ + switch (GET_CODE (op)) + { + case CONST_INT: + case LABEL_REF: + case SYMBOL_REF: + case CONST: + return 1; + + case REG: + return 1; + + case MEM: + return CONSTANT_ADDRESS_P (XEXP (op, 0)); + + /* We never need to negate or complement constants. */ + case NEG: + return (mode != SFmode && mode != DFmode); + case NOT: + return 1; + + case COMPARE: + case MINUS: + case PLUS: + return (mode != SFmode && mode != DFmode); + case AND: + case IOR: + case XOR: + case LSHIFT: + case ASHIFT: + case ASHIFTRT: + case LSHIFTRT: + if ((GET_CODE (XEXP (op, 0)) == CONST_INT && ! SMALL_INT (XEXP (op, 0))) + || (GET_CODE (XEXP (op, 1)) == CONST_INT && ! SMALL_INT (XEXP (op, 1)))) + return 0; + return 1; + + default: + return 0; + } +} + +/* Return 1 if REG is clobbered in IN. + Return 0 if REG is used in IN (other than being clobbered). + Return 2 if REG does not appear in IN. */ + +static int +reg_clobbered_p (reg, in) + rtx reg; + rtx in; +{ + register char *fmt; + register int i, result = 0; + + register enum rtx_code code; + + if (in == 0) + return 2; + + code = GET_CODE (in); + + switch (code) + { + /* Let these fail out quickly. */ + case CONST_INT: + case SYMBOL_REF: + case CONST: + return 2; + + case SUBREG: + if (SUBREG_WORD (in) != 0) + in = gen_rtx (REG, SImode, REGNO (SUBREG_REG (in)) + SUBREG_WORD (in)); + else + in = SUBREG_REG (in); + + case REG: + if (in == reg + || refers_to_regno_p (REGNO (reg), + REGNO (reg) + HARD_REGNO_NREGS (reg, GET_MODE (reg)), + in, 0)) + return 0; + return 2; + + case SET: + if (SET_SRC (in) == reg + || refers_to_regno_p (REGNO (reg), + REGNO (reg) + HARD_REGNO_NREGS (reg, GET_MODE (reg)), + SET_SRC (in), 0)) + return 0; + + if (SET_DEST (in) == reg) + return 1; + + if (refers_to_regno_p (REGNO (reg), + REGNO (reg) + HARD_REGNO_NREGS (reg, GET_MODE (reg)), + SET_DEST (in), 0)) + if (GET_CODE (SET_DEST (in)) == REG + || GET_CODE (SET_DEST (in)) == SUBREG) + return 1; + else + return 0; + return 2; + + case USE: + if (XEXP (in, 0) == reg + || refers_to_regno_p (REGNO (reg), + REGNO (reg) + HARD_REGNO_NREGS (reg, GET_MODE (reg)), + XEXP (in, 0), 0)) + return 0; + return 2; + + case CLOBBER: + if (XEXP (in, 0) == reg) + return 1; + /* If the CLOBBER expression is a SUBREG, accept that as a + clobber. But if it is some expression based on this register, + that is like a USE as far as this register is concerned, + so we won't take it. */ + if (refers_to_regno_p (REGNO (reg), + REGNO (reg) + HARD_REGNO_NREGS (reg, GET_MODE (reg)), + XEXP (in, 0), 0)) + if (GET_CODE (XEXP (in, 0)) == REG + || GET_CODE (XEXP (in, 0)) == SUBREG) + return 1; + else + return 0; + return 2; + } + + fmt = GET_RTX_FORMAT (code); + + result = 2; + + for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) + { + if (fmt[i] == 'E') + { + register int j; + for (j = XVECLEN (in, i) - 1; j >= 0; j--) + switch (reg_clobbered_p (reg, XVECEXP (in, i, j))) + { + case 0: + return 0; + case 2: + continue; + case 1: + result = 1; + break; + } + } + else if (fmt[i] == 'e') + switch (reg_clobbered_p (reg, XEXP (in, i))) + { + case 0: + return 0; + case 2: + continue; + case 1: + result = 1; + break; + } + } + return result; +} + +/* Return non-zero if OP can be written to without screwing up + GCC's model of what's going on. It is assumed that this operand + appears in the dest position of a SET insn in a conditional + branch's delay slot. AFTER is the label to start looking from. */ +int +operand_clobbered_before_used_after (op, after) + rtx op; + rtx after; +{ + extern char call_used_regs[]; + + /* Just experimenting. */ + if (GET_CODE (op) == CC0) + return 1; + if (GET_CODE (op) == REG) + { + rtx insn; + + if (op == stack_pointer_rtx) + return 0; + + for (insn = NEXT_INSN (after); insn; insn = NEXT_INSN (insn)) + { + if (GET_CODE (insn) == NOTE) + continue; + if (GET_CODE (insn) == INSN + || GET_CODE (insn) == JUMP_INSN + || GET_CODE (insn) == CALL_INSN) + { + switch (reg_clobbered_p (op, PATTERN (insn))) + { + case 0: + return 0; + case 2: + break; + case 1: + return 1; + } + if (dead_or_set_p (insn, op)) + return 1; + } + else if (GET_CODE (insn) == CODE_LABEL) + return 0; + if (GET_CODE (insn) == JUMP_INSN) + { + if (condjump_p (insn)) + return 0; + /* This is a jump insn which has already + been mangled. We can't tell what it does. */ + if (GET_CODE (PATTERN (insn)) == PARALLEL) + return 0; + if (! JUMP_LABEL (insn)) + return 0; + /* Keep following jumps. */ + insn = JUMP_LABEL (insn); + } + } + return 1; + } + + /* In both of these cases, the first insn executed + for this op will be a sethi %hi(whatever),%g1, + which is tolerable. */ + if (GET_CODE (op) == MEM) + return (CONSTANT_ADDRESS_P (XEXP (op, 0))); + + return 0; +} + +/* Return non-zero if this pattern, as a source to a "SET", + is known to yield an instruction of unit size. */ +int +single_insn_src_p (op, mode) + rtx op; + enum machine_mode mode; +{ + switch (GET_CODE (op)) + { + case CONST_INT: +#if 1 + /* This is not always a single insn src, technically, + but output_delayed_branch knows how to deal with it. */ + return 1; +#else + if (SMALL_INT (op)) + return 1; + /* We can put this set insn into delay slot, because this is one + insn; 'sethi'. */ + if ((INTVAL (op) & 0x3ff) == 0) + return 1; + + /* This is not a single insn src, technically, + but output_delayed_branch knows how to deal with it. */ + return 1; +#endif + +#if 1 + case SYMBOL_REF: + /* This is not a single insn src, technically, + but output_delayed_branch knows how to deal with it. */ + return 1; +#else + return 0; +#endif + + case REG: + return 1; + + case MEM: +#if 0 + /* This is not a single insn src, technically, + but output_delayed_branch knows how to deal with it. */ + if (GET_CODE (XEXP (op, 0)) == SYMBOL_REF) + return 0; +#endif + return 1; + + /* We never need to negate or complement constants. */ + case NEG: + return (mode != DFmode); + case NOT: + return 1; + + case COMPARE: + case MINUS: + /* If the target is cc0, then these insns will take + two insns (one being a nop). */ + return (mode != SFmode && mode != DFmode); + case PLUS: + case AND: + case IOR: + case XOR: + case LSHIFT: + case ASHIFT: + case ASHIFTRT: + case LSHIFTRT: + if ((GET_CODE (XEXP (op, 0)) == CONST_INT && ! SMALL_INT (XEXP (op, 0))) + || (GET_CODE (XEXP (op, 1)) == CONST_INT && ! SMALL_INT (XEXP (op, 1)))) + return 0; + return 1; + + case SUBREG: + if (SUBREG_WORD (op) != 0) + return 0; + return single_insn_src_p (SUBREG_REG (op), mode); + + case SIGN_EXTEND: + case ZERO_EXTEND: + /* Lazy... could check for more cases. */ + if (GET_CODE (XEXP (op, 0)) == MEM + && ! CONSTANT_ADDRESS_P (XEXP (XEXP (op, 0), 0))) + return 1; + return 0; + + /* Not doing floating point, since they probably + take longer than the branch slot they might fill. */ + case FLOAT_EXTEND: + case FLOAT_TRUNCATE: + case FLOAT: + case FIX: + case UNSIGNED_FLOAT: + case UNSIGNED_FIX: + return 0; + + default: + return 0; + } +} + +/* This extra test must be done to verify that a move insn + really is just one assembler insn. */ + +int +single_insn_extra_test (dest, src) + rtx dest, src; +{ + /* Moves between FP regs and CPU regs are two insns. */ + return (!(GET_CODE (src) == REG + && GET_CODE (dest) == REG + && (FP_REG_P (src) != FP_REG_P (dest)))); +} + +/* Nonzero only if this *really* is a single insn operand. */ +int +strict_single_insn_op_p (op, mode) + rtx op; + enum machine_mode mode; +{ + if (mode == VOIDmode) + mode = GET_MODE (op); + + switch (GET_CODE (op)) + { + case CC0: + return 1; + + case CONST_INT: + if (SMALL_INT (op)) + return 1; + /* We can put this set insn into delay slot, because this is one + insn; 'sethi'. */ + if ((INTVAL (op) & 0x3ff) == 0) + return 1; + return 0; + + case SYMBOL_REF: + return 0; + + case REG: + return (mode != DFmode && mode != DImode); + + case MEM: + if (! CONSTANT_ADDRESS_P (XEXP (op, 0))) + return (mode != DFmode && mode != DImode); + return 0; + + /* We never need to negate or complement constants. */ + case NEG: + return (mode != DFmode); + case NOT: + return 1; + + case COMPARE: + case MINUS: + /* If the target is cc0, then these insns will take + two insns (one being a nop). */ + return (mode != SFmode && mode != DFmode); + case PLUS: + case AND: + case IOR: + case XOR: + case LSHIFT: + case ASHIFT: + case ASHIFTRT: + case LSHIFTRT: + if ((GET_CODE (XEXP (op, 0)) == CONST_INT && ! SMALL_INT (XEXP (op, 0))) + || (GET_CODE (XEXP (op, 1)) == CONST_INT && ! SMALL_INT (XEXP (op, 1)))) + return 0; + return 1; + + case SUBREG: + if (SUBREG_WORD (op) != 0) + return 0; + return strict_single_insn_op_p (SUBREG_REG (op), mode); + + case SIGN_EXTEND: + case ZERO_EXTEND: + if (GET_CODE (XEXP (op, 0)) == MEM + && ! CONSTANT_ADDRESS_P (XEXP (XEXP (op, 0), 0))) + return 1; + return 0; + + /* Not doing floating point, since they probably + take longer than the branch slot they might fill. */ + case FLOAT_EXTEND: + case FLOAT_TRUNCATE: + case FLOAT: + case FIX: + case UNSIGNED_FLOAT: + case UNSIGNED_FIX: + return 0; + + default: + return 0; + } +} + +/* Return truth value of whether OP is a relational operator. */ +int +relop (op, mode) + rtx op; + enum machine_mode mode; +{ + switch (GET_CODE (op)) + { + case EQ: + case NE: + case GT: + case GE: + case LT: + case LE: + case GTU: + case GEU: + case LTU: + case LEU: + return 1; + } + return 0; +} + +/* Return truth value of wheterh OP is EQ or NE. */ +int +eq_or_neq (op, mode) + rtx op; + enum machine_mode mode; +{ + return (GET_CODE (op) == EQ || GET_CODE (op) == NE); +} + +/* Return truth value of whether OP can be used as an operands in a three + address arithmetic insn (such as add %o1,7,%l2) of mode MODE. */ + +int +arith_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + return (register_operand (op, mode) + || (GET_CODE (op) == CONST_INT && SMALL_INT (op))); +} + +/* Return truth value of whether OP can be used as an operand in a two + address arithmetic insn (such as set 123456,%o4) of mode MODE. */ + +int +arith32_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + return (register_operand (op, mode) || GET_CODE (op) == CONST_INT); +} + +/* Return truth value of whether OP is a integer which fits the + range constraining immediate operands in three-address insns. */ + +int +small_int (op, mode) + rtx op; + enum machine_mode mode; +{ + return (GET_CODE (op) == CONST_INT && SMALL_INT (op)); +} + +/* Return the best assembler insn template + for moving operands[1] into operands[0] as a fullword. */ + +static char * +singlemove_string (operands) + rtx *operands; +{ + if (GET_CODE (operands[0]) == MEM) + { + if (GET_CODE (operands[1]) != MEM) + if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) + { + if (! ((cc_prev_status.flags & CC_KNOW_HI_G1) + && cc_prev_status.mdep == XEXP (operands[0], 0))) + output_asm_insn ("sethi %%hi(%m0),%%g1", operands); + cc_status.flags |= CC_KNOW_HI_G1; + cc_status.mdep = XEXP (operands[0], 0); + return "st %1,[%%lo(%m0)+%%g1]"; + } + else + return "st %r1,%0"; + else + { + rtx xoperands[2]; + + cc_status.flags &= ~CC_F0_IS_0; + xoperands[0] = gen_rtx (REG, SFmode, 32); + xoperands[1] = operands[1]; + output_asm_insn (singlemove_string (xoperands), xoperands); + xoperands[1] = xoperands[0]; + xoperands[0] = operands[0]; + output_asm_insn (singlemove_string (xoperands), xoperands); + return ""; + } + } + if (GET_CODE (operands[1]) == MEM) + { + if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) + { + if (! ((cc_prev_status.flags & CC_KNOW_HI_G1) + && cc_prev_status.mdep == XEXP (operands[1], 0))) + output_asm_insn ("sethi %%hi(%m1),%%g1", operands); + cc_status.flags |= CC_KNOW_HI_G1; + cc_status.mdep = XEXP (operands[1], 0); + return "ld [%%lo(%m1)+%%g1],%0"; + } + return "ld %1,%0"; + } + return "mov %1,%0"; +} + +/* Output assembler code to perform a doubleword move insn + with operands OPERANDS. */ + +char * +output_move_double (operands) + rtx *operands; +{ + enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1; + rtx latehalf[2]; + rtx addreg0 = 0, addreg1 = 0; + + /* First classify both operands. */ + + if (REG_P (operands[0])) + optype0 = REGOP; + else if (offsettable_memref_p (operands[0])) + optype0 = OFFSOP; + else if (GET_CODE (operands[0]) == MEM) + optype0 = MEMOP; + else + optype0 = RNDOP; + + if (REG_P (operands[1])) + optype1 = REGOP; + else if (CONSTANT_P (operands[1]) + || GET_CODE (operands[1]) == CONST_DOUBLE) + optype1 = CNSTOP; + else if (offsettable_memref_p (operands[1])) + optype1 = OFFSOP; + else if (GET_CODE (operands[1]) == 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) + 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 (operands[0], 0)); + + if (optype1 == MEMOP) + addreg1 = find_addr_reg (XEXP (operands[1], 0)); + + /* Ok, we can do one word at a time. + Normally we do the low-numbered word first, + but if either operand is autodecrementing then we + do the high-numbered word first. + + In either case, set up in LATEHALF the operands to use + for the high-numbered 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 (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); + else if (optype1 == OFFSOP) + latehalf[1] = adj_offsettable_operand (operands[1], 4); + else if (optype1 == CNSTOP) + { + if (CONSTANT_P (operands[1])) + latehalf[1] = const0_rtx; + else if (GET_CODE (operands[1]) == CONST_DOUBLE) + { + latehalf[1] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_HIGH (operands[1])); + operands[1] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_LOW (operands[1])); + } + } + else + latehalf[1] = operands[1]; + + /* If the first move would clobber the source of the second one, + do them in the other order. + + RMS says "This happens only for registers; + such overlap can't happen in memory unless the user explicitly + sets it up, and that is an undefined circumstance." + + but it happens on the sparc when loading parameter registers, + so I am going to define that circumstance, and make it work + as expected. */ + + /* Easy case: try moving both words at once. */ + /* First check for moving between an even/odd register pair + and a memory location. */ + if ((optype0 == REGOP && optype1 != REGOP && optype1 != CNSTOP + && (REGNO (operands[0]) & 1) == 0) + || (optype0 != REGOP && optype1 != CNSTOP && optype1 == REGOP + && (REGNO (operands[1]) & 1) == 0)) + { + rtx op1, op2; + rtx base = 0, offset = const0_rtx; + + /* OP1 gets the register pair, and OP2 gets the memory address. */ + if (optype0 == REGOP) + op1 = operands[0], op2 = XEXP (operands[1], 0); + else + op1 = operands[1], op2 = XEXP (operands[0], 0); + + /* Now see if we can trust the address to be 8-byte aligned. */ + /* Trust global variables. */ + if (CONSTANT_ADDRESS_P (op2)) + { + operands[0] = op1; + operands[1] = op2; + if (! ((cc_prev_status.flags & CC_KNOW_HI_G1) + && cc_prev_status.mdep == op2)) + output_asm_insn ("sethi %%hi(%1),%%g1", operands); + cc_status.flags |= CC_KNOW_HI_G1; + cc_status.mdep = op2; + if (op1 == operands[0]) + return "ldd [%%lo(%1)+%%g1],%0"; + else + return "std [%%lo(%1)+%%g1],%0"; + } + + if (GET_CODE (op2) == PLUS) + { + if (GET_CODE (XEXP (op2, 0)) == REG) + base = XEXP (op2, 0), offset = XEXP (op2, 1); + else if (GET_CODE (XEXP (op2, 1)) == REG) + base = XEXP (op2, 1), offset = XEXP (op2, 0); + } + + /* Trust round enough offsets from the stack or frame pointer. */ + if (base + && (REGNO (base) == FRAME_POINTER_REGNUM + || REGNO (base) == STACK_POINTER_REGNUM)) + { + if (GET_CODE (offset) == CONST_INT + && (INTVAL (offset) & 0x7) == 0) + { + if (op1 == operands[0]) + return "ldd %1,%0"; + else + return "std %1,%0"; + } + } + else + { + /* We know structs not on the stack are properly aligned. + Since a double asks for 8-byte alignment, + we know it must have got that if it is in a struct. + But a DImode need not be 8-byte aligned, because it could be a + struct containing two ints or pointers. */ + + /* Sun fucks us here. We cannot trust references + to doubles via varying addresses. It might be on the stack + even if we don't know that it is; and then it might not be + double-word aligned. */ +#if 0 + if (GET_CODE (operands[1]) == MEM && GET_MODE (operands[1]) == DFmode + && MEM_IN_STRUCT_P (operands[1])) + return "ldd %1,%0"; + else if (GET_CODE (operands[0]) == MEM + && GET_MODE (operands[0]) == DFmode + && MEM_IN_STRUCT_P (operands[0])) + return "std %1,%0"; +#endif + } + } + + if (optype0 == REGOP && optype1 == REGOP + && REGNO (operands[0]) == REGNO (latehalf[1])) + { + /* 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) + output_asm_insn ("add %0,-0x4,%0", &addreg0); + + /* Do low-numbered word. */ + return singlemove_string (operands); + } + else if (optype0 == REGOP && optype1 != REGOP + && reg_overlap_mentioned_p (operands[0], operands[1])) + { + /* Do the late half first. */ + output_asm_insn (singlemove_string (latehalf), latehalf); + /* Then clobber. */ + return singlemove_string (operands); + } + + /* Normal case: do the two words, low-numbered 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) + output_asm_insn ("add %0,-0x4,%0", &addreg1); + + return ""; +} + +static char * +output_fp_move_double (operands) + rtx *operands; +{ + if (FP_REG_P (operands[0])) + { + if (FP_REG_P (operands[1])) + { + output_asm_insn ("fmovs %1,%0", operands); + operands[0] = gen_rtx (REG, VOIDmode, REGNO (operands[0]) + 1); + operands[1] = gen_rtx (REG, VOIDmode, REGNO (operands[1]) + 1); + return "fmovs %1,%0"; + } + if (GET_CODE (operands[1]) == REG) + { + if ((REGNO (operands[1]) & 1) == 0) + return "std %1,[%%fp-8]\n\tldd [%%fp-8],%0"; + else + { + rtx xoperands[3]; + xoperands[0] = operands[0]; + xoperands[1] = operands[1]; + xoperands[2] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1); + output_asm_insn ("st %2,[%%fp-4]\n\tst %1,[%%fp-8]\n\tldd [%%fp-8],%0", xoperands); + return ""; + } + } + /* Use ldd if known to be aligned. */ + if (GET_CODE (XEXP (operands[1], 0)) == PLUS + && (((XEXP (XEXP (operands[1], 0), 0) == frame_pointer_rtx + || XEXP (XEXP (operands[1], 0), 0) == stack_pointer_rtx) + && GET_CODE (XEXP (XEXP (operands[1], 0), 1)) == CONST_INT + && (INTVAL (XEXP (XEXP (operands[1], 0), 1)) & 0x7) == 0) +#if 0 /* An array in a structure that is a parm need not be aligned! */ + /* Arrays are known to be aligned, + and reg+reg addresses are used (on this machine) + only for array accesses. */ + || (REG_P (XEXP (XEXP (operands[1], 0), 0)) + && REG_P (XEXP (XEXP (operands[1], 0), 1))) +#endif + )) + return "ldd %1,%0"; + if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) + { + if (! ((cc_prev_status.flags & CC_KNOW_HI_G1) + && cc_prev_status.mdep == XEXP (operands[1], 0))) + output_asm_insn ("sethi %%hi(%m1),%%g1", operands); + cc_status.flags |= CC_KNOW_HI_G1; + cc_status.mdep = XEXP (operands[1], 0); + return "ldd [%%lo(%m1)+%%g1],%0"; + } + /* Otherwise use two ld insns. */ + { + rtx xoperands[2]; + output_asm_insn ("ld %1,%0", operands); + xoperands[0] = gen_rtx (REG, GET_MODE (operands[0]), + REGNO (operands[0]) + 1); + if (GET_CODE (XEXP (operands[1], 0)) == PLUS + && offsettable_address_p (1, GET_MODE (operands[1]), + XEXP (operands[1], 0))) + { + xoperands[1] = adj_offsettable_operand (operands[1], 4); + output_asm_insn ("ld %1,%0", xoperands); + } + else if (GET_CODE (XEXP (operands[1], 0)) == PLUS) + { + rtx memref = operands[1]; + rtx inc_reg = XEXP (XEXP (operands[1], 0), 0); + if (inc_reg == frame_pointer_rtx + && GET_CODE (XEXP (XEXP (operands[1], 0), 1)) == REG + && XEXP (XEXP (operands[1], 0), 1) != frame_pointer_rtx) + inc_reg = XEXP (XEXP (operands[1], 0), 1); + if (inc_reg == frame_pointer_rtx) + { + output_asm_insn ("mov %%fp,%%g1", xoperands); + inc_reg = gen_rtx (REG, SImode, 1); + memref = gen_rtx (GET_CODE (operands[1]), + GET_MODE (operands[1]), + gen_rtx (PLUS, GET_MODE (XEXP (operands[1], 0)), + inc_reg, + XEXP (XEXP (operands[1], 0), 1))); + } + xoperands[1] = inc_reg; + output_asm_insn ("add 4,%1,%1", xoperands); + xoperands[1] = memref; + output_asm_insn ("ld %1,%0", xoperands); + xoperands[1] = inc_reg; + output_asm_insn ("add -4,%1,%1", xoperands); + } + else + { + xoperands[1] = gen_rtx (MEM, GET_MODE (operands[1]), + plus_constant (XEXP (operands[1], 0), 4)); + output_asm_insn ("ld %1,%0", xoperands); + } + return ""; + } + } + else if (FP_REG_P (operands[1])) + { + if (GET_CODE (operands[0]) == REG) + { + if ((REGNO (operands[0]) & 1) == 0) + return "std %1,[%%fp-8]\n\tldd [%%fp-8],%0"; + else + { + rtx xoperands[3]; + xoperands[2] = operands[1]; + xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); + xoperands[0] = operands[0]; + output_asm_insn ("std %2,[%%fp-8]\n\tld [%%fp-4],%1\n\tld [%%fp-8],%0", xoperands); + return ""; + } + } + /* Use std if we can be sure it is well-aligned. */ + if (GET_CODE (XEXP (operands[0], 0)) == PLUS + && (((XEXP (XEXP (operands[0], 0), 0) == frame_pointer_rtx + || XEXP (XEXP (operands[0], 0), 0) == stack_pointer_rtx) + && GET_CODE (XEXP (XEXP (operands[0], 0), 1)) == CONST_INT + && (INTVAL (XEXP (XEXP (operands[0], 0), 1)) & 0x7) == 0) +#if 0 /* An array in a structure that is a parm need not be aligned! */ + /* Arrays are known to be aligned, + and reg+reg addresses are used (on this machine) + only for array accesses. */ + || (REG_P (XEXP (XEXP (operands[0], 0), 0)) + && REG_P (XEXP (XEXP (operands[0], 0), 1))) +#endif + )) + return "std %1,%0"; + if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) + { + if (! ((cc_prev_status.flags & CC_KNOW_HI_G1) + && cc_prev_status.mdep == XEXP (operands[0], 0))) + output_asm_insn ("sethi %%hi(%m0),%%g1", operands); + cc_status.flags |= CC_KNOW_HI_G1; + cc_status.mdep = XEXP (operands[0], 0); + return "std %1,[%%lo(%m0)+%%g1]"; + } + /* Otherwise use two st insns. */ + { + rtx xoperands[2]; + output_asm_insn ("st %r1,%0", operands); + xoperands[1] = gen_rtx (REG, GET_MODE (operands[1]), + REGNO (operands[1]) + 1); + if (GET_CODE (XEXP (operands[0], 0)) == PLUS + && offsettable_address_p (1, GET_MODE (operands[0]), + XEXP (operands[0], 0))) + { + xoperands[0] = adj_offsettable_operand (operands[0], 4); + output_asm_insn ("st %r1,%0", xoperands); + } + else if (GET_CODE (XEXP (operands[0], 0)) == PLUS) + { + rtx memref = operands[0]; + rtx inc_reg = XEXP (XEXP (operands[0], 0), 0); + if (inc_reg == frame_pointer_rtx + && GET_CODE (XEXP (XEXP (operands[0], 0), 1)) == REG + && XEXP (XEXP (operands[0], 0), 1) != frame_pointer_rtx) + inc_reg = XEXP (XEXP (operands[0], 0), 1); + if (inc_reg == frame_pointer_rtx) + { + output_asm_insn ("mov %%fp,%%g1", xoperands); + inc_reg = gen_rtx (REG, SImode, 1); + memref = gen_rtx (GET_CODE (operands[0]), + GET_MODE (operands[0]), + gen_rtx (PLUS, GET_MODE (XEXP (operands[0], 0)), + inc_reg, + XEXP (XEXP (operands[0], 0), 1))); + } + xoperands[0] = inc_reg; + output_asm_insn ("add 4,%0,%0", xoperands); + xoperands[0] = memref; + output_asm_insn ("st %r1,%0", xoperands); + xoperands[0] = inc_reg; + output_asm_insn ("add -4,%0,%0", xoperands); + } + else + { + xoperands[0] = gen_rtx (MEM, GET_MODE (operands[0]), + plus_constant (XEXP (operands[0], 0), 4)); + output_asm_insn ("st %r1,%0", xoperands); + } + return ""; + } + } + 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) + { + if (GET_CODE (XEXP (addr, 0)) == REG + && !(GET_CODE (XEXP (addr, 1)) == REG + && XEXP (addr, 0) == frame_pointer_rtx)) + addr = XEXP (addr, 0); + else if (GET_CODE (XEXP (addr, 1)) == REG) + 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 (); +} + +void +output_sized_memop (opname, mode) + char *opname; + enum machine_mode mode; +{ + extern struct _iobuf *asm_out_file; + + static char *ld_size_suffix[] = { "ub", "uh", "", "?", "d" }; + static char *st_size_suffix[] = { "b", "h", "", "?", "d" }; + char *modename + = (opname[0] == 'l' ? ld_size_suffix : st_size_suffix)[GET_MODE_SIZE (mode) >> 1]; + + fprintf (asm_out_file, "\t%s%s", opname, modename); +} + +/* Output a store-in-memory whose operands are OPERANDS[0,1]. + OPERANDS[0] is a MEM, and OPERANDS[1] is a reg or zero. */ + +char * +output_store (operands) + rtx *operands; +{ + enum machine_mode mode = GET_MODE (operands[0]); + rtx address = XEXP (operands[0], 0); + + cc_status.flags |= CC_KNOW_HI_G1; + cc_status.mdep = address; + + if (! ((cc_prev_status.flags & CC_KNOW_HI_G1) + && address == cc_prev_status.mdep)) + { + output_asm_insn ("sethi %%hi(%m0),%%g1", operands); + cc_prev_status.mdep = address; + } + + /* Store zero in two parts when appropriate. */ + if (mode == DFmode && operands[1] == dconst0_rtx) + { + /* We can't cross a page boundary here because the + SYMBOL_REF must be double word aligned, and for this + to be the case, SYMBOL_REF+4 cannot cross. */ + output_sized_memop ("st", SImode); + output_asm_insn ("%r1,[%%g1+%%lo(%m0)]", operands); + output_sized_memop ("st", SImode); + return "%r1,[%%g1+%%lo(%m0)+4]"; + } + + /* Code below isn't smart enough to move a doubleword in two parts, + so use output_move_double to do that in the cases that require it. */ + if ((mode == DImode || mode == DFmode) + && (GET_CODE (operands[1]) == REG + && (REGNO (operands[1]) & 1))) + return output_move_double (operands); + + output_sized_memop ("st", mode); + return "%r1,[%%g1+%%lo(%m0)]"; +} + +/* Output a fixed-point load-from-memory whose operands are OPERANDS[0,1]. + OPERANDS[0] is a reg, and OPERANDS[1] is a mem. */ + +char * +output_load_fixed (operands) + rtx *operands; +{ + enum machine_mode mode = GET_MODE (operands[0]); + rtx address = XEXP (operands[1], 0); + + /* We don't bother trying to see if we know %hi(address). + This is because we are doing a load, and if we know the + %hi value, we probably also know that value in memory. */ + cc_status.flags |= CC_KNOW_HI_G1; + cc_status.mdep = address; + + if (! ((cc_prev_status.flags & CC_KNOW_HI_G1) + && address == cc_prev_status.mdep + && cc_prev_status.mdep == cc_status.mdep)) + { + output_asm_insn ("sethi %%hi(%m1),%%g1", operands); + cc_prev_status.mdep = address; + } + + /* Code below isn't smart enough to do a doubleword in two parts. + So handle that case the slow way. */ + if (mode == DImode + && GET_CODE (operands[0]) == REG /* Moving to nonaligned reg pair */ + && (REGNO (operands[0]) & 1)) + return output_move_double (operands); + + output_sized_memop ("ld", mode); + if (GET_CODE (operands[0]) == REG) + return "[%%g1+%%lo(%m1)],%0"; + abort (); +} + +/* Output a floating-point load-from-memory whose operands are OPERANDS[0,1]. + OPERANDS[0] is a reg, and OPERANDS[1] is a mem. + We also handle the case where OPERANDS[0] is a mem. */ + +char * +output_load_floating (operands) + rtx *operands; +{ + enum machine_mode mode = GET_MODE (operands[0]); + rtx address = XEXP (operands[1], 0); + + /* We don't bother trying to see if we know %hi(address). + This is because we are doing a load, and if we know the + %hi value, we probably also know that value in memory. */ + cc_status.flags |= CC_KNOW_HI_G1; + cc_status.mdep = address; + + if (! ((cc_prev_status.flags & CC_KNOW_HI_G1) + && address == cc_prev_status.mdep + && cc_prev_status.mdep == cc_status.mdep)) + { + output_asm_insn ("sethi %%hi(%m1),%%g1", operands); + cc_prev_status.mdep = address; + } + + if (mode == DFmode) + { + if (REG_P (operands[0])) + { + if (REGNO (operands[0]) & 1) + return output_move_double (operands); + else + return "ldd [%%g1+%%lo(%m1)],%0"; + } + cc_status.flags &= ~(CC_F0_IS_0|CC_F1_IS_0); + output_asm_insn ("ldd [%%g1+%%lo(%m1)],%%f0", operands); + operands[1] = gen_rtx (REG, DFmode, 32); + return output_fp_move_double (operands); + } + + if (GET_CODE (operands[0]) == MEM) + { + cc_status.flags &= ~CC_F1_IS_0; + output_asm_insn ("ld [%%g1+%%lo(%1)],%%f1", operands); + if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) + { + cc_status.mdep = XEXP (operands[0], 0); + return "sethi %%hi(%m0),%%g1\n\tst %%f1,[%%g1+%%lo(%m0)]"; + } + else + return "st %%f1,%0"; + } + return "ld [%%g1+%%lo(%m1)],%0"; +} + +/* Load the address specified by OPERANDS[3] into the register + specified by OPERANDS[0]. + + OPERANDS[3] may be the result of a sum, hence it could either be: + + (1) CONST + (2) REG + (2) REG + CONST_INT + (3) REG + REG + CONST_INT + (4) REG + REG (special case of 3). + + Note that (3) is not a legitimate address. + All cases are handled here. */ + +void +output_load_address (operands) + rtx *operands; +{ + rtx base, offset; + + if (CONSTANT_P (operands[3])) + { + output_asm_insn ("set %3,%0", operands); + return; + } + + if (REG_P (operands[3])) + { + if (REGNO (operands[0]) != REGNO (operands[3])) + output_asm_insn ("mov %3,%0", operands); + return; + } + + if (GET_CODE (operands[3]) != PLUS) + abort (); + + base = XEXP (operands[3], 0); + offset = XEXP (operands[3], 1); + + if (GET_CODE (base) == CONST_INT) + { + rtx tmp = base; + base = offset; + offset = tmp; + } + + if (GET_CODE (offset) != CONST_INT) + { + /* Operand is (PLUS (REG) (REG)). */ + base = operands[3]; + offset = const0_rtx; + } + + if (REG_P (base)) + { + operands[6] = base; + operands[7] = offset; + if (SMALL_INT (offset)) + output_asm_insn ("add %6,%7,%0", operands); + else + output_asm_insn ("set %7,%0\n\tadd %0,%6,%0", operands); + } + else if (GET_CODE (base) == PLUS) + { + operands[6] = XEXP (base, 0); + operands[7] = XEXP (base, 1); + operands[8] = offset; + + if (SMALL_INT (offset)) + output_asm_insn ("add %6,%7,%0\n\tadd %0,%8,%0", operands); + else + output_asm_insn ("set %8,%0\n\tadd %0,%6,%0\n\tadd %0,%7,%0", operands); + } + else + abort (); +} + +/* Output code to place a size count SIZE in register REG. + ALIGN is the size of the unit of transfer. + + Because block moves are pipelined, we don't include the + first element in the transfer of SIZE to REG. */ + +static void +output_size_for_block_move (size, reg, align) + rtx size, reg; + rtx align; +{ + rtx xoperands[3]; + + xoperands[0] = reg; + xoperands[1] = size; + xoperands[2] = align; + if (GET_CODE (size) == REG) + output_asm_insn ("sub %1,%2,%0", xoperands); + else + { + xoperands[1] + = gen_rtx (CONST_INT, VOIDmode, INTVAL (size) - INTVAL (align)); + cc_status.flags &= ~ CC_KNOW_HI_G1; + output_asm_insn ("set %1,%0", xoperands); + } +} + +/* Emit code to perform a block move. + + OPERANDS[0] is the destination. + OPERANDS[1] is the source. + OPERANDS[2] is the size. + OPERANDS[3] is the alignment safe to use. + OPERANDS[4] is a register we can safely clobber as a temp. */ + +char * +output_block_move (operands) + rtx *operands; +{ + /* A vector for our computed operands. Note that load_output_address + makes use of (and can clobber) up to the 8th element of this vector. */ + rtx xoperands[10]; + rtx zoperands[10]; + static int movstrsi_label = 0; + int i, j; + rtx temp1 = operands[4]; + rtx alignrtx = operands[3]; + int align = INTVAL (alignrtx); + + xoperands[0] = operands[0]; + xoperands[1] = operands[1]; + xoperands[2] = temp1; + + /* We can't move more than four bytes at a time + because we have only one register to move them through. */ + if (align > 4) + { + align = 4; + alignrtx = gen_rtx (CONST_INT, VOIDmode, 4); + } + + /* Since we clobber untold things, nix the condition codes. */ + CC_STATUS_INIT; + + /* Recognize special cases of block moves. These occur + when GNU C++ is forced to treat something as BLKmode + to keep it in memory, when its mode could be represented + with something smaller. + + We cannot do this for global variables, since we don't know + what pages they don't cross. Sigh. */ + if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) <= 16 + && ! CONSTANT_ADDRESS_P (operands[0]) + && ! CONSTANT_ADDRESS_P (operands[1])) + { + int size = INTVAL (operands[2]); + + cc_status.flags &= ~CC_KNOW_HI_G1; + if (align == 1) + { + if (memory_address_p (QImode, plus_constant (xoperands[0], size)) + && memory_address_p (QImode, plus_constant (xoperands[1], size))) + { + /* We will store different integers into this particular RTX. */ + xoperands[2] = gen_rtx (CONST_INT, VOIDmode, 13); + for (i = size-1; i >= 0; i--) + { + INTVAL (xoperands[2]) = i; + output_asm_insn ("ldub [%a1+%2],%%g1\n\tstb %%g1,[%a0+%2]", + xoperands); + } + return ""; + } + } + else if (align == 2) + { + if (memory_address_p (HImode, plus_constant (xoperands[0], size)) + && memory_address_p (HImode, plus_constant (xoperands[1], size))) + { + /* We will store different integers into this particular RTX. */ + xoperands[2] = gen_rtx (CONST_INT, VOIDmode, 13); + for (i = (size>>1)-1; i >= 0; i--) + { + INTVAL (xoperands[2]) = i<<1; + output_asm_insn ("lduh [%a1+%2],%%g1\n\tsth %%g1,[%a0+%2]", + xoperands); + } + return ""; + } + } + else + { + if (memory_address_p (SImode, plus_constant (xoperands[0], size)) + && memory_address_p (SImode, plus_constant (xoperands[1], size))) + { + /* We will store different integers into this particular RTX. */ + xoperands[2] = gen_rtx (CONST_INT, VOIDmode, 13); + for (i = (size>>2)-1; i >= 0; i--) + { + INTVAL (xoperands[2]) = i<<2; + output_asm_insn ("ld [%a1+%2],%%g1\n\tst %%g1,[%a0+%2]", + xoperands); + } + return ""; + } + } + } + + /* This is the size of the transfer. + Either use the register which already contains the size, + or use a free register (used by no operands). + Also emit code to decrement the size value by ALIGN. */ + output_size_for_block_move (operands[2], temp1, alignrtx); + + zoperands[0] = operands[0]; + zoperands[3] = plus_constant (operands[0], align); + output_load_address (zoperands); + + xoperands[3] = gen_rtx (CONST_INT, VOIDmode, movstrsi_label++); + xoperands[4] = gen_rtx (CONST_INT, VOIDmode, align); + +#ifdef NO_UNDERSCORES + if (align == 1) + output_asm_insn ("\n.Lm%3:\n\tldub [%1+%2],%%g1\n\tsubcc %2,%4,%2\n\tbge .Lm%3\n\tstb %%g1,[%0+%2]", xoperands); + else if (align == 2) + output_asm_insn ("\n.Lm%3:\n\tlduh [%1+%2],%%g1\n\tsubcc %2,%4,%2\n\tbge .Lm%3\n\tsth %%g1,[%0+%2]", xoperands); + else + output_asm_insn ("\n.Lm%3:\n\tld [%1+%2],%%g1\n\tsubcc %2,%4,%2\n\tbge .Lm%3\n\tst %%g1,[%0+%2]", xoperands); +#else + if (align == 1) + output_asm_insn ("\nLm%3:\n\tldub [%1+%2],%%g1\n\tsubcc %2,%4,%2\n\tbge Lm%3\n\tstb %%g1,[%0+%2]", xoperands); + else if (align == 2) + output_asm_insn ("\nLm%3:\n\tlduh [%1+%2],%%g1\n\tsubcc %2,%4,%2\n\tbge Lm%3\n\tsth %%g1,[%0+%2]", xoperands); + else + output_asm_insn ("\nLm%3:\n\tld [%1+%2],%%g1\n\tsubcc %2,%4,%2\n\tbge Lm%3\n\tst %%g1,[%0+%2]", xoperands); +#endif + return ""; +} + +/* What the sparc lacks in hardware, make up for in software. + Compute a fairly good sequence of shift and add insns + to make a multiply happen. */ + +#define ABS(x) ((x) < 0 ? -(x) : x) + +char * +output_mul_by_constant (insn, operands, unsignedp) + rtx insn; + rtx *operands; + int unsignedp; +{ + int c; /* Size of constant */ + int shifts[BITS_PER_WORD]; /* Table of shifts */ + unsigned int p, log; /* A power of two, and its log */ + int d1, d2; /* Differences of c and p */ + int first = 1; /* True if dst has unknown data in it */ + int i; + + CC_STATUS_INIT; + + c = INTVAL (operands[2]); + if (c == 0) + { + /* Does happen, at least when not optimizing. */ + if (GET_CODE (operands[0]) == MEM) + return "st %%g0,%0"; + return "mov %%g0,%0"; + } + + output_asm_insn ("! start open coded multiply"); + + /* Clear out the table of shifts. */ + for (i = 0; i < BITS_PER_WORD; ++i) + shifts[i] = 0; + + while (c) + { + /* Find the power of two nearest ABS(c) */ + p = 1, log = 0; + do + { + d1 = ABS(c) - p; + p *= 2; + ++log; + } + while (p < ABS(c)); + d2 = p - ABS(c); + + /* Make an appropriate entry in shifts for p. */ + if (d2 < d1) + { + shifts[log] = c < 0 ? -1 : 1; + c = c < 0 ? d2 : -d2; + } + else + { + shifts[log - 1] = c < 0 ? -1 : 1; + c = c < 0 ? -d1 : d1; + } + } + + /* Take care of the first insn in sequence. + We know we have at least one. */ + + /* A value of -1 in shifts says to subtract that power of two, and a value + of 1 says to add that power of two. */ + for (i = 0; ; i++) + if (shifts[i]) + { + if (i) + { + operands[2] = gen_rtx (CONST_INT, VOIDmode, i); + output_asm_insn ("sll %1,%2,%%g1", operands); + } + else output_asm_insn ("mov %1,%%g1", operands); + + log = i; + if (shifts[i] < 0) + output_asm_insn ("sub %%g0,%%g1,%0", operands); + else + output_asm_insn ("mov %%g1,%0", operands); + break; + } + + /* A value of -1 in shifts says to subtract that power of two, and a value + of 1 says to add that power of two--continued. */ + for (i += 1; i < BITS_PER_WORD; ++i) + if (shifts[i]) + { + if (i - log > 0) + { + operands[2] = gen_rtx (CONST_INT, VOIDmode, i - log); + output_asm_insn ("sll %%g1,%2,%%g1", operands); + } + else + { + operands[2] = gen_rtx (CONST_INT, VOIDmode, log - i); + output_asm_insn ("sra %%g1,%2,%%g1", operands); + } + log = i; + if (shifts[i] < 0) + output_asm_insn ("sub %0,%%g1,%0", operands); + else + output_asm_insn ("add %0,%%g1,%0", operands); + } + + output_asm_insn ("! end open coded multiply"); + + return ""; +} + +char * +output_mul_insn (operands, unsignedp) + rtx *operands; + int unsignedp; +{ + int lucky1 = ((unsigned)REGNO (operands[1]) - 8) <= 1; + int lucky2 = ((unsigned)REGNO (operands[2]) - 8) <= 1; + + CC_STATUS_INIT; + + if (lucky1) + { + if (lucky2) + { + if (REGNO (operands[1]) == REGNO (operands[2])) + { + if (REGNO (operands[1]) == 8) + output_asm_insn ("mov %%o0,%%o1"); + else + output_asm_insn ("mov %%o1,%%o0"); + } + output_asm_insn ("call .mul,2\n\tnop", operands); + } + else + { + rtx xoperands[2]; + xoperands[0] = gen_rtx (REG, SImode, + 8 ^ (REGNO (operands[1]) == 8)); + xoperands[1] = operands[2]; + output_asm_insn ("call .mul,2\n\tmov %1,%0", xoperands); + } + } + else if (lucky2) + { + rtx xoperands[2]; + xoperands[0] = gen_rtx (REG, SImode, + 8 ^ (REGNO (operands[2]) == 8)); + xoperands[1] = operands[1]; + output_asm_insn ("call .mul,2\n\tmov %1,%0", xoperands); + } + else + { + output_asm_insn ("mov %1,%%o0\n\tcall .mul,2\n\tmov %2,%%o1", + operands); + } + + if (REGNO (operands[0]) == 8) + return ""; + return "mov %%o0,%0"; +} + +/* Make floating point register f0 contain 0. + SIZE is the number of registers (including f0) + which should contain 0. */ + +void +make_f0_contain_0 (size) + int size; +{ + if (size == 1) + { + if ((cc_status.flags & (CC_F0_IS_0)) == 0) + output_asm_insn ("ld [%%fp-16],%%f0", 0); + cc_status.flags |= CC_F0_IS_0; + } + else if (size == 2) + { + if ((cc_status.flags & CC_F0_IS_0) == 0) + output_asm_insn ("ld [%%fp-16],%%f0", 0); + if ((cc_status.flags & (CC_F1_IS_0)) == 0) + output_asm_insn ("ld [%%fp-12],%%f1", 0); + cc_status.flags |= CC_F0_IS_0 | CC_F1_IS_0; + } +} + +/* Since condition codes don't have logical links, we need to keep + their setting and use together for set-cc insns. */ +void +gen_scc_insn (code, mode, operands) + enum rtx_code code; + enum machine_mode mode; + rtx *operands; +{ + extern rtx sequence_stack; + rtx last_insn = XEXP (XEXP (sequence_stack, 1), 0); + rtx last_pat; + + /* Skip back over the CLOBBERs that may precede this insn. */ + while (last_insn && GET_CODE (last_insn) == INSN + && GET_CODE (PATTERN (last_insn)) == CLOBBER) + last_insn = PREV_INSN (last_insn); + /* We should have found the preceding compare. */ + if (last_insn == 0 || GET_CODE (last_insn) != INSN) + abort (); + last_pat = PATTERN (last_insn); + if (GET_CODE (last_pat) != SET + || GET_CODE (SET_DEST (last_pat)) != CC0) + abort (); + + /* Turn off that previous insn, now that we have got the data out of it. */ + PUT_CODE (last_insn, NOTE); + NOTE_LINE_NUMBER (last_insn) = NOTE_INSN_DELETED; + + /* Emit one replacement insn to compare operands and store result. */ + emit_insn (gen_rtx (SET, VOIDmode, operands[0], + gen_rtx (code, mode, SET_SRC (last_pat), const0_rtx))); +} + +/* Output reasonable peephole for set-on-condition-code insns. + Note that these insns assume a particular way of defining + labels. Therefore, *both* tm-sparc.h and this function must + be changed if a new syntax is needed. */ + +char * +output_scc_insn (code, operand) + enum rtx_code code; + rtx operand; +{ + rtx xoperands[2]; + rtx label = gen_label_rtx (); + int cc_in_fccr = cc_status.flags & CC_IN_FCCR; + int antisymmetric = 0; + + xoperands[0] = operand; + xoperands[1] = label; + + switch (code) + { + case NE: + if (cc_in_fccr) + output_asm_insn ("fbne,a %l0", &label); + else + output_asm_insn ("bne,a %l0", &label); + break; + case EQ: + if (cc_in_fccr) + output_asm_insn ("fbe,a %l0", &label); + else + output_asm_insn ("be,a %l0", &label); + break; + case GE: + if (cc_in_fccr) + output_asm_insn ("fbge,a %l0", &label); + else + output_asm_insn ("bge,a %l0", &label); + antisymmetric = 1; + break; + case GT: + if (cc_in_fccr) + output_asm_insn ("fbg,a %l0", &label); + else + output_asm_insn ("bg,a %l0", &label); + antisymmetric = 1; + break; + case LE: + if (cc_in_fccr) + output_asm_insn ("fble,a %l0", &label); + else + output_asm_insn ("ble,a %l0", &label); + antisymmetric = 1; + break; + case LT: + if (cc_in_fccr) + output_asm_insn ("fbl,a %l0", &label); + else + output_asm_insn ("bl,a %l0", &label); + antisymmetric = 1; + break; + case GEU: + if (cc_in_fccr) + abort (); + else + output_asm_insn ("bgeu,a %l0", &label); + antisymmetric = 1; + break; + case GTU: + if (cc_in_fccr) + abort (); + else + output_asm_insn ("bgu,a %l0", &label); + antisymmetric = 1; + break; + case LEU: + if (cc_in_fccr) + abort (); + else + output_asm_insn ("bleu,a %l0", &label); + antisymmetric = 1; + break; + case LTU: + if (cc_in_fccr) + abort (); + else + output_asm_insn ("blu,a %l0", &label); + antisymmetric = 1; + break; + default: + abort (); + } + + if (antisymmetric + && (cc_status.flags & CC_REVERSED)) + output_asm_insn ("orcc %%g0,0,%0\n\torcc %%g0,1,%0\n%l1:", xoperands); + else + output_asm_insn ("orcc %%g0,1,%0\n\torcc %%g0,0,%0\n%l1:", xoperands); + cc_status.flags &= ~CC_IN_FCCR; + + return ""; +} + +/* Output a delayed branch insn with the delay insn in its + branch slot. The delayed branch insn template is in TEMPLATE, + with operands OPERANDS. The insn in its delay slot is INSN. + + As a special case, since we know that all memory transfers are via + ld/st insns, if we see a (MEM (SYMBOL_REF ...)) we divide the memory + reference around the branch as + + sethi %hi(x),%%g1 + b ... + ld/st [%g1+%lo(x)],... + + As another special case, we handle loading (SYMBOL_REF ...) and + other large constants around branches as well: + + sethi %hi(x),%0 + b ... + or %0,%lo(x),%1 + + */ + +char * +output_delayed_branch (template, operands, insn) + char *template; + rtx *operands; + rtx insn; +{ + extern rtx recog_operand[]; + rtx src = XVECEXP (PATTERN (insn), 0, 1); + rtx dest = XVECEXP (PATTERN (insn), 0, 0); + + if (GET_CODE (src) == SYMBOL_REF + || (GET_CODE (src) == CONST_INT + && !(SMALL_INT (src) || (INTVAL (src) & 0x3ff) == 0))) + { + rtx xoperands[2]; + xoperands[0] = dest; + xoperands[1] = src; + + /* Output the `sethi' insn. */ + output_asm_insn ("sethi %%hi(%1),%0", xoperands); + + /* Output the branch instruction next. */ + output_asm_insn (template, operands); + + /* Now output the `or' insn. */ + output_asm_insn ("or %0,%%lo(%1),%0", xoperands); + } + else if ((GET_CODE (src) == MEM + && CONSTANT_ADDRESS_P (XEXP (src, 0))) + || (GET_CODE (dest) == MEM + && CONSTANT_ADDRESS_P (XEXP (dest, 0)))) + { + rtx xoperands[2]; + char *split_template; + xoperands[0] = dest; + xoperands[1] = src; + + /* Output the `sethi' insn. */ + if (GET_CODE (src) == MEM) + { + if (! ((cc_prev_status.flags & CC_KNOW_HI_G1) + && cc_prev_status.mdep == XEXP (operands[1], 0))) + output_asm_insn ("sethi %%hi(%m1),%%g1", xoperands); + split_template = "ld [%%g1+%%lo(%m1)],%0"; + } + else + { + if (! ((cc_prev_status.flags & CC_KNOW_HI_G1) + && cc_prev_status.mdep == XEXP (operands[0], 0))) + output_asm_insn ("sethi %%hi(%m0),%%g1", xoperands); + split_template = "st %r1,[%%g1+%%lo(%m0)]"; + } + + /* Output the branch instruction next. */ + output_asm_insn (template, operands); + + /* Now output the load or store. + No need to do a CC_STATUS_INIT, because we are branching anyway. */ + output_asm_insn (split_template, xoperands); + } + else + { + extern char *insn_template[]; + extern char *(*insn_outfun[])(); + int insn_code_number; + rtx pat = gen_rtx (SET, VOIDmode, dest, src); + rtx delay_insn = gen_rtx (INSN, VOIDmode, 0, 0, 0, pat, -1, 0, 0); + int i; + extern rtx alter_subreg(); + extern int insn_n_operands[]; + + /* Output the branch instruction first. */ + output_asm_insn (template, operands); + + /* Now recognize the insn which we put in its delay slot. + We must do this after outputing the branch insn, + since operands may just be a pointer to `recog_operand'. */ + insn_code_number = recog (pat, delay_insn); + if (insn_code_number == -1) + abort (); + + for (i = 0; i < insn_n_operands[insn_code_number]; i++) + { + if (GET_CODE (recog_operand[i]) == SUBREG) + recog_operand[i] = alter_subreg (recog_operand[i]); + } + + /* Now get the template for what this insn would + have been, without the branch. Its operands are + exactly the same as they would be, so we don't + need to do an insn_extract. */ + template = insn_template[insn_code_number]; + if (template == 0) + template = (*insn_outfun[insn_code_number]) (recog_operand, delay_insn); + output_asm_insn (template, recog_operand); + } + CC_STATUS_INIT; + return ""; +} + +/* Output a newly constructed insn DELAY_INSN. */ +char * +output_delay_insn (delay_insn) + rtx delay_insn; +{ + char *template; + extern rtx recog_operand[]; + extern char call_used_regs[]; + extern char *insn_template[]; + extern int insn_n_operands[]; + extern char *(*insn_outfun[])(); + extern rtx alter_subreg(); + int insn_code_number; + extern int insn_n_operands[]; + int i; + + /* Now recognize the insn which we put in its delay slot. + We must do this after outputing the branch insn, + since operands may just be a pointer to `recog_operand'. */ + insn_code_number = recog_memoized (delay_insn); + if (insn_code_number == -1) + abort (); + + /* Extract the operands of this delay insn. */ + INSN_CODE (delay_insn) = insn_code_number; + insn_extract (delay_insn); + + /* It is possible that this insn has not been properly scaned by final + yet. If this insn's operands don't appear in the peephole's + actual operands, then they won't be fixed up by final, so we + make sure they get fixed up here. -- This is a kludge. */ + for (i = 0; i < insn_n_operands[insn_code_number]; i++) + { + if (GET_CODE (recog_operand[i]) == SUBREG) + recog_operand[i] = alter_subreg (recog_operand[i]); + } + +#ifdef REGISTER_CONSTRAINTS + if (! constrain_operands (insn_code_number)) + abort (); +#endif + + cc_prev_status = cc_status; + + /* Update `cc_status' for this instruction. + The instruction's output routine may change it further. + If the output routine for a jump insn needs to depend + on the cc status, it should look at cc_prev_status. */ + + NOTICE_UPDATE_CC (PATTERN (delay_insn), delay_insn); + + /* Now get the template for what this insn would + have been, without the branch. */ + + template = insn_template[insn_code_number]; + if (template == 0) + template = (*insn_outfun[insn_code_number]) (recog_operand, delay_insn); + output_asm_insn (template, recog_operand); + return ""; +} + +/* Output the insn HEAD, keeping OPERANDS protected (wherever they are). + HEAD comes from the target of some branch, so before we output it, + we delete it from the target, lest we execute it twice. The caller + of this function promises that such code motion is permissable. */ +char * +output_eager_then_insn (head, operands) + rtx head; + rtx *operands; +{ + extern rtx alter_subreg (); + extern int insn_n_operands[]; + extern rtx recog_operand[]; + rtx xoperands[MAX_RECOG_OPERANDS]; + int insn_code_number, i, nbytes; + rtx nhead; + + /* Micro-hack: run peephole on head if it looks like a good idea. + Right now there's only one such case worth doing... + + This could be made smarter if the peephole for ``2-insn combine'' + were also made smarter. */ + if (GET_CODE (PATTERN (head)) == SET + && REG_P (SET_SRC (PATTERN (head))) + && REG_P (SET_DEST (PATTERN (head))) + && (nhead = next_real_insn_no_labels (head)) + && GET_CODE (nhead) == INSN + && GET_CODE (PATTERN (nhead)) == SET + && GET_CODE (SET_DEST (PATTERN (nhead))) == CC0 + && (SET_SRC (PATTERN (nhead)) == SET_SRC (PATTERN (head)) + || SET_SRC (PATTERN (nhead)) == SET_DEST (PATTERN (head)))) + /* Something's wrong if this does not fly. */ + if (! peephole (head)) + abort (); + + /* Save our contents of `operands', since output_delay_insn sets them. */ + insn_code_number = recog_memoized (head); + nbytes = insn_n_operands[insn_code_number] * sizeof (rtx); + bcopy (operands, xoperands, nbytes); + + /* Output the delay insn, and prevent duplication later. */ + delete_insn (head); + output_delay_insn (head); + + /* Restore this insn's operands. */ + bcopy (xoperands, operands, nbytes); +} + +/* Return the next INSN, CALL_INSN or JUMP_INSN after LABEL; + or 0, if there is none. Also return 0 if we cross a label. */ + +rtx +next_real_insn_no_labels (label) + rtx label; +{ + register rtx insn = NEXT_INSN (label); + register RTX_CODE code; + + while (insn) + { + code = GET_CODE (insn); + if (code == INSN) + { + if (GET_CODE (PATTERN (insn)) != CLOBBER + && GET_CODE (PATTERN (insn)) != USE) + return insn; + } + if (code == CALL_INSN || code == JUMP_INSN) + return insn; + if (code == CODE_LABEL) + return 0; + insn = NEXT_INSN (insn); + } + + return 0; +} + +int +operands_satisfy_eager_branch_peephole (operands, conditional) + rtx *operands; + int conditional; +{ + rtx label; + + if (conditional) + { + if (GET_CODE (operands[0]) != IF_THEN_ELSE) + return 0; + + if (GET_CODE (XEXP (operands[0], 1)) == LABEL_REF) + label = XEXP (XEXP (operands[0], 1), 0); + else if (GET_CODE (XEXP (operands[0], 2)) == LABEL_REF) + label = XEXP (XEXP (operands[0], 2), 0); + else return 0; + } + else + { + label = operands[0]; + } + + if (LABEL_NUSES (label) == 1) + { + rtx prev = PREV_INSN (label); + while (prev && GET_CODE (prev) == NOTE) + prev = PREV_INSN (prev); + if (prev == 0 + || GET_CODE (prev) == BARRIER) + { + rtx head = next_real_insn_no_labels (label); + + if (head + && ! INSN_DELETED_P (head) + && GET_CODE (head) == INSN + && GET_CODE (PATTERN (head)) == SET + && strict_single_insn_op_p (SET_SRC (PATTERN (head)), + GET_MODE (SET_DEST (PATTERN (head)))) + && strict_single_insn_op_p (SET_DEST (PATTERN (head)), + GET_MODE (SET_DEST (PATTERN (head)))) + /* Moves between FP regs and CPU regs are two insns. */ + && !(GET_CODE (SET_SRC (PATTERN (head))) == REG + && GET_CODE (SET_DEST (PATTERN (head))) == REG + && (FP_REG_P (SET_SRC (PATTERN (head))) + != FP_REG_P (SET_DEST (PATTERN (head)))))) + { + if (conditional == 2) + return (GET_CODE (operands[1]) != PC + && safe_insn_src_p (operands[2], VOIDmode) + && strict_single_insn_op_p (operands[2], VOIDmode) + && operand_clobbered_before_used_after (operands[1], label)); + return 1; + } + } + } + + if (conditional == 1 + && GET_CODE (operands[1]) != PC + && safe_insn_src_p (operands[2], VOIDmode) + && strict_single_insn_op_p (operands[2], VOIDmode) + && operand_clobbered_before_used_after (operands[1], label)) + return 1; + + return 0; +} + diff --git a/gcc-1.40/config/out-spur.c b/gcc-1.40/config/out-spur.c new file mode 100644 index 0000000..0e5c5a8 --- /dev/null +++ b/gcc-1.40/config/out-spur.c @@ -0,0 +1,316 @@ +/* Subroutines for insn-output.c for SPUR. Adapted from routines for + the Motorola 68000 family. + Copyright (C) 1988 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 1, 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. */ + +static rtx find_addr_reg (); + +char * +output_compare (operands, opcode, exchange_opcode, + neg_opcode, neg_exchange_opcode) + rtx *operands; + char *opcode; + char *exchange_opcode; + char *neg_opcode; + char *neg_exchange_opcode; +{ + static char buf[100]; + operands[2] = operands[0]; + if (GET_CODE (cc_prev_status.value1) == CONST_INT) + { + operands[1] = cc_prev_status.value1; + operands[0] = cc_prev_status.value2; + opcode = exchange_opcode, neg_opcode = neg_exchange_opcode; + } + else + { + operands[0] = cc_prev_status.value1; + operands[1] = cc_prev_status.value2; + } + if (TARGET_LONG_JUMPS) + sprintf (buf, + "cmp_br_delayed %s,%%0,%%1,1f\n\tnop\n\tjump %%l2\n\tnop\n1:", + neg_opcode); + else + sprintf (buf, "cmp_br_delayed %s,%%0,%%1,%%l2\n\tnop", opcode); + return buf; +} + +/* Return the best assembler insn template + for moving operands[1] into operands[0] as a fullword. */ + +static char * +singlemove_string (operands) + rtx *operands; +{ + if (GET_CODE (operands[0]) == MEM) + return "st_32 %r1,%0"; + if (GET_CODE (operands[1]) == MEM) + return "ld_32 %0,%1\n\tnop"; + if (GET_CODE (operands[1]) == REG) + return "add_nt %0,%1,$0"; + return "add_nt %0,r0,%1"; +} + +/* Output assembler code to perform a doubleword move insn + with operands OPERANDS. */ + +char * +output_move_double (operands) + rtx *operands; +{ + enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1; + rtx latehalf[2]; + rtx addreg0 = 0, addreg1 = 0; + + /* First classify both operands. */ + + if (REG_P (operands[0])) + optype0 = REGOP; + else if (offsettable_memref_p (operands[0])) + optype0 = OFFSOP; + else if (GET_CODE (operands[0]) == MEM) + optype0 = MEMOP; + else + optype0 = RNDOP; + + if (REG_P (operands[1])) + optype1 = REGOP; + else if (CONSTANT_P (operands[1]) + || GET_CODE (operands[1]) == CONST_DOUBLE) + optype1 = CNSTOP; + else if (offsettable_memref_p (operands[1])) + optype1 = OFFSOP; + else if (GET_CODE (operands[1]) == 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) + 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 (operands[0], 0)); + + if (optype1 == MEMOP) + addreg1 = find_addr_reg (XEXP (operands[1], 0)); + + /* Ok, we can do one word at a time. + Normally we do the low-numbered word first, + but if either operand is autodecrementing then we + do the high-numbered word first. + + In either case, set up in LATEHALF the operands to use + for the high-numbered 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 (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); + else if (optype1 == OFFSOP) + latehalf[1] = adj_offsettable_operand (operands[1], 4); + else if (optype1 == CNSTOP) + { + if (CONSTANT_P (operands[1])) + latehalf[1] = const0_rtx; + else if (GET_CODE (operands[1]) == CONST_DOUBLE) + { + latehalf[1] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_HIGH (operands[1])); + operands[1] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_LOW (operands[1])); + } + } + else + latehalf[1] = operands[1]; + + /* If the first move would clobber the source of the second one, + do them in the other order. This happens only for registers; + such overlap can't happen in memory unless the user explicitly + sets it up, and that is an undefined circumstance. */ + + if (optype0 == REGOP && optype1 == REGOP + && REGNO (operands[0]) == REGNO (latehalf[1])) + { + /* Make any unoffsettable addresses point at high-numbered word. */ + if (addreg0) + output_asm_insn ("add_nt %0,%0,$4", &addreg0); + if (addreg1) + output_asm_insn ("add_nt %0,%0,$4", &addreg1); + + /* Do that word. */ + output_asm_insn (singlemove_string (latehalf), latehalf); + + /* Undo the adds we just did. */ + if (addreg0) + output_asm_insn ("add_nt %0,%0,$-4", &addreg0); + if (addreg1) + output_asm_insn ("add_nt %0,%0,$-4", &addreg0); + + /* Do low-numbered word. */ + return singlemove_string (operands); + } + + /* Normal case: do the two words, low-numbered first. */ + + output_asm_insn (singlemove_string (operands), operands); + + /* Make any unoffsettable addresses point at high-numbered word. */ + if (addreg0) + output_asm_insn ("add_nt %0,%0,$4", &addreg0); + if (addreg1) + output_asm_insn ("add_nt %0,%0,$4", &addreg1); + + /* Do that word. */ + output_asm_insn (singlemove_string (latehalf), latehalf); + + /* Undo the adds we just did. */ + if (addreg0) + output_asm_insn ("add_nt %0,%0,$-4", &addreg0); + if (addreg1) + output_asm_insn ("add_nt %0,%0,$-4", &addreg1); + + return ""; +} + +static char * +output_fp_move_double (operands) + rtx *operands; +{ + if (FP_REG_P (operands[0])) + { + if (FP_REG_P (operands[1])) + return "fmov %0,%1"; + if (GET_CODE (operands[1]) == REG) + { + rtx xoperands[2]; + int offset = - get_frame_size () - 8; + xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1); + xoperands[0] = gen_rtx (CONST_INT, VOIDmode, offset + 4); + output_asm_insn ("st_32 %1,r25,%0", xoperands); + xoperands[1] = operands[1]; + xoperands[0] = gen_rtx (CONST_INT, VOIDmode, offset); + output_asm_insn ("st_32 %1,r25,%0", xoperands); + xoperands[1] = operands[0]; + output_asm_insn ("ld_dbl %1,r25,%0\n\tnop", xoperands); + return ""; + } + return "ld_dbl %0,%1\n\tnop"; + } + else if (FP_REG_P (operands[1])) + { + if (GET_CODE (operands[0]) == REG) + { + rtx xoperands[2]; + int offset = - get_frame_size () - 8; + xoperands[0] = gen_rtx (CONST_INT, VOIDmode, offset); + xoperands[1] = operands[1]; + output_asm_insn ("st_dbl %1,r25,%0", xoperands); + xoperands[1] = operands[0]; + output_asm_insn ("ld_32 %1,r25,%0\n\tnop", xoperands); + xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); + xoperands[0] = gen_rtx (CONST_INT, VOIDmode, offset + 4); + output_asm_insn ("ld_32 %1,r25,%0\n\tnop", xoperands); + return ""; + } + return "st_dbl %1,%0"; + } +} + +/* 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) + { + if (GET_CODE (XEXP (addr, 0)) == REG) + addr = XEXP (addr, 0); + else if (GET_CODE (XEXP (addr, 1)) == REG) + 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 (); +} + +/* Generate code to add a large integer constant to register, reg, storing + * the result in a register, target. Offset must be 27-bit signed quantity */ + +static char * +output_add_large_offset (target, reg, offset) + rtx target, reg; + int offset; +{ + rtx operands[3]; + int high, n, i; + operands[0] = target, operands[1] = reg; + + for (high = offset, n = 0; + (unsigned) (high + 0x2000) >= 0x4000; + high >>= 1, n += 1) + ; + operands[2] = gen_rtx (CONST_INT, VOIDmode, high); + output_asm_insn ("add_nt r2,r0,%2", operands); + i = n; + while (i >= 3) + output_asm_insn ("sll r2,r2,$3", operands), i -= 3; + if (i == 2) + output_asm_insn ("sll r2,r2,$2", operands); + else if (i == 1) + output_asm_insn ("sll r2,r2,$1", operands); + output_asm_insn ("add_nt %0,r2,%1", operands); + if (offset - (high << n) != 0) + { + operands[2] = gen_rtx (CONST_INT, VOIDmode, offset - (high << n)); + output_asm_insn ("add_nt %0,%0,%2", operands); + } + return ""; +} + +/* Additional TESTFN for matching. Like immediate_operand, but matches big + * constants */ + +int +big_immediate_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + return (GET_CODE (op) == CONST_INT); +} diff --git a/gcc-1.40/config/out-tahoe.c b/gcc-1.40/config/out-tahoe.c new file mode 100644 index 0000000..47f9591 --- /dev/null +++ b/gcc-1.40/config/out-tahoe.c @@ -0,0 +1,550 @@ +/* Subroutines for insn-output.c for Tahoe. + Copyright (C) 1989 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 1, 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. */ + + +/* + * File: output-tahoe.c + * + * This port made at the University of Buffalo by Devon Bowen, + * Dale Wiles and Kevin Zachmann. + * + * Mail bugs reports or fixes to: gcc@cs.buffalo.edu + */ + + +/* most of the print_operand_address function was taken from the vax */ +/* since the modes are basically the same. I had to add a special case, */ +/* though, for symbol references with offsets. */ + +#include + +print_operand_address (file, addr) + FILE *file; + register rtx addr; +{ + register rtx reg1, reg2, breg, ireg; + rtx offset; + static char *reg_name[] = REGISTER_NAMES; + + retry: + switch (GET_CODE (addr)) + { + case MEM: + fprintf (file, "*"); + addr = XEXP (addr, 0); + goto retry; + + case REG: + fprintf (file, "(%s)", reg_name [REGNO (addr)]); + break; + + case PRE_DEC: + fprintf (file, "-(%s)", reg_name [REGNO (XEXP (addr, 0))]); + break; + + case POST_INC: + fprintf (file, "(%s)+", reg_name [REGNO (XEXP (addr, 0))]); + break; + + case PLUS: + reg1 = 0; reg2 = 0; + ireg = 0; breg = 0; + offset = 0; + + if (CONSTANT_ADDRESS_P (XEXP (addr, 0)) + && GET_CODE (XEXP (addr, 1)) == CONST_INT) + output_addr_const (file, addr); + + if (CONSTANT_ADDRESS_P (XEXP (addr, 1)) + && GET_CODE (XEXP (addr, 0)) == CONST_INT) + output_addr_const (file, addr); + + if (CONSTANT_ADDRESS_P (XEXP (addr, 0)) + || GET_CODE (XEXP (addr, 0)) == MEM) + { + offset = XEXP (addr, 0); + addr = XEXP (addr, 1); + } + else if (CONSTANT_ADDRESS_P (XEXP (addr, 1)) + || GET_CODE (XEXP (addr, 1)) == MEM) + { + offset = XEXP (addr, 1); + addr = XEXP (addr, 0); + } + if (GET_CODE (addr) != PLUS) + ; + else if (GET_CODE (XEXP (addr, 0)) == MULT) + { + reg1 = XEXP (addr, 0); + addr = XEXP (addr, 1); + } + else if (GET_CODE (XEXP (addr, 1)) == MULT) + { + reg1 = XEXP (addr, 1); + addr = XEXP (addr, 0); + } + else if (GET_CODE (XEXP (addr, 0)) == REG) + { + reg1 = XEXP (addr, 0); + addr = XEXP (addr, 1); + } + else if (GET_CODE (XEXP (addr, 1)) == REG) + { + 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; + addr = 0; + } + if (offset != 0) + { + if (addr != 0) abort (); + addr = offset; + } + if (reg1 != 0 && GET_CODE (reg1) == MULT) + { + breg = reg2; + ireg = reg1; + } + else if (reg2 != 0 && GET_CODE (reg2) == MULT) + { + breg = reg1; + ireg = reg2; + } + else if (reg2 != 0 || GET_CODE (addr) == MEM) + { + breg = reg2; + ireg = reg1; + } + else + { + breg = reg1; + ireg = reg2; + } + if (addr != 0) + output_address (offset); + if (breg != 0) + { + if (GET_CODE (breg) != REG) + abort (); + fprintf (file, "(%s)", reg_name[REGNO (breg)]); + } + if (ireg != 0) + { + if (GET_CODE (ireg) == MULT) + ireg = XEXP (ireg, 0); + if (GET_CODE (ireg) != REG) + abort (); + fprintf (file, "[%s]", reg_name[REGNO (ireg)]); + } + break; + + default: + output_addr_const (file, addr); + } +} + + +/* Do a quick check and find out what the best way to do the */ +/* mini-move is. Could be a push or a move..... */ + +static char * +singlemove_string (operands) + rtx *operands; +{ + if (GET_CODE (operands[0]) == MEM + && GET_CODE (XEXP (operands[0],0)) == PRE_DEC) + return "pushl %1"; + return "movl %1,%0"; +} + + +/* given the rtx for an address, return true if the given */ +/* register number is used in the address somewhere. */ + +int +regisused (addr,regnum) + rtx addr; + int regnum; +{ + if (GET_CODE (addr) == REG) + { + if (REGNO (addr) == regnum) + return (1); + else + return (0); + } + + if (GET_CODE (addr) == MEM) + return regisused (XEXP (addr,0),regnum); + + if (GET_CODE (addr) == MULT || GET_CODE (addr) == PLUS) + return (regisused (XEXP (addr,0),regnum) + || regisused (XEXP (addr,1),regnum)); + + return 0; +} + + +/* Given some rtx, traverse it and return the register used in a */ +/* index. If no index is found, return 0. */ + +rtx +index_reg (addr) + rtx addr; +{ + rtx temp; + + if (GET_CODE (addr) == MEM) + return index_reg (XEXP (addr,0)); + + if (GET_CODE (addr) == MULT) + { + if (GET_CODE (XEXP (addr,0)) == REG) + return XEXP (addr,0); + else + return XEXP (addr,1); + } + + if (GET_CODE (addr) == PLUS) + { + if (temp = index_reg (XEXP (addr,0))) + return temp; + else + return index_reg (XEXP (addr,1)); + } + + return 0; +} + + +/* simulate the move double by generating two movl's. You have */ +/* to be careful about mixing modes here. A future improvement */ +/* would be to allow immediate doubles. */ + +char * +output_move_double (operands) + rtx *operands; +{ + enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, INDOP, CNSTOP, RNDOP } optype0, optype1; + rtx latehalf[2]; + rtx shftreg0 = 0, shftreg1 = 0; + rtx temp0 = 0, temp1 = 0; + rtx addreg0 = 0, addreg1 = 0; + int dohighfirst = 0; + + /* First classify both operands. */ + + if (REG_P (operands[0])) + optype0 = REGOP; + else if ((GET_CODE (operands[0])==MEM) && (shftreg0=index_reg (operands[0]))) + optype0 = INDOP; + else if (offsettable_memref_p (operands[0])) + optype0 = OFFSOP; + else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC) + { + optype0 = PUSHOP; + dohighfirst++; + } + else if (GET_CODE (operands[0]) == MEM) + optype0 = MEMOP; + else + optype0 = RNDOP; + + if (REG_P (operands[1])) + optype1 = REGOP; + else if ((GET_CODE (operands[1])==MEM) && (shftreg1=index_reg (operands[1]))) + optype1 = INDOP; + else if (offsettable_memref_p (operands[1])) + optype1 = OFFSOP; + else if (GET_CODE (XEXP (operands[1], 0)) == POST_INC) + optype1 = POPOP; + else if (GET_CODE (operands[1]) == MEM) + optype1 = MEMOP; + else if (GET_CODE (operands[1]) == CONST_DOUBLE || CONSTANT_P (operands[1])) + optype1 = CNSTOP; + else + optype1 = RNDOP; + + /* set up for the high byte move for operand zero */ + + switch (optype0) + { + + /* if it's a register, just use the next highest in the */ + /* high address move. */ + + case REGOP: + latehalf[0] = gen_rtx (REG,SImode,REGNO (operands[0])+1); + break; + + /* for an offsettable address, use the gcc function to */ + /* modify the operand to get an offset of 4 higher for */ + /* the second move. */ + + case OFFSOP: + latehalf[0] = adj_offsettable_operand (operands[0], 4); + break; + + /* if the operand is MEMOP type, it must be a pointer */ + /* to a pointer. So just remember to increase the mem */ + /* location and use the same operand. */ + + case MEMOP: + latehalf[0] = operands[0]; + addreg0 = XEXP (operands[0],0); + break; + + /* if we're dealing with a push instruction, just leave */ + /* the operand alone since it auto-increments. */ + + case PUSHOP: + latehalf[0] = operands[0]; + break; + + /* YUCK! Indexed addressing!! If the address is considered */ + /* offsettable, go use the offset in the high part. Otherwise */ + /* find what exactly is being added to the mutiplication. If */ + /* it's a mem reference, increment that with the high part */ + /* being unchanged to cause the shift. If it's a reg, do the */ + /* same. If you can't identify it, abort. Remember that the */ + /* shift register was already set during identification. */ + + case INDOP: + if (offsettable_memref_p (operands[0])) + { + latehalf[0] = adj_offsettable_operand (operands[0],4); + break; + } + + latehalf[0] = operands[0]; + + temp0 = XEXP (XEXP (operands[0],0),0); + if (GET_CODE (temp0) == MULT) + { + temp1 = temp0; + temp0 = XEXP (XEXP (operands[0],0),1); + } + else + { + temp1 = XEXP (XEXP (operands[0],0),1); + if (GET_CODE (temp1) != MULT) + abort (); + } + + if (GET_CODE (temp0) == MEM) + addreg0 = temp0; + else if (GET_CODE (temp0) == REG) + addreg0 = temp0; + else + abort (); + + break; + + /* if we don't know the operand type, print a friendly */ + /* little error message... 8-) */ + + case RNDOP: + default: + abort (); + } + + /* do the same setup for operand one */ + + switch (optype1) + { + + case REGOP: + latehalf[1] = gen_rtx (REG,SImode,REGNO (operands[1])+1); + break; + + case OFFSOP: + latehalf[1] = adj_offsettable_operand (operands[1], 4); + break; + + case MEMOP: + latehalf[1] = operands[1]; + addreg1 = XEXP (operands[1],0); + break; + + case POPOP: + latehalf[1] = operands[1]; + break; + + case INDOP: + if (offsettable_memref_p (operands[1])) + { + latehalf[1] = adj_offsettable_operand (operands[1],4); + break; + } + + latehalf[1] = operands[1]; + + temp0 = XEXP (XEXP (operands[1],0),0); + if (GET_CODE (temp0) == MULT) + { + temp1 = temp0; + temp0 = XEXP (XEXP (operands[1],0),1); + } + else + { + temp1 = XEXP (XEXP (operands[1],0),1); + if (GET_CODE (temp1) != MULT) + abort (); + } + + if (GET_CODE (temp0) == MEM) + addreg1 = temp0; + else if (GET_CODE (temp0) == REG) + addreg1 = temp0; + else + abort (); + + break; + + case CNSTOP: + /* Since this machine is big-endian, + the late half must be the low-order word for an integer, + or the latter word for a float. */ + if (GET_CODE (operands[1]) == CONST_DOUBLE) + { + if (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_FLOAT) + { + latehalf[1] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_HIGH (operands[1])); + operands[1] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_LOW (operands[1])); + } + else + { + latehalf[1] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_LOW (operands[1])); + operands[1] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_HIGH (operands[1])); + } + } + else + { + latehalf[1] = operands[1]; + operands[1] = const0_rtx; + } + break; + + case RNDOP: + default: + abort (); + } + + + /* double the register used for shifting in both of the operands */ + /* but make sure the same register isn't doubled twice! */ + + if (shftreg0 && shftreg1 && rtx_equal_p (shftreg0, shftreg1)) + output_asm_insn ("addl2 %0,%0", &shftreg0); + else + { + if (shftreg0) + output_asm_insn ("addl2 %0,%0", &shftreg0); + if (shftreg1) + output_asm_insn ("addl2 %0,%0", &shftreg1); + } + + /* if the destination is a register and that register is needed in */ + /* the source addressing mode, swap the order of the moves since we */ + /* don't want this destroyed til last. If both regs are used, not */ + /* much we can do, so abort. If these becomes a problem, maybe we */ + /* can do it on the stack? */ + + if (GET_CODE (operands[0])==REG && regisused (operands[1],REGNO (operands[0]))) + if (regisused (latehalf[1],REGNO (latehalf[0]))) + 8; + else + dohighfirst++; + + /* if we're pushing, do the high address part first. */ + + if (dohighfirst) + { + + if (addreg0 && addreg1 && (rtx_equal_p (addreg0,addreg1))) + output_asm_insn ("addl2 $4,%0", &addreg0); + else + { + if (addreg0) + output_asm_insn ("addl2 $4,%0", &addreg0); + if (addreg1) + output_asm_insn ("addl2 $4,%0", &addreg1); + } + + output_asm_insn (singlemove_string (latehalf), latehalf); + + if (addreg0 && addreg1 && (rtx_equal_p (addreg0,addreg1))) + output_asm_insn ("subl2 $4,%0", &addreg0); + else + { + if (addreg0) + output_asm_insn ("subl2 $4,%0", &addreg0); + if (addreg1) + output_asm_insn ("subl2 $4,%0", &addreg1); + } + + return singlemove_string (operands); + } + + output_asm_insn (singlemove_string (operands), operands); + + if (addreg0 && addreg1 && (rtx_equal_p (addreg0,addreg1))) + output_asm_insn ("addl2 $4,%0", &addreg0); + else + { + if (addreg0) + output_asm_insn ("addl2 $4,%0", &addreg0); + if (addreg1) + output_asm_insn ("addl2 $4,%0", &addreg1); + } + + output_asm_insn (singlemove_string (latehalf), latehalf); + + if (addreg0 && addreg1 && (rtx_equal_p (addreg0,addreg1))) + output_asm_insn ("subl2 $4,%0", &addreg0); + else + { + if (addreg0) + output_asm_insn ("subl2 $4,%0", &addreg0); + if (addreg1) + output_asm_insn ("subl2 $4,%0", &addreg1); + } + + if (shftreg0 && shftreg1 && (rtx_equal_p (shftreg0,shftreg1))) + output_asm_insn ("shar $1,%0,%0", &shftreg0); + else + { + if (shftreg0) + output_asm_insn ("shar $1,%0,%0", &shftreg0); + if (shftreg1) + output_asm_insn ("shar $1,%0,%0", &shftreg1); + } + + return ""; +} diff --git a/gcc-1.40/config/out-vax.c b/gcc-1.40/config/out-vax.c new file mode 100644 index 0000000..a17590b --- /dev/null +++ b/gcc-1.40/config/out-vax.c @@ -0,0 +1,152 @@ +/* Subroutines for insn-output.c for Vax. + Copyright (C) 1987 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 1, 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 + +/* This function allows any constant operand, even on VMS where some + constants are not normally legitimate. */ + +int +supergeneral_operand (x, mode) + rtx x; + enum machine_mode mode; +{ + return (CONSTANT_P (x) || general_operand (x, mode)); +} + +print_operand_address (file, addr) + FILE *file; + register rtx addr; +{ + register rtx reg1, reg2, breg, ireg; + rtx offset; + + retry: + switch (GET_CODE (addr)) + { + case MEM: + fprintf (file, "*"); + addr = XEXP (addr, 0); + goto retry; + + case REG: + fprintf (file, "(%s)", reg_names[REGNO (addr)]); + break; + + case PRE_DEC: + fprintf (file, "-(%s)", reg_names[REGNO (XEXP (addr, 0))]); + break; + + case POST_INC: + fprintf (file, "(%s)+", reg_names[REGNO (XEXP (addr, 0))]); + break; + + case PLUS: + reg1 = 0; reg2 = 0; + ireg = 0; breg = 0; + offset = 0; + if (CONSTANT_ADDRESS_P (XEXP (addr, 0)) + || GET_CODE (XEXP (addr, 0)) == MEM) + { + offset = XEXP (addr, 0); + addr = XEXP (addr, 1); + } + else if (CONSTANT_ADDRESS_P (XEXP (addr, 1)) + || GET_CODE (XEXP (addr, 1)) == MEM) + { + offset = XEXP (addr, 1); + addr = XEXP (addr, 0); + } + if (GET_CODE (addr) != PLUS) + ; + else if (GET_CODE (XEXP (addr, 0)) == MULT) + { + reg1 = XEXP (addr, 0); + addr = XEXP (addr, 1); + } + else if (GET_CODE (XEXP (addr, 1)) == MULT) + { + reg1 = XEXP (addr, 1); + addr = XEXP (addr, 0); + } + else if (GET_CODE (XEXP (addr, 0)) == REG) + { + reg1 = XEXP (addr, 0); + addr = XEXP (addr, 1); + } + else if (GET_CODE (XEXP (addr, 1)) == REG) + { + 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; + addr = 0; + } + if (offset != 0) + { + if (addr != 0) abort (); + addr = offset; + } + if (reg1 != 0 && GET_CODE (reg1) == MULT) + { + breg = reg2; + ireg = reg1; + } + else if (reg2 != 0 && GET_CODE (reg2) == MULT) + { + breg = reg1; + ireg = reg2; + } + else if (reg2 != 0 || GET_CODE (addr) == MEM) + { + breg = reg2; + ireg = reg1; + } + else + { + breg = reg1; + ireg = reg2; + } + if (addr != 0) + output_address (addr); + if (breg != 0) + { + if (GET_CODE (breg) != REG) + abort (); + fprintf (file, "(%s)", reg_names[REGNO (breg)]); + } + if (ireg != 0) + { + if (GET_CODE (ireg) == MULT) + ireg = XEXP (ireg, 0); + if (GET_CODE (ireg) != REG) + abort (); + fprintf (file, "[%s]", reg_names[REGNO (ireg)]); + } + break; + + default: + output_addr_const (file, addr); + } +} diff --git a/gcc-1.40/config/pyr.md b/gcc-1.40/config/pyr.md new file mode 100644 index 0000000..e8b09d0 --- /dev/null +++ b/gcc-1.40/config/pyr.md @@ -0,0 +1,1377 @@ +;; Machine description for Pyramid 90 Series for GNU C compiler +;; Copyright (C) 1989 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 1, 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. + +;; Instruction patterns. When multiple patterns apply, +;; the first one in the file is chosen. +;; +;; See file "rtl.def" for documentation on define_insn, match_*, et. al. +;; +;; cpp macro #define NOTICE_UPDATE_CC in file tm.h handles condition code +;; updates for most instructions. + +;; * Try using define_insn instead of some peepholes in more places. +;; * Set REG_NOTES:REG_EQUIV for cvt[bh]w loads. This would make the +;; backward scan in sign_extend needless. +;; * Match (pc) (label_ref) case in peephole patterns. +;; * Should optimize +;; "cmpX op1,op2; b{eq,ne} LY; ucmpX op1.op2; b{lt,le,gt,ge} LZ" +;; to +;; "ucmpX op1,op2; b{eq,ne} LY; b{lt,le,gt,ge} LZ" +;; by pre-scanning insn and running notice_update_cc for them. +;; * Is it necessary to do copy_rtx in the test and compare patterns? +;; * Fix true frame pointer omission. +;; * Make the jump tables contain branches, not addresses! This would +;; save us one instruction. +;; * Could the compilcated scheme for compares be simplyfied, if we had +;; no named cmpqi or cmphi patterns, and instead anonymous patterns for +;; the less-than-word compare cases pyr can handle??? +;; * The jump insn seems to accept more than just IR addressing. Would +;; we win by telling GCC? Or can we use movw into the global reg which +;; is a synonym for pc? +;; * More DImode patterns. +;; * Scan backwards in "zero_extendhisi2", "zero_extendqisi2" to find out +;; if the extension can be omitted. +;; * "divmodsi" with Pyramid "ediv" insn. Is it possible in rtl?? +;; * Would "rcsp tmpreg; u?cmp[bh] op1_regdispl(tmpreg),op2" win in +;; comparison with the two extensions and single test generated now? +;; The rcsp insn could be expanded, and moved out of loops by the +;; optimizer, making 1 (64 bit) insn of 3 (32 bit) insns in loops. +;; The rcsp insn could be followed by an add insn, making non-displacement +;; IR addressing sufficient. + +;______________________________________________________________________ +; +; Test and Compare Patterns. +;______________________________________________________________________ + +; The argument for the rather complicated test and compare expansion +; scheme, is the irregular pyramid instructions for these operations. +; 1) Pyramid has different signed and unsigned compares. 2) HImode +; and QImode integers are memory-memory and immediate-memory only. 3) +; Unsigned HImode compares doesn't exist. 4) Only certain +; combinations of addresses are allowed for memory-memory compares. +; Whenever necessary, in order to fulfill these addressing +; constraints, the compare operands are swapped. + +(define_expand "tstsi" + [(set (cc0) + (match_operand:SI 0 "general_operand" ""))] + "" "operands[0] = force_reg (SImode, operands[0]);") + +(define_insn "" + [(set (cc0) + (compare (match_operand:SI 0 "memory_operand" "m") + (match_operand:SI 1 "memory_operand" "m")))] + "weird_memory_memory (operands[0], operands[1])" + "* +{ + rtx br_insn = NEXT_INSN (insn); + RTX_CODE br_code; + + if (GET_CODE (br_insn) != JUMP_INSN) + abort(); + br_code = GET_CODE (XEXP (XEXP (PATTERN (br_insn), 1), 0)); + + weird_memory_memory (operands[0], operands[1]); + + if (swap_operands) + { + cc_status.flags = CC_REVERSED; + if (TRULY_UNSIGNED_COMPARE_P (br_code)) + { + cc_status.mdep = CC_VALID_FOR_UNSIGNED; + return \"ucmpw %0,%1\"; + } + return \"cmpw %0,%1\"; + } + + if (TRULY_UNSIGNED_COMPARE_P (br_code)) + { + cc_status.mdep = CC_VALID_FOR_UNSIGNED; + return \"ucmpw %1,%0\"; + } + return \"cmpw %1,%0\"; +}") + +(define_insn "cmpsi" + [(set (cc0) + (compare (match_operand:SI 0 "general_operand" "r,g") + (match_operand:SI 1 "general_operand" "g,r")))] + "" + "* +{ + rtx br_insn = NEXT_INSN (insn); + RTX_CODE br_code; + + if (GET_CODE (br_insn) != JUMP_INSN) + abort(); + br_code = GET_CODE (XEXP (XEXP (PATTERN (br_insn), 1), 0)); + + if (which_alternative != 0) + { + cc_status.flags = CC_REVERSED; + if (TRULY_UNSIGNED_COMPARE_P (br_code)) + { + cc_status.mdep = CC_VALID_FOR_UNSIGNED; + return \"ucmpw %0,%1\"; + } + return \"cmpw %0,%1\"; + } + + if (TRULY_UNSIGNED_COMPARE_P (br_code)) + { + cc_status.mdep = CC_VALID_FOR_UNSIGNED; + return \"ucmpw %1,%0\"; + } + return \"cmpw %1,%0\"; +}") + +(define_insn "" + [(set (cc0) + (match_operand:SI 0 "general_operand" "r"))] + "" + "* +{ + rtx br_insn = NEXT_INSN (insn); + RTX_CODE br_code; + + if (GET_CODE (br_insn) != JUMP_INSN) + abort(); + br_code = GET_CODE (XEXP (XEXP (PATTERN (br_insn), 1), 0)); + + if (TRULY_UNSIGNED_COMPARE_P (br_code)) + { + cc_status.mdep = CC_VALID_FOR_UNSIGNED; + return \"ucmpw $0,%0\"; + } + return \"mtstw %0,%0\"; +}") + +(define_expand "cmphi" + [(set (cc0) + (compare (match_operand:HI 0 "general_operand" "") + (match_operand:HI 1 "general_operand" "")))] + "" + " +{ + extern rtx test_op0, test_op1; extern enum machine_mode test_mode; + test_op0 = copy_rtx (operands[0]); + test_op1 = copy_rtx (operands[1]); + test_mode = HImode; + DONE; +}") + +(define_insn "tsthi" + [(set (cc0) + (match_operand:HI 0 "nonimmediate_operand" "rm"))] + "" + "* +{ + cc_status.flags = CC_NO_OVERFLOW; + return \"cvthw %0,lr15\"; +}") + +(define_insn "" + [(set (cc0) + (compare (match_operand:HI 0 "memory_operand" "m") + (match_operand:HI 1 "memory_operand" "m")))] + "weird_memory_memory (operands[0], operands[1])" + "* +{ + rtx br_insn = NEXT_INSN (insn); + + if (GET_CODE (br_insn) != JUMP_INSN) + abort(); + + weird_memory_memory (operands[0], operands[1]); + + if (swap_operands) + { + cc_status.flags = CC_REVERSED; + return \"cmph %0,%1\"; + } + + return \"cmph %1,%0\"; +}") + +(define_insn "" + [(set (cc0) + (compare (match_operand:HI 0 "nonimmediate_operand" "r,m") + (match_operand:HI 1 "nonimmediate_operand" "m,r")))] + "(GET_CODE (operands[0]) != GET_CODE (operands[1]))" + "* +{ + rtx br_insn = NEXT_INSN (insn); + + if (GET_CODE (br_insn) != JUMP_INSN) + abort(); + + if (which_alternative != 0) + { + cc_status.flags = CC_REVERSED; + return \"cmph %0,%1\"; + } + + return \"cmph %1,%0\"; +}") + +(define_expand "cmpqi" + [(set (cc0) + (compare (match_operand:QI 0 "general_operand" "") + (match_operand:QI 1 "general_operand" "")))] + "" + " +{ + extern rtx test_op0, test_op1; extern enum machine_mode test_mode; + test_op0 = copy_rtx (operands[0]); + test_op1 = copy_rtx (operands[1]); + test_mode = QImode; + DONE; +}") + +(define_insn "tstqi" + [(set (cc0) + (match_operand:QI 0 "nonimmediate_operand" "rm"))] + "" + "* +{ + cc_status.flags = CC_NO_OVERFLOW; + return \"cvtbw %0,lr15\"; +}") + +(define_insn "" + [(set (cc0) + (compare (match_operand:QI 0 "memory_operand" "m") + (match_operand:QI 1 "memory_operand" "m")))] + "weird_memory_memory (operands[0], operands[1])" + "* +{ + rtx br_insn = NEXT_INSN (insn); + RTX_CODE br_code; + + if (GET_CODE (br_insn) != JUMP_INSN) + abort(); + br_code = GET_CODE (XEXP (XEXP (PATTERN (br_insn), 1), 0)); + + weird_memory_memory (operands[0], operands[1]); + + if (swap_operands) + { + cc_status.flags = CC_REVERSED; + if (TRULY_UNSIGNED_COMPARE_P (br_code)) + { + cc_status.mdep = CC_VALID_FOR_UNSIGNED; + return \"ucmpb %0,%1\"; + } + return \"cmpb %0,%1\"; + } + + if (TRULY_UNSIGNED_COMPARE_P (br_code)) + { + cc_status.mdep = CC_VALID_FOR_UNSIGNED; + return \"ucmpb %1,%0\"; + } + return \"cmpb %1,%0\"; +}") + +(define_insn "" + [(set (cc0) + (compare (match_operand:QI 0 "nonimmediate_operand" "r,m") + (match_operand:QI 1 "nonimmediate_operand" "m,r")))] + "(GET_CODE (operands[0]) != GET_CODE (operands[1]))" + "* +{ + rtx br_insn = NEXT_INSN (insn); + RTX_CODE br_code; + + if (GET_CODE (br_insn) != JUMP_INSN) + abort(); + br_code = GET_CODE (XEXP (XEXP (PATTERN (br_insn), 1), 0)); + + if (which_alternative != 0) + { + cc_status.flags = CC_REVERSED; + if (TRULY_UNSIGNED_COMPARE_P (br_code)) + { + cc_status.mdep = CC_VALID_FOR_UNSIGNED; + return \"ucmpb %0,%1\"; + } + return \"cmpb %0,%1\"; + } + + if (TRULY_UNSIGNED_COMPARE_P (br_code)) + { + cc_status.mdep = CC_VALID_FOR_UNSIGNED; + return \"ucmpb %1,%0\"; + } + return \"cmpb %1,%0\"; +}") + +(define_expand "bgt" + [(set (pc) (if_then_else (gt (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) (pc)))] + "" "extend_and_branch (SIGN_EXTEND);") + +(define_expand "blt" + [(set (pc) (if_then_else (lt (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) (pc)))] + "" "extend_and_branch (SIGN_EXTEND);") + +(define_expand "bge" + [(set (pc) (if_then_else (ge (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) (pc)))] + "" "extend_and_branch (SIGN_EXTEND);") + +(define_expand "ble" + [(set (pc) (if_then_else (le (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) (pc)))] + "" "extend_and_branch (SIGN_EXTEND);") + +(define_expand "beq" + [(set (pc) (if_then_else (eq (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) (pc)))] + "" "extend_and_branch (SIGN_EXTEND);") + +(define_expand "bne" + [(set (pc) (if_then_else (ne (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) (pc)))] + "" "extend_and_branch (SIGN_EXTEND);") + +(define_expand "bgtu" + [(set (pc) (if_then_else (gtu (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) (pc)))] + "" "extend_and_branch (ZERO_EXTEND);") + +(define_expand "bltu" + [(set (pc) (if_then_else (ltu (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) (pc)))] + "" "extend_and_branch (ZERO_EXTEND);") + +(define_expand "bgeu" + [(set (pc) (if_then_else (geu (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) (pc)))] + "" "extend_and_branch (ZERO_EXTEND);") + +(define_expand "bleu" + [(set (pc) (if_then_else (leu (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) (pc)))] + "" "extend_and_branch (ZERO_EXTEND);") + +(define_insn "cmpdf" + [(set (cc0) + (compare (match_operand:DF 0 "register_operand" "r") + (match_operand:DF 1 "register_operand" "r")))] + "" + "cmpd %1,%0") + +(define_insn "cmpsf" + [(set (cc0) + (compare (match_operand:SF 0 "register_operand" "r") + (match_operand:SF 1 "register_operand" "r")))] + "" + "cmpf %1,%0") + +(define_insn "tstdf" + [(set (cc0) + (match_operand:DF 0 "register_operand" "r"))] + "" + "mtstd %0,%0") + +(define_insn "tstsf" + [(set (cc0) + (match_operand:SF 0 "register_operand" "r"))] + "" + "mtstf %0,%0") + +;______________________________________________________________________ +; +; Fixed-point Arithmetic. +;______________________________________________________________________ + +(define_insn "addsi3" + [(set (match_operand:SI 0 "register_operand" "=r,!r") + (plus:SI (match_operand:SI 1 "general_operand" "%0,r") + (match_operand:SI 2 "general_operand" "g,rJ")))] + "" + "* +{ + if (which_alternative == 0) + return \"addw %2,%0\"; + else + { + forget_cc_if_dependent (operands[0]); + return REG_P (operands[2]) + ? \"mova (%2)[%1*1],%0\" : \"mova %a2[%1*1],%0\"; + } +}") + +(define_insn "subsi3" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (minus:SI (match_operand:SI 1 "general_operand" "0,g") + (match_operand:SI 2 "general_operand" "g,0")))] + "" + "* return (which_alternative == 0) ? \"subw %2,%0\" : \"rsubw %1,%0\";") + +(define_insn "mulsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (mult:SI (match_operand:SI 1 "general_operand" "%0") + (match_operand:SI 2 "general_operand" "g")))] + "" + "mulw %2,%0") + +(define_insn "umulsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (umult:SI (match_operand:SI 1 "general_operand" "%0") + (match_operand:SI 2 "general_operand" "g")))] + "" + "umulw %2,%0") + +(define_insn "divsi3" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (div:SI (match_operand:SI 1 "general_operand" "0,g") + (match_operand:SI 2 "general_operand" "g,0")))] + "" + "* return (which_alternative == 0) ? \"divw %2,%0\" : \"rdivw %1,%0\";") + +(define_insn "udivsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (udiv:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "general_operand" "g")))] + "" + "udivw %2,%0") + +(define_insn "modsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (mod:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "general_operand" "g")))] + "" + "modw %2,%0") + +(define_insn "umodsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (umod:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "general_operand" "g")))] + "" + "umodw %2,%0") + +(define_insn "negsi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (neg:SI (match_operand:SI 1 "nonimmediate_operand" "rm")))] + "" + "mnegw %1,%0") + +(define_insn "one_cmplsi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (not:SI (match_operand:SI 1 "nonimmediate_operand" "rm")))] + "" + "mcomw %1,%0") + +(define_insn "abssi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (abs:SI (match_operand:SI 1 "nonimmediate_operand" "rm")))] + "" + "mabsw %1,%0") + +;______________________________________________________________________ +; +; Floating-point Arithmetic. +;______________________________________________________________________ + +(define_insn "adddf3" + [(set (match_operand:DF 0 "register_operand" "=r") + (plus:DF (match_operand:DF 1 "register_operand" "%0") + (match_operand:DF 2 "register_operand" "r")))] + "" + "addd %2,%0") + +(define_insn "addsf3" + [(set (match_operand:SF 0 "register_operand" "=r") + (plus:SF (match_operand:SF 1 "register_operand" "%0") + (match_operand:SF 2 "register_operand" "r")))] + "" + "addf %2,%0") + +(define_insn "subdf3" + [(set (match_operand:DF 0 "register_operand" "=r") + (minus:DF (match_operand:DF 1 "register_operand" "0") + (match_operand:DF 2 "register_operand" "r")))] + "" + "subd %2,%0") + +(define_insn "subsf3" + [(set (match_operand:SF 0 "register_operand" "=r") + (minus:SF (match_operand:SF 1 "register_operand" "0") + (match_operand:SF 2 "register_operand" "r")))] + "" + "subf %2,%0") + +(define_insn "muldf3" + [(set (match_operand:DF 0 "register_operand" "=r") + (mult:DF (match_operand:DF 1 "register_operand" "%0") + (match_operand:DF 2 "register_operand" "r")))] + "" + "muld %2,%0") + +(define_insn "mulsf3" + [(set (match_operand:SF 0 "register_operand" "=r") + (mult:SF (match_operand:SF 1 "register_operand" "%0") + (match_operand:SF 2 "register_operand" "r")))] + "" + "mulf %2,%0") + +(define_insn "divdf3" + [(set (match_operand:DF 0 "register_operand" "=r") + (div:DF (match_operand:DF 1 "register_operand" "0") + (match_operand:DF 2 "register_operand" "r")))] + "" + "divd %2,%0") + +(define_insn "divsf3" + [(set (match_operand:SF 0 "register_operand" "=r") + (div:SF (match_operand:SF 1 "register_operand" "0") + (match_operand:SF 2 "register_operand" "r")))] + "" + "divf %2,%0") + +(define_insn "negdf2" + [(set (match_operand:DF 0 "register_operand" "=r") + (neg:DF (match_operand:DF 1 "register_operand" "r")))] + "" + "mnegd %1,%0") + +(define_insn "negsf2" + [(set (match_operand:SF 0 "register_operand" "=r") + (neg:SF (match_operand:SF 1 "register_operand" "r")))] + "" + "mnegf %1,%0") + +(define_insn "absdf2" + [(set (match_operand:DF 0 "register_operand" "=r") + (abs:DF (match_operand:DF 1 "register_operand" "r")))] + "" + "mabsd %1,%0") + +(define_insn "abssf2" + [(set (match_operand:SF 0 "register_operand" "=r") + (abs:SF (match_operand:SF 1 "register_operand" "r")))] + "" + "mabsf %1,%0") + +;______________________________________________________________________ +; +; Logical and Shift Instructions. +;______________________________________________________________________ + +(define_insn "" + [(set (cc0) + (and:SI (match_operand:SI 0 "general_operand" "%r") + (match_operand:SI 1 "general_operand" "g")))] + "" + "* +{ + cc_status.flags |= CC_NO_OVERFLOW; + return \"bitw %1,%0\"; +}") + +(define_insn "andsi3" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (and:SI (match_operand:SI 1 "general_operand" "%0,r") + (match_operand:SI 2 "general_operand" "g,K")))] + "" + "* +{ + if (which_alternative == 0) + return \"andw %2,%0\"; + + cc_status.flags = CC_NOT_NEGATIVE; + return (INTVAL (operands[2]) == 255 + ? \"movzbw %1,%0\" : \"movzhw %1,%0\"); +}") + +(define_insn "andcbsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (and:SI (match_operand:SI 1 "register_operand" "0") + (not:SI (match_operand:SI 2 "general_operand" "g"))))] + "" + "bicw %2,%0") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (and:SI (not:SI (match_operand:SI 1 "general_operand" "g")) + (match_operand:SI 2 "register_operand" "0")))] + "" + "bicw %1,%0") + +(define_insn "iorsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (ior:SI (match_operand:SI 1 "general_operand" "%0") + (match_operand:SI 2 "general_operand" "g")))] + "" + "orw %2,%0") + +(define_insn "xorsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (xor:SI (match_operand:SI 1 "general_operand" "%0") + (match_operand:SI 2 "general_operand" "g")))] + "" + "xorw %2,%0") + +; The arithmetic left shift instructions work strangely on pyramids. +; They fail to modify the sign bit. Therefore, use logic shifts. + +(define_insn "ashlsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (ashift:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "general_operand" "rnm")))] + "" + "* return output_shift (\"lshlw %2,%0\", operands[2], 32); ") + +(define_insn "ashrsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (ashiftrt:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "general_operand" "rnm")))] + "" + "* return output_shift (\"ashrw %2,%0\", operands[2], 32); ") + +(define_insn "ashrdi3" + [(set (match_operand:DI 0 "register_operand" "=r") + (ashiftrt:DI (match_operand:DI 1 "register_operand" "0") + (match_operand:SI 2 "general_operand" "rnm")))] + "" + "* return output_shift (\"ashrl %2,%0\", operands[2], 64); ") + +(define_insn "lshrsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (lshiftrt:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "general_operand" "rnm")))] + "" + "* return output_shift (\"lshrw %2,%0\", operands[2], 32); ") + +(define_insn "rotlsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (rotate:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "general_operand" "rnm")))] + "" + "* return output_shift (\"rotlw %2,%0\", operands[2], 32); ") + +(define_insn "rotrsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (rotatert:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "general_operand" "rnm")))] + "" + "* return output_shift (\"rotrw %2,%0\", operands[2], 32); ") + +;______________________________________________________________________ +; +; Fixed and Floating Moves. +;______________________________________________________________________ + +;; If the destination is a memory operand, indexed source operands are +;; disallowed. Big DImode constants are always loaded into a reg pair, +;; although offsetable memory addresses really could be dealt with. + +(define_insn "" + [(set (match_operand:DI 0 "memory_operand" "=m") + (match_operand:DI 1 "nonindexed_operand" "gF"))] + "(GET_CODE (operands[1]) == CONST_DOUBLE + ? ((CONST_DOUBLE_HIGH (operands[1]) == 0 + && CONST_DOUBLE_LOW (operands[1]) >= 0) + || (CONST_DOUBLE_HIGH (operands[1]) == -1 + && CONST_DOUBLE_LOW (operands[1]) < 0)) + : 1)" + "* +{ + if (GET_CODE (operands[1]) == CONST_DOUBLE) + operands[1] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_LOW (operands[1])); + return \"movl %1,%0\"; +}") + +;; Force the destination to a register, so all source operands are allowed. + +(define_insn "movdi" + [(set (match_operand:DI 0 "general_operand" "=r") + (match_operand:DI 1 "general_operand" "gF"))] + "" + "* return output_move_double (operands); ") + +;; If the destination is a memory address, indexed source operands are +;; disallowed. + +(define_insn "" + [(set (match_operand:SI 0 "memory_operand" "=m") + (match_operand:SI 1 "nonindexed_operand" "g"))] + "" + "movw %1,%0") + +;; Force the destination to a register, so all source operands are allowed. + +(define_insn "movsi" + [(set (match_operand:SI 0 "general_operand" "=r") + (match_operand:SI 1 "general_operand" "g"))] + "" + "movw %1,%0") + +;; If the destination is a memory address, indexed source operands are +;; disallowed. + +(define_insn "" + [(set (match_operand:HI 0 "memory_operand" "=m") + (match_operand:HI 1 "nonindexed_operand" "g"))] + "" + "* +{ + if (REG_P (operands[1])) + return \"cvtwh %1,%0\"; /* reg -> mem */ + else + return \"movh %1,%0\"; /* mem imm -> mem */ +}") + +;; Force the destination to a register, so all source operands are allowed. + +(define_insn "movhi" + [(set (match_operand:HI 0 "general_operand" "=r") + (match_operand:HI 1 "general_operand" "g"))] + "" + "* +{ + if (GET_CODE (operands[1]) != MEM) + return \"movw %1,%0\"; /* reg imm -> reg */ + return \"cvthw %1,%0\"; /* mem -> reg */ +}") + +;; If the destination is a memory address, indexed source operands are +;; disallowed. + +(define_insn "" + [(set (match_operand:QI 0 "memory_operand" "=m") + (match_operand:QI 1 "nonindexed_operand" "g"))] + "" + "* +{ + if (REG_P (operands[1])) + return \"cvtwb %1,%0\"; /* reg -> mem */ + else + return \"movb %1,%0\"; /* mem imm -> mem */ +}") + +;; Force the destination to a register, so all source operands are allowed. + +(define_insn "movqi" + [(set (match_operand:QI 0 "general_operand" "=r") + (match_operand:QI 1 "general_operand" "g"))] + "" + "* +{ + if (GET_CODE (operands[1]) != MEM) + return \"movw %1,%0\"; /* reg imm -> reg */ + return \"cvtbw %1,%0\"; /* mem -> reg */ +}") + +;; If the destination is a memory address, indexed source operands are +;; disallowed. + +(define_insn "" + [(set (match_operand:DF 0 "memory_operand" "=m") + (match_operand:DF 1 "nonindexed_operand" "g"))] + "GET_CODE (operands[1]) != CONST_DOUBLE" + "movl %1,%0") + +;; Force the destination to a register, so all source operands are allowed. + +(define_insn "movdf" + [(set (match_operand:DF 0 "general_operand" "=r") + (match_operand:DF 1 "general_operand" "gF"))] + "" + "* return output_move_double (operands); ") + +;; If the destination is a memory address, indexed source operands are +;; disallowed. + +(define_insn "" + [(set (match_operand:SF 0 "memory_operand" "=m") + (match_operand:SF 1 "nonindexed_operand" "g"))] + "" + "movw %1,%0") + +;; Force the destination to a register, so all source operands are allowed. + +(define_insn "movsf" + [(set (match_operand:SF 0 "general_operand" "=r") + (match_operand:SF 1 "general_operand" "g"))] + "" + "movw %1,%0") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (match_operand:QI 1 "address_operand" "p"))] + "" + "* +{ + forget_cc_if_dependent (operands[0]); + return \"mova %a1,%0\"; +}") + +;______________________________________________________________________ +; +; Conversion patterns. +;______________________________________________________________________ + +;; The trunc patterns are used only when non compile-time constants are used. + +(define_insn "truncsiqi2" + [(set (match_operand:QI 0 "register_operand" "=r") + (truncate:QI (match_operand:SI 1 "nonimmediate_operand" "rm")))] + "" + "* +{ + if (REG_P (operands[0]) && REG_P (operands[1]) + && REGNO (operands[0]) == REGNO (operands[1])) + { + cc_status = cc_prev_status; + return \"\"; + } + forget_cc_if_dependent (operands[0]); + return \"movw %1,%0\"; +}") + +(define_insn "truncsihi2" + [(set (match_operand:HI 0 "register_operand" "=r") + (truncate:HI (match_operand:SI 1 "nonimmediate_operand" "rm")))] + "" + "* +{ + if (REG_P (operands[0]) && REG_P (operands[1]) + && REGNO (operands[0]) == REGNO (operands[1])) + { + cc_status = cc_prev_status; + return \"\"; + } + forget_cc_if_dependent (operands[0]); + return \"movw %1,%0\"; +}") + +(define_insn "extendhisi2" + [(set (match_operand:SI 0 "general_operand" "=r,m") + (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "rm,r")))] + "" + "* +{ + extern int optimize; + if (optimize && REG_P (operands[0]) && REG_P (operands[1]) + && REGNO (operands[0]) == REGNO (operands[1]) + && already_sign_extended (insn, HImode, operands[0])) + { + cc_status = cc_prev_status; + return \"\"; + } + return \"cvthw %1,%0\"; +}") + +(define_insn "extendqisi2" + [(set (match_operand:SI 0 "general_operand" "=r,m") + (sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "rm,r")))] + "" + "* +{ + extern int optimize; + if (optimize && REG_P (operands[0]) && REG_P (operands[1]) + && REGNO (operands[0]) == REGNO (operands[1]) + && already_sign_extended (insn, QImode, operands[0])) + { + cc_status = cc_prev_status; + return \"\"; + } + return \"cvtbw %1,%0\"; +}") + +; Pyramid doesn't have insns *called* "cvtbh" or "movzbh". +; But we can cvtbw/movzbw into a register, where there is no distinction +; between words and halfwords. + +(define_insn "extendqihi2" + [(set (match_operand:HI 0 "register_operand" "=r") + (sign_extend:HI (match_operand:QI 1 "nonimmediate_operand" "rm")))] + "" + "cvtbw %1,%0") + +(define_insn "zero_extendhisi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "rm")))] + "" + "* +{ + cc_status.flags = CC_NOT_NEGATIVE; + return \"movzhw %1,%0\"; +}") + +(define_insn "zero_extendqisi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "rm")))] + "" + "* +{ + cc_status.flags = CC_NOT_NEGATIVE; + return \"movzbw %1,%0\"; +}") + +(define_insn "zero_extendqihi2" + [(set (match_operand:HI 0 "register_operand" "=r") + (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "rm")))] + "" + "* +{ + cc_status.flags = CC_NOT_NEGATIVE; + return \"movzbw %1,%0\"; +}") + +(define_insn "extendsfdf2" + [(set (match_operand:DF 0 "general_operand" "=&r,m") + (float_extend:DF (match_operand:SF 1 "nonimmediate_operand" "rm,r")))] + "" + "cvtfd %1,%0") + +(define_insn "truncdfsf2" + [(set (match_operand:SF 0 "general_operand" "=&r,m") + (float_truncate:SF (match_operand:DF 1 "nonimmediate_operand" "rm,r")))] + "" + "cvtdf %1,%0") + +(define_insn "floatsisf2" + [(set (match_operand:SF 0 "general_operand" "=&r,m") + (float:SF (match_operand:SI 1 "nonimmediate_operand" "rm,r")))] + "" + "cvtwf %1,%0") + +(define_insn "floatsidf2" + [(set (match_operand:DF 0 "general_operand" "=&r,m") + (float:DF (match_operand:SI 1 "nonimmediate_operand" "rm,r")))] + "" + "cvtwd %1,%0") + +(define_insn "fix_truncsfsi2" + [(set (match_operand:SI 0 "general_operand" "=&r,m") + (fix:SI (fix:SF (match_operand:SF 1 "nonimmediate_operand" "rm,r"))))] + "" + "cvtfw %1,%0") + +(define_insn "fix_truncdfsi2" + [(set (match_operand:SI 0 "general_operand" "=&r,m") + (fix:SI (fix:DF (match_operand:DF 1 "nonimmediate_operand" "rm,r"))))] + "" + "cvtdw %1,%0") + +;______________________________________________________________________ +; +; Flow Control Patterns. +;______________________________________________________________________ + +;; Prefer "br" to "jump" for unconditional jumps, since it's faster. +;; (The assembler can manage with out-of-range branches.) + +(define_insn "jump" + [(set (pc) + (label_ref (match_operand 0 "" "")))] + "" + "br %l0") + +(define_insn "" + [(set (pc) + (if_then_else (match_operator 0 "relop" [(cc0) (const_int 0)]) + (label_ref (match_operand 1 "" "")) + (pc)))] + "" + "* +{ + extern int optimize; + if (optimize) + switch (GET_CODE (operands[0])) + { + case EQ: case NE: + break; + case LT: case LE: case GE: case GT: + if (cc_prev_status.mdep == CC_VALID_FOR_UNSIGNED) + return 0; + break; + case LTU: case LEU: case GEU: case GTU: + if (cc_prev_status.mdep != CC_VALID_FOR_UNSIGNED) + return 0; + break; + } + + return \"b%N0 %l1\"; +}") + +(define_insn "" + [(set (pc) + (if_then_else (match_operator 0 "relop" [(cc0) (const_int 0)]) + (pc) + (label_ref (match_operand 1 "" ""))))] + "" + "* +{ + extern int optimize; + if (optimize) + switch (GET_CODE (operands[0])) + { + case EQ: case NE: + break; + case LT: case LE: case GE: case GT: + if (cc_prev_status.mdep == CC_VALID_FOR_UNSIGNED) + return 0; + break; + case LTU: case LEU: case GEU: case GTU: + if (cc_prev_status.mdep != CC_VALID_FOR_UNSIGNED) + return 0; + break; + } + + return \"b%C0 %l1\"; +}") + +(define_insn "call" + [(call (match_operand:QI 0 "memory_operand" "m") + (match_operand:SI 1 "immediate_operand" "n"))] + "" + "call %0") + +(define_insn "call_value" + [(set (match_operand 0 "" "=r") + (call (match_operand:QI 1 "memory_operand" "m") + (match_operand:SI 2 "immediate_operand" "n")))] + ;; Operand 2 not really used on Pyramid architecture. + "" + "call %1") + +(define_insn "return" + [(return)] + "" + "* +{ + if (get_frame_size () + current_function_pretend_args_size + + current_function_args_size != 0 + || current_function_calls_alloca) + { + int dealloc_size = current_function_pretend_args_size; + if (current_function_pops_args) + dealloc_size += current_function_args_size; + operands[0] = gen_rtx (CONST_INT, VOIDmode, dealloc_size); + return \"retd %0\"; + } + else + return \"ret\"; +}") + +(define_insn "tablejump" + [(set (pc) (match_operand:SI 0 "register_operand" "r")) + (use (label_ref (match_operand 1 "" "")))] + "" + "jump (%0)") + +(define_insn "nop" + [(const_int 0)] + "" + "movw gr0,gr0 # nop") + +;______________________________________________________________________ +; +; Peep-hole Optimization Patterns. +;______________________________________________________________________ + +;; Optimize fullword move followed by a test of the moved value. + +(define_peephole + [(set (match_operand:SI 0 "register_operand" "=r") + (match_operand:SI 1 "nonimmediate_operand" "rm")) + (set (cc0) (match_operand:SI 2 "nonimmediate_operand" "rm"))] + "rtx_equal_p (operands[2], operands[0]) + || rtx_equal_p (operands[2], operands[1])" + "* + cc_status.flags |= CC_NO_OVERFLOW; + return \"mtstw %1,%0\"; +") + +;; Same for HI and QI mode move-test as well. + +(define_peephole + [(set (match_operand:HI 0 "register_operand" "=r") + (match_operand:HI 1 "nonimmediate_operand" "rm")) + (set (match_operand:SI 2 "register_operand" "=r") + (sign_extend:SI (match_operand:HI 3 "nonimmediate_operand" "rm"))) + (set (cc0) (match_dup 2))] + "dead_or_set_p (insn, operands[2]) + && (rtx_equal_p (operands[3], operands[0]) + || rtx_equal_p (operands[3], operands[1]))" + "* + cc_status.flags |= CC_NO_OVERFLOW; + return \"cvthw %1,%0\"; +") + +(define_peephole + [(set (match_operand:QI 0 "register_operand" "=r") + (match_operand:QI 1 "nonimmediate_operand" "rm")) + (set (match_operand:SI 2 "register_operand" "=r") + (sign_extend:SI (match_operand:QI 3 "nonimmediate_operand" "rm"))) + (set (cc0) (match_dup 2))] + "dead_or_set_p (insn, operands[2]) + && (rtx_equal_p (operands[3], operands[0]) + || rtx_equal_p (operands[3], operands[1]))" + "* + cc_status.flags |= CC_NO_OVERFLOW; + return \"cvtbw %1,%0\"; +") + +;; Optimize loops with an incremented/decremented variable. + +(define_peephole + [(set (match_operand:SI 0 "register_operand" "=r") + (plus:SI (match_dup 0) + (const_int -1))) + (set (cc0) + (compare (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "nonmemory_operand" "ri"))) + (set (pc) + (if_then_else (match_operator:SI 3 "signed_comparison" + [(cc0) (const_int 0)]) + (label_ref (match_operand 4 "" "")) + (pc)))] + "(GET_CODE (operands[2]) == CONST_INT + ? (unsigned)INTVAL (operands[2]) + 32 >= 64 + : 1) && (rtx_equal_p (operands[0], operands[1]) + || rtx_equal_p (operands[0], operands[2]))" + "* + if (rtx_equal_p (operands[0], operands[1])) + { + output_asm_insn (\"dcmpw %2,%0\", operands); + return \"b%N3 %l4\"; + } + else + { + output_asm_insn (\"dcmpw %1,%0\", operands); + return \"b%R3 %l4\"; + } +") + +(define_peephole + [(set (match_operand:SI 0 "register_operand" "=r") + (plus:SI (match_dup 0) + (const_int 1))) + (set (cc0) + (compare (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "nonmemory_operand" "ri"))) + (set (pc) + (if_then_else (match_operator:SI 3 "signed_comparison" + [(cc0) (const_int 0)]) + (label_ref (match_operand 4 "" "")) + (pc)))] + "(GET_CODE (operands[2]) == CONST_INT + ? (unsigned)INTVAL (operands[2]) + 32 >= 64 + : 1) && (rtx_equal_p (operands[0], operands[1]) + || rtx_equal_p (operands[0], operands[2]))" + "* + if (rtx_equal_p (operands[0], operands[1])) + { + output_asm_insn (\"icmpw %2,%0\", operands); + return \"b%N3 %l4\"; + } + else + { + output_asm_insn (\"icmpw %1,%0\", operands); + return \"b%R3 %l4\"; + } +") + +;; Combine two word moves with consecutive operands into one long move. +;; Also combines immediate moves, if the high-order destination operand +;; is loaded with 0 or -1 and the low-order destination operand is loaded +;; with a constant with the same sign. + +(define_peephole + [(set (match_operand:SI 0 "general_operand" "=g") + (match_operand:SI 1 "general_operand" "g")) + (set (match_operand:SI 2 "general_operand" "=g") + (match_operand:SI 3 "general_operand" "g"))] + "movdi_possible (operands)" + "* + output_asm_insn (\"# COMBINE movw %1,%0\", operands); + output_asm_insn (\"# COMBINE movw %3,%2\", operands); + movdi_possible (operands); + if (CONSTANT_P (operands[1])) + return (swap_operands) ? \"movl %3,%0\" : \"movl %1,%2\"; + + return (swap_operands) ? \"movl %1,%0\" : \"movl %3,%2\"; +") + +;; Optimize certain tests after memory stores. + +(define_peephole + [(set (match_operand 0 "memory_operand" "=m") + (match_operand 1 "register_operand" "r")) + (set (match_operand:SI 2 "register_operand" "=r") + (sign_extend:SI (match_dup 1))) + (set (cc0) + (match_dup 2))] + "dead_or_set_p (insn, operands[2])" + "* + cc_status.flags |= CC_NO_OVERFLOW; + if (GET_MODE (operands[0]) == QImode) + return \"cvtwb %1,%0\"; + else + return \"cvtwh %1,%0\"; +") + +;______________________________________________________________________ +; +; DImode Patterns. +;______________________________________________________________________ + +(define_expand "extendsidi2" + [(set (subreg:SI (match_operand:DI 0 "register_operand" "=r") 1) + (match_operand:SI 1 "general_operand" "g")) + (set (subreg:SI (match_dup 0) 0) + (subreg:SI (match_dup 0) 1)) + (set (subreg:SI (match_dup 0) 0) + (ashiftrt:SI (subreg:SI (match_dup 0) 0) + (const_int 31)))] + "" + "") + +(define_insn "adddi3" + [(set (match_operand:DI 0 "register_operand" "=r") + (plus:DI (match_operand:DI 1 "nonmemory_operand" "%0") + (match_operand:DI 2 "nonmemory_operand" "rF")))] + "" + "* +{ + rtx xoperands[2]; + CC_STATUS_INIT; + xoperands[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); + if (REG_P (operands[2])) + xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[2]) + 1); + else + { + xoperands[1] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_LOW (operands[2])); + operands[2] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_HIGH (operands[2])); + } + output_asm_insn (\"addw %1,%0\", xoperands); + return \"addwc %2,%0\"; +}") + +(define_insn "subdi3" + [(set (match_operand:DI 0 "register_operand" "=r") + (minus:DI (match_operand:DI 1 "register_operand" "0") + (match_operand:DI 2 "nonmemory_operand" "rF")))] + "" + "* +{ + rtx xoperands[2]; + CC_STATUS_INIT; + xoperands[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); + if (REG_P (operands[2])) + xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[2]) + 1); + else + { + xoperands[1] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_LOW (operands[2])); + operands[2] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_HIGH (operands[2])); + } + output_asm_insn (\"subw %1,%0\", xoperands); + return \"subwb %2,%0\"; +}") + +(define_insn "iordi3" + [(set (match_operand:DI 0 "register_operand" "=r") + (ior:DI (match_operand:DI 1 "nonmemory_operand" "%0") + (match_operand:DI 2 "nonmemory_operand" "rF")))] + "" + "* +{ + rtx xoperands[2]; + CC_STATUS_INIT; + xoperands[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); + if (REG_P (operands[2])) + xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[2]) + 1); + else + { + xoperands[1] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_LOW (operands[2])); + operands[2] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_HIGH (operands[2])); + } + output_asm_insn (\"orw %1,%0\", xoperands); + return \"orw %2,%0\"; +}") + +(define_insn "anddi3" + [(set (match_operand:DI 0 "register_operand" "=r") + (and:DI (match_operand:DI 1 "nonmemory_operand" "%0") + (match_operand:DI 2 "nonmemory_operand" "rF")))] + "" + "* +{ + rtx xoperands[2]; + CC_STATUS_INIT; + xoperands[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); + if (REG_P (operands[2])) + xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[2]) + 1); + else + { + xoperands[1] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_LOW (operands[2])); + operands[2] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_HIGH (operands[2])); + } + output_asm_insn (\"andw %1,%0\", xoperands); + return \"andw %2,%0\"; +}") + +(define_insn "xordi3" + [(set (match_operand:DI 0 "register_operand" "=r") + (xor:DI (match_operand:DI 1 "nonmemory_operand" "%0") + (match_operand:DI 2 "nonmemory_operand" "rF")))] + "" + "* +{ + rtx xoperands[2]; + CC_STATUS_INIT; + xoperands[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); + if (REG_P (operands[2])) + xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[2]) + 1); + else + { + xoperands[1] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_LOW (operands[2])); + operands[2] = gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_HIGH (operands[2])); + } + output_asm_insn (\"xorw %1,%0\", xoperands); + return \"xorw %2,%0\"; +}") + +;;- Local variables: +;;- mode:emacs-lisp +;;- comment-start: ";;- " +;;- eval: (set-syntax-table (copy-sequence (syntax-table))) +;;- eval: (modify-syntax-entry ?] ")[") +;;- eval: (modify-syntax-entry ?{ "(}") +;;- eval: (modify-syntax-entry ?} "){") +;;- End: diff --git a/gcc-1.40/config/sparc.md b/gcc-1.40/config/sparc.md new file mode 100644 index 0000000..e3d7b64 --- /dev/null +++ b/gcc-1.40/config/sparc.md @@ -0,0 +1,2370 @@ + +;;- Machine description for SPARC chip for GNU C compiler +;; Copyright (C) 1988, 1989 Free Software Foundation, Inc. +;; Contributed by Michael Tiemann (tiemann@mcc.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 1, 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. + + +;;- See file "rtl.def" for documentation on define_insn, match_*, et. al. + +;;- cpp macro #define NOTICE_UPDATE_CC in file tm.h handles condition code +;;- updates for most instructions. + +;;- Operand classes for the register allocator: + +;; Compare instructions. +;; This controls RTL generation and register allocation. + +;; Put cmpsi first among compare insns so it matches two CONST_INT operands. + +(define_insn "cmpsi" + [(set (cc0) + (compare (match_operand:SI 0 "arith_operand" "r,rI") + (match_operand:SI 1 "arith_operand" "I,r")))] + "" + "* +{ + if (! REG_P (operands[0])) + { + cc_status.flags |= CC_REVERSED; + return \"cmp %1,%0\"; + } + return \"cmp %0,%1\"; +}") + +(define_expand "cmpdf" + [(set (cc0) + (compare (match_operand:DF 0 "nonmemory_operand" "f,fG") + (match_operand:DF 1 "nonmemory_operand" "G,f")))] + "" + "emit_insn (gen_rtx (USE, VOIDmode, gen_rtx (REG, DFmode, 32)));") + +(define_insn "" + [(set (cc0) + (compare (match_operand:DF 0 "nonmemory_operand" "f,fG") + (match_operand:DF 1 "nonmemory_operand" "G,f")))] + "GET_CODE (operands[0]) != CONST_INT && GET_CODE (operands[1]) != CONST_INT" + "* +{ + if (GET_CODE (operands[0]) == CONST_DOUBLE + || GET_CODE (operands[1]) == CONST_DOUBLE) + make_f0_contain_0 (2); + + cc_status.flags |= CC_IN_FCCR; + if (GET_CODE (operands[0]) == CONST_DOUBLE) + return \"fcmped %%f0,%1\;nop\"; + if (GET_CODE (operands[1]) == CONST_DOUBLE) + return \"fcmped %0,%%f0\;nop\"; + return \"fcmped %0,%1\;nop\"; +}") + +(define_expand "cmpsf" + [(set (cc0) + (compare (match_operand:SF 0 "nonmemory_operand" "f,fG") + (match_operand:SF 1 "nonmemory_operand" "G,f")))] + "" + "emit_insn (gen_rtx (USE, VOIDmode, gen_rtx (REG, SFmode, 32)));") + +(define_insn "" + [(set (cc0) + (compare (match_operand:SF 0 "nonmemory_operand" "f,fG") + (match_operand:SF 1 "nonmemory_operand" "G,f")))] + "GET_CODE (operands[0]) != CONST_INT && GET_CODE (operands[1]) != CONST_INT" + "* +{ + if (GET_CODE (operands[0]) == CONST_DOUBLE + || GET_CODE (operands[1]) == CONST_DOUBLE) + make_f0_contain_0 (1); + + cc_status.flags |= CC_IN_FCCR; + if (GET_CODE (operands[0]) == CONST_DOUBLE) + return \"fcmpes %%f0,%1\;nop\"; + if (GET_CODE (operands[1]) == CONST_DOUBLE) + return \"fcmpes %0,%%f0\;nop\"; + return \"fcmpes %0,%1\;nop\"; +}") + +;; Put tstsi first among test insns so it matches a CONST_INT operand. + +(define_insn "tstsi" + [(set (cc0) + (match_operand:SI 0 "register_operand" "r"))] + "" + "tst %0") + +;; Need this to take a general operand because cse can make +;; a CONST which won't be in a register. +(define_insn "" + [(set (cc0) + (match_operand:SI 0 "immediate_operand" "i"))] + "" + "set %0,%%g1\;tst %%g1") + +;; Optimize the case of following a reg-reg move with a test +;; of reg just moved. + +(define_peephole + [(set (match_operand:SI 0 "register_operand" "=r") + (match_operand:SI 1 "register_operand" "r")) + (set (cc0) (match_operand:SI 2 "register_operand" "r"))] + "operands[2] == operands[0] + || operands[2] == operands[1]" + "orcc %1,%%g0,%0 ! 2-insn combine") + +;; Optimize 5(6) insn sequence to 3(4) insns. +;; These patterns could also optimize more complicated sets +;; before conditional branches. + +;; Turned off because (1) this case is rarely encounted +;; (2) to be correct, more conditions must be checked +;; (3) the conditions must be checked with rtx_equal_p, not == +;; (4) when branch scheduling is added to the compiler, +;; this optimization will be performed by the branch scheduler +;; Bottom line: it is not worth the trouble of fixing or +;; maintaining it. + +;(define_peephole +; [(set (match_operand:SI 0 "register_operand" "=r") +; (match_operand:SI 1 "general_operand" "g")) +; (set (match_operand:SI 2 "register_operand" "=r") +; (match_operand:SI 3 "reg_or_0_operand" "rJ")) +; (set (cc0) (match_operand:SI 4 "register_operand" "r")) +; (set (pc) (match_operand 5 "" ""))] +; "GET_CODE (operands[5]) == IF_THEN_ELSE +; && operands[0] != operands[3] +; && ! reg_mentioned_p (operands[2], operands[1]) +; && (operands[4] == operands[0] +; || operands[4] == operands[2] +; || operands[4] == operands[3])" +; "* +;{ +; rtx xoperands[2]; +; int parity; +; xoperands[0] = XEXP (operands[5], 0); +; if (GET_CODE (XEXP (operands[5], 1)) == PC) +; { +; parity = 1; +; xoperands[1] = XEXP (XEXP (operands[5], 2), 0); +; } +; else +; { +; parity = 0; +; xoperands[1] = XEXP (XEXP (operands[5], 1), 0); +; } +; +; if (operands[4] == operands[0]) +; { +; /* Although the constraints for operands[1] permit a general +; operand (and hence possibly a const_int), we know that +; in this branch it cannot be a CONST_INT, since that would give +; us a fixed condition, and those should have been optimized away. */ +; if (REG_P (operands[1])) +; output_asm_insn (\"orcc %1,%%g0,%0 ! 3-insn reorder\", operands); +; else if (GET_CODE (operands[1]) != MEM) +; abort (); +; else +; { +; if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) +; output_asm_insn (\"sethi %%hi(%m1),%%g1\;ld [%%g1+%%lo(%m1)],%0\;tst %0 ! 4-insn reorder\", operands); +; else +; output_asm_insn (\"ld %1,%0\;tst %0 ! 3.5-insn reorder\", operands); +; } +; XVECEXP (PATTERN (insn), 0, 0) = XVECEXP (PATTERN (insn), 0, 2); +; XVECEXP (PATTERN (insn), 0, 1) = XVECEXP (PATTERN (insn), 0, 3); +; } +; else +; { +; output_asm_insn (\"orcc %3,%%g0,%2 ! 3-insn reorder\", operands); +; } +; if (parity) +; return output_delayed_branch (\"b%N0 %l1\", xoperands, insn); +; else +; return output_delayed_branch (\"b%C0 %l1\", xoperands, insn); +;}") + +;; By default, operations don't set the condition codes. +;; These patterns allow cc's to be set, while doing some work + +(define_insn "" + [(set (cc0) + (zero_extend:SI (subreg:QI (match_operand:SI 0 "register_operand" "r") 0)))] + "" + "andcc %0,0xff,%%g0") + +(define_insn "" + [(set (cc0) + (plus:SI (match_operand:SI 0 "register_operand" "r%") + (match_operand:SI 1 "arith_operand" "rI")))] + "ignore_overflow_conditional_p (NEXT_INSN (insn))" + "* +{ + cc_status.flags |= CC_NO_OVERFLOW; + return \"addcc %0,%1,%%g0\"; +}") + +(define_insn "" + [(set (cc0) + (plus:SI (match_operand:SI 0 "register_operand" "r%") + (match_operand:SI 1 "arith_operand" "rI"))) + (set (match_operand:SI 2 "register_operand" "=r") + (plus:SI (match_dup 0) (match_dup 1)))] + "ignore_overflow_conditional_p (NEXT_INSN (insn))" + "* +{ + cc_status.flags |= CC_NO_OVERFLOW; + return \"addcc %0,%1,%2\"; +}") + +(define_insn "" + [(set (cc0) + (minus:SI (match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "arith_operand" "rI")))] + "ignore_overflow_conditional_p (NEXT_INSN (insn))" + "* +{ + cc_status.flags |= CC_NO_OVERFLOW; + return \"subcc %0,%1,%%g0\"; +}") + +(define_insn "" + [(set (cc0) + (minus:SI (match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "arith_operand" "rI"))) + (set (match_operand:SI 2 "register_operand" "=r") + (minus:SI (match_dup 0) (match_dup 1)))] + "ignore_overflow_conditional_p (NEXT_INSN (insn))" + "* +{ + cc_status.flags |= CC_NO_OVERFLOW; + return \"subcc %0,%1,%2\"; +}") + +(define_insn "" + [(set (cc0) + (and:SI (match_operand:SI 0 "register_operand" "r%") + (match_operand:SI 1 "arith_operand" "rI")))] + "" + "andcc %0,%1,%%g0") + +(define_insn "" + [(set (cc0) + (and:SI (match_operand:SI 0 "register_operand" "r%") + (match_operand:SI 1 "arith_operand" "rI"))) + (set (match_operand:SI 2 "register_operand" "=r") + (and:SI (match_dup 0) (match_dup 1)))] + "" + "andcc %0,%1,%2") + +(define_insn "" + [(set (cc0) + (and:SI (match_operand:SI 0 "register_operand" "r") + (not:SI (match_operand:SI 1 "arith_operand" "rI"))))] + "" + "andncc %0,%1,%%g0") + +(define_insn "" + [(set (cc0) + (and:SI (match_operand:SI 0 "register_operand" "r") + (not:SI (match_operand:SI 1 "arith_operand" "rI")))) + (set (match_operand:SI 2 "register_operand" "=r") + (and:SI (match_dup 0) (not:SI (match_dup 1))))] + "" + "andncc %0,%1,%2") + +(define_insn "" + [(set (cc0) + (ior:SI (match_operand:SI 0 "register_operand" "r%") + (match_operand:SI 1 "arith_operand" "rI")))] + "" + "orcc %0,%1,%%g0") + +(define_insn "" + [(set (cc0) + (ior:SI (match_operand:SI 0 "register_operand" "r%") + (match_operand:SI 1 "arith_operand" "rI"))) + (set (match_operand:SI 2 "register_operand" "=r") + (ior:SI (match_dup 0) (match_dup 1)))] + "" + "orcc %0,%1,%2") + +(define_insn "" + [(set (cc0) + (ior:SI (match_operand:SI 0 "register_operand" "r") + (not:SI (match_operand:SI 1 "arith_operand" "rI"))))] + "" + "orncc %0,%1,%%g0") + +(define_insn "" + [(set (cc0) + (ior:SI (match_operand:SI 0 "register_operand" "r") + (not:SI (match_operand:SI 1 "arith_operand" "rI")))) + (set (match_operand:SI 2 "register_operand" "=r") + (ior:SI (match_dup 0) (not:SI (match_dup 1))))] + "" + "orncc %0,%1,%2") + +(define_insn "" + [(set (cc0) + (xor:SI (match_operand:SI 0 "register_operand" "r%") + (match_operand:SI 1 "arith_operand" "rI")))] + "" + "xorcc %0,%1,%%g0") + +(define_insn "" + [(set (cc0) + (xor:SI (match_operand:SI 0 "register_operand" "r%") + (match_operand:SI 1 "arith_operand" "rI"))) + (set (match_operand:SI 2 "register_operand" "=r") + (xor:SI (match_dup 0) (match_dup 1)))] + "" + "xorcc %0,%1,%2") + +(define_insn "" + [(set (cc0) + (xor:SI (match_operand:SI 0 "register_operand" "r") + (not:SI (match_operand:SI 1 "arith_operand" "rI"))))] + "" + "xnorcc %0,%1,%%g0") + +(define_insn "" + [(set (cc0) + (xor:SI (match_operand:SI 0 "register_operand" "r") + (not:SI (match_operand:SI 1 "arith_operand" "rI")))) + (set (match_operand:SI 2 "register_operand" "=r") + (xor:SI (match_dup 0) (not:SI (match_dup 1))))] + "" + "xnorcc %0,%1,%2") + +(define_expand "tstdf" + [(set (cc0) + (match_operand:DF 0 "register_operand" "f"))] + "" + "emit_insn (gen_rtx (CLOBBER, VOIDmode, gen_rtx (REG, DFmode, 32)));") + +(define_insn "" + [(set (cc0) + (match_operand:DF 0 "register_operand" "f"))] + "" + "* +{ + make_f0_contain_0 (2); + cc_status.flags |= CC_IN_FCCR; + return \"fcmped %0,%%f0\;nop\"; +}") + +(define_expand "tstsf" + [(set (cc0) + (match_operand:SF 0 "register_operand" "f"))] + "" + "emit_insn (gen_rtx (CLOBBER, VOIDmode, gen_rtx (REG, SFmode, 32)));") + +(define_insn "" + [(set (cc0) + (match_operand:SF 0 "register_operand" "f"))] + "" + "* +{ + make_f0_contain_0 (1); + cc_status.flags |= CC_IN_FCCR; + return \"fcmpes %0,%%f0\;nop\"; +}") + +;; There are no logical links for the condition codes. This +;; would not normally be a problem, but on the SPARC (and possibly +;; other RISC machines), when argument passing, the insn which sets +;; the condition code and the insn which uses the set condition code +;; may not be performed adjacently (due to optimizations performed +;; in combine.c). To make up for this, we emit insn patterns which +;; cannot possibly be rearranged on us. +(define_expand "seq" + [(set (match_operand:SI 0 "general_operand" "=r") + (eq (cc0) (const_int 0)))] + "" + "gen_scc_insn (EQ, VOIDmode, operands); DONE;") + +(define_expand "sne" + [(set (match_operand:SI 0 "general_operand" "=r") + (ne (cc0) (const_int 0)))] + "" + "gen_scc_insn (NE, VOIDmode, operands); DONE;") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=r,r") + (match_operator 1 "eq_or_neq" + [(compare (match_operand:SI 2 "general_operand" "r,rI") + (match_operand:SI 3 "general_operand" "I,r")) + (const_int 0)]))] + "" + "* +{ + CC_STATUS_INIT; + cc_status.value1 = operands[0]; + if (! REG_P (operands[2])) + { + output_asm_insn (\"cmp %3,%2\", operands); + cc_status.flags |= CC_REVERSED; + } + else + output_asm_insn (\"cmp %2,%3\", operands); + return output_scc_insn (GET_CODE (operands[1]), operands[0]); +}") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=r") + (match_operator 1 "eq_or_neq" + [(match_operand:SI 2 "general_operand" "r") + (const_int 0)]))] + "" + "* +{ + CC_STATUS_INIT; + cc_status.value1 = operands[0]; + output_asm_insn (\"tst %2\", operands); + return output_scc_insn (GET_CODE (operands[1]), operands[0]); +}") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=r,r") + (match_operator 1 "eq_or_neq" + [(compare (match_operand:DF 2 "general_operand" "f,fG") + (match_operand:DF 3 "general_operand" "G,f")) + (const_int 0)]))] + "" + "* +{ + CC_STATUS_INIT; + cc_status.value1 = operands[0]; + cc_status.flags |= CC_IN_FCCR; + + if (GET_CODE (operands[2]) == CONST_DOUBLE + || GET_CODE (operands[3]) == CONST_DOUBLE) + make_f0_contain_0 (2); + + if (GET_CODE (operands[2]) == CONST_DOUBLE) + output_asm_insn (\"fcmped %%f0,%3\;nop\", operands); + else if (GET_CODE (operands[3]) == CONST_DOUBLE) + output_asm_insn (\"fcmped %2,%%f0\;nop\", operands); + else output_asm_insn (\"fcmped %2,%3\;nop\", operands); + return output_scc_insn (GET_CODE (operands[1]), operands[0]); +}") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=r") + (match_operator 1 "eq_or_neq" + [(match_operand:DF 2 "general_operand" "f") + (const_int 0)]))] + "" + "* +{ + CC_STATUS_INIT; + cc_status.value1 = operands[0]; + cc_status.flags |= CC_IN_FCCR; + + make_f0_contain_0 (2); + output_asm_insn (\"fcmped %2,%%f0\;nop\", operands); + return output_scc_insn (GET_CODE (operands[1]), operands[0]); +}") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=r,r") + (match_operator 1 "eq_or_neq" + [(compare (match_operand:SF 2 "general_operand" "f,fG") + (match_operand:SF 3 "general_operand" "G,f")) + (const_int 0)]))] + "" + "* +{ + CC_STATUS_INIT; + cc_status.value1 = operands[0]; + cc_status.flags |= CC_IN_FCCR; + + if (GET_CODE (operands[2]) == CONST_DOUBLE + || GET_CODE (operands[3]) == CONST_DOUBLE) + make_f0_contain_0 (1); + + if (GET_CODE (operands[2]) == CONST_DOUBLE) + output_asm_insn (\"fcmpes %%f0,%3\;nop\", operands); + else if (GET_CODE (operands[3]) == CONST_DOUBLE) + output_asm_insn (\"fcmpes %2,%%f0\;nop\", operands); + else output_asm_insn (\"fcmpes %2,%3\;nop\", operands); + return output_scc_insn (GET_CODE (operands[1]), operands[0]); +}") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=r") + (match_operator 1 "eq_or_neq" + [(match_operand:SF 2 "general_operand" "f") + (const_int 0)]))] + "" + "* +{ + CC_STATUS_INIT; + cc_status.value1 = operands[0]; + cc_status.flags |= CC_IN_FCCR; + + make_f0_contain_0 (1); + output_asm_insn (\"fcmpes %2,%%f0\;nop\", operands); + return output_scc_insn (GET_CODE (operands[1]), operands[0]); +}") + +;; These control RTL generation for conditional jump insns +;; and match them for register allocation. + +(define_insn "beq" + [(set (pc) + (if_then_else (eq (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +{ + OUTPUT_JUMP (\"be %l0\;nop\", \"be %l0\;nop\", \"fbe %l0\;nop\"); +}") + +(define_insn "bne" + [(set (pc) + (if_then_else (ne (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +{ + OUTPUT_JUMP (\"bne %l0\;nop\", \"bne %l0\;nop\", \"fbne %l0\;nop\"); +}") + +(define_insn "bgt" + [(set (pc) + (if_then_else (gt (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +{ + OUTPUT_JUMP (\"bg %l0\;nop\", 0, \"fbg %l0\;nop\"); +}") + +(define_insn "bgtu" + [(set (pc) + (if_then_else (gtu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +{ + if (cc_prev_status.flags & CC_IN_FCCR) + abort (); + return \"bgu %l0\;nop\"; +}") + +(define_insn "blt" + [(set (pc) + (if_then_else (lt (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +{ + OUTPUT_JUMP (\"bl %l0\;nop\", \"bneg %l0\;nop\", \"fbl %l0\;nop\"); +}") + +(define_insn "bltu" + [(set (pc) + (if_then_else (ltu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +{ + if (cc_prev_status.flags & CC_IN_FCCR) + abort (); + return \"blu %l0\;nop\"; +}") + +(define_insn "bge" + [(set (pc) + (if_then_else (ge (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +{ + OUTPUT_JUMP (\"bge %l0\;nop\", \"bpos %l0\;nop\", \"fbge %l0\;nop\"); +}") + +(define_insn "bgeu" + [(set (pc) + (if_then_else (geu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +{ + if (cc_prev_status.flags & CC_IN_FCCR) + abort (); + return \"bgeu %l0\;nop\"; +}") + +(define_insn "ble" + [(set (pc) + (if_then_else (le (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +{ + OUTPUT_JUMP (\"ble %l0\;nop\", 0, \"fble %l0\;nop\"); +}") + +(define_insn "bleu" + [(set (pc) + (if_then_else (leu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +{ + if (cc_prev_status.flags & CC_IN_FCCR) + abort (); + return \"bleu %l0\;nop\"; +}") + +;; This matches inverted jump insns for register allocation. + +(define_insn "" + [(set (pc) + (if_then_else (match_operator 0 "relop" [(cc0) (const_int 0)]) + (pc) + (label_ref (match_operand 1 "" ""))))] + "" + "* +{ + if (cc_prev_status.flags & CC_NO_OVERFLOW) + { + if (GET_CODE (operands[0]) == GT || GET_CODE (operands[0]) == LE) + /* These two conditions can't ignore overflow, + so reinsert the deleted test instruction. */ + return 0; + return \"b%U0 %l1\;nop\"; + } + if (cc_prev_status.flags & CC_IN_FCCR) + return \"fb%F0 %l1\;nop\"; + return \"b%N0 %l1\;nop\"; +}") + +;; Move instructions + +(define_insn "swapsi" + [(set (match_operand:SI 0 "general_operand" "r,rm") + (match_operand:SI 1 "general_operand" "m,r")) + (set (match_dup 1) (match_dup 0))] + "" + "* +{ + if (GET_CODE (operands[1]) == MEM) + { + if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) + output_asm_insn (\"set %a1,%%g1\", operands), + operands[1] = gen_rtx (MEM, SImode, gen_rtx (REG, SImode, 1)), + cc_status.flags &= ~CC_KNOW_HI_G1; + output_asm_insn (\"swap %1,%0\", operands); + } + if (REG_P (operands[0])) + { + if (REGNO (operands[0]) == REGNO (operands[1])) + return \"\"; + return \"xor %0,%1,%0\;xor %1,%0,%1\;xor %0,%1,%0\"; + } + if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) + { + output_asm_insn (\"set %a0,%%g1\", operands); + operands[0] = gen_rtx (MEM, SImode, gen_rtx (REG, SImode, 1)); + cc_status.flags &= ~CC_KNOW_HI_G1; + } + return \"swap %0,%1\"; +}") + +(define_insn "movsi" + [(set (match_operand:SI 0 "general_operand" "=r,m") + (match_operand:SI 1 "general_operand" "rmif,rJ"))] + "" + "* +{ + if (GET_CODE (operands[0]) == MEM) + { + if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) + return output_store (operands); + return \"st %r1,%0\"; + } + if (GET_CODE (operands[1]) == MEM) + { + if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) + return output_load_fixed (operands); + return \"ld %1,%0\"; + } + if (FP_REG_P (operands[1])) + return \"st %r1,[%%fp-4]\;ld [%%fp-4],%0\"; + if (REG_P (operands[1]) + || (GET_CODE (operands[1]) == CONST_INT + && SMALL_INT (operands[1]))) + return \"mov %1,%0\"; + if (GET_CODE (operands[1]) == CONST_INT + && (INTVAL (operands[1]) & 0x3ff) == 0) + return \"sethi %%hi(%1),%0\"; + return \"sethi %%hi(%1),%0\;or %%lo(%1),%0,%0\"; +}") + +(define_insn "movhi" + [(set (match_operand:HI 0 "general_operand" "=r,m") + (match_operand:HI 1 "general_operand" "rmi,rJ"))] + "" + "* +{ + if (GET_CODE (operands[0]) == MEM) + { + if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) + return output_store (operands); + return \"sth %r1,%0\"; + } + if (GET_CODE (operands[1]) == MEM) + { + if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) + return output_load_fixed (operands); + return \"ldsh %1,%0\"; + } + if (REG_P (operands[1]) + || (GET_CODE (operands[1]) == CONST_INT + && SMALL_INT (operands[1]))) + return \"mov %1,%0\"; + return \"sethi %%hi(%1),%0\;or %%lo(%1),%0,%0\"; +}") + +(define_insn "movqi" + [(set (match_operand:QI 0 "general_operand" "=r,m") + (match_operand:QI 1 "general_operand" "rmi,rJ"))] + "" + "* +{ + if (GET_CODE (operands[0]) == MEM) + { + if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) + return output_store (operands); + return \"stb %r1,%0\"; + } + if (GET_CODE (operands[1]) == MEM) + { + if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) + return output_load_fixed (operands); + return \"ldsb %1,%0\"; + } + if (REG_P (operands[1]) + || (GET_CODE (operands[1]) == CONST_INT + && SMALL_INT (operands[1]))) + return \"mov %1,%0\"; + return \"sethi %%hi(%1),%0\;or %%lo(%1),%0,%0\"; +}") + +;; The definition of this insn does not really explain what it does, +;; but it should suffice +;; that anything generated as this insn will be recognized as one +;; and that it won't successfully combine with anything. +(define_expand "movstrsi" + [(parallel [(set (mem:BLK (match_operand:BLK 0 "general_operand" "")) + (mem:BLK (match_operand:BLK 1 "general_operand" ""))) + (use (match_operand:SI 2 "arith32_operand" "")) + (use (match_operand:SI 3 "immediate_operand" "")) + (clobber (match_dup 4)) + (clobber (match_dup 0)) + (clobber (match_dup 1))])] + "" + " +{ + operands[0] = copy_to_mode_reg (SImode, XEXP (operands[0], 0)); + operands[1] = copy_to_mode_reg (SImode, XEXP (operands[1], 0)); + operands[4] = gen_reg_rtx (SImode); +}") + +(define_insn "" + [(set (mem:BLK (match_operand:SI 0 "register_operand" "r")) + (mem:BLK (match_operand:SI 1 "register_operand" "r"))) + (use (match_operand:SI 2 "arith32_operand" "rn")) + (use (match_operand:SI 3 "immediate_operand" "i")) + (clobber (match_operand:SI 4 "register_operand" "=r")) + (clobber (match_operand:SI 5 "register_operand" "=0")) + (clobber (match_operand:SI 6 "register_operand" "=1"))] + "" + "* return output_block_move (operands);") + +;; Floating point move insns + +;; 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 "" + [(set (match_operand:DF 0 "general_operand" "=r,f,o") + (match_operand:DF 1 "" "mG,m,G"))] + "GET_CODE (operands[1]) == CONST_DOUBLE" + "* +{ + if (FP_REG_P (operands[0])) + return output_fp_move_double (operands); + if (operands[1] == dconst0_rtx && GET_CODE (operands[0]) == REG) + { + operands[1] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); + return \"mov %%g0,%0\;mov %%g0,%1\"; + } + if (operands[1] == dconst0_rtx && GET_CODE (operands[0]) == MEM) + { + if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) + { + if (! ((cc_prev_status.flags & CC_KNOW_HI_G1) + && XEXP (operands[0], 0) == cc_prev_status.mdep)) + { + cc_status.flags |= CC_KNOW_HI_G1; + cc_status.mdep = XEXP (operands[0], 0); + output_asm_insn (\"sethi %%hi(%m0),%%g1\", operands); + } + return \"st %%g0,[%%g1+%%lo(%%m0)]\;st %%g0,[%%g1+%%lo(%%m0)+4]\"; + } + operands[1] = adj_offsettable_operand (operands[0], 4); + return \"st %%g0,%0\;st %%g0,%1\"; + } + return output_move_double (operands); +}") + +(define_insn "movdf" + [(set (match_operand:DF 0 "general_operand" "=rm,&r,?f,?rm") + (match_operand:DF 1 "general_operand" "r,m,rfm,f"))] + "" + "* +{ + if (GET_CODE (operands[0]) == MEM + && CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) + return output_store (operands); + if (GET_CODE (operands[1]) == MEM + && CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) + return output_load_floating (operands); + + if (FP_REG_P (operands[0]) || FP_REG_P (operands[1])) + return output_fp_move_double (operands); + return output_move_double (operands); +}") + +(define_insn "movdi" + [(set (match_operand:DI 0 "general_operand" "=rm,&r,?f,?rm") + (match_operand:DI 1 "general_operand" "r,mi,rfm,f"))] + "" + "* +{ + if (GET_CODE (operands[0]) == MEM + && CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) + return output_store (operands); + if (GET_CODE (operands[1]) == MEM + && CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) + return output_load_fixed (operands); + + if (FP_REG_P (operands[0]) || FP_REG_P (operands[1])) + return output_fp_move_double (operands); + return output_move_double (operands); +}") + +(define_insn "movsf" + [(set (match_operand:SF 0 "general_operand" "=rf,m") + (match_operand:SF 1 "general_operand" "rfm,rf"))] + "" + "* +{ + if (GET_CODE (operands[0]) == MEM + && CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) + return output_store (operands); + if (GET_CODE (operands[1]) == MEM + && CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) + return output_load_floating (operands); + if (FP_REG_P (operands[0])) + { + if (FP_REG_P (operands[1])) + return \"fmovs %1,%0\"; + if (GET_CODE (operands[1]) == REG) + return \"st %r1,[%%fp-4]\;ld [%%fp-4],%0\"; + if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) + { + cc_status.flags |= CC_KNOW_HI_G1; + cc_status.mdep = XEXP (operands[1], 0); + return \"sethi %%hi(%m1),%%g1\;ld [%%g1+%%lo(%m1)],%0\"; + } + return \"ld %1,%0\"; + } + if (FP_REG_P (operands[1])) + { + if (GET_CODE (operands[0]) == REG) + return \"st %r1,[%%fp-4]\;ld [%%fp-4],%0\"; + if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) + { + if (! ((cc_prev_status.flags & CC_KNOW_HI_G1) + && XEXP (operands[0], 0) == cc_prev_status.mdep)) + { + cc_status.flags |= CC_KNOW_HI_G1; + cc_status.mdep = XEXP (operands[0], 0); + output_asm_insn (\"sethi %%hi(%m0),%%g1\", operands); + } + return \"st %r1,[%%g1+%%lo(%m0)]\"; + } + return \"st %r1,%0\"; + } + if (GET_CODE (operands[0]) == MEM) + return \"st %r1,%0\"; + if (GET_CODE (operands[1]) == MEM) + return \"ld %1,%0\"; + return \"mov %1,%0\"; +}") + +;;- truncation instructions +(define_insn "truncsiqi2" + [(set (match_operand:QI 0 "general_operand" "=g") + (truncate:QI + (match_operand:SI 1 "register_operand" "r")))] + "" + "* +{ + if (GET_CODE (operands[0]) == MEM) + if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) + { + if (! ((cc_prev_status.flags & CC_KNOW_HI_G1) + && XEXP (operands[0], 0) == cc_prev_status.mdep)) + { + cc_status.flags |= CC_KNOW_HI_G1; + cc_status.mdep = XEXP (operands[0], 0); + output_asm_insn (\"sethi %%hi(%m0),%%g1\", operands); + } + return \"stb %1,[%%g1+%%lo(%m0)]\"; + } + else + return \"stb %1,%0\"; + return \"mov %1,%0\"; +}") + +(define_insn "trunchiqi2" + [(set (match_operand:QI 0 "general_operand" "=g") + (truncate:QI + (match_operand:HI 1 "register_operand" "r")))] + "" + "* +{ + if (GET_CODE (operands[0]) == MEM) + if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) + { + if (! ((cc_prev_status.flags & CC_KNOW_HI_G1) + && XEXP (operands[0], 0) == cc_prev_status.mdep)) + { + cc_status.flags |= CC_KNOW_HI_G1; + cc_status.mdep = XEXP (operands[0], 0); + output_asm_insn (\"sethi %%hi(%m0),%%g1\", operands); + } + return \"stb %1,[%%g1+%%lo(%m0)]\"; + } + else + return \"stb %1,%0\"; + return \"mov %1,%0\"; +}") + +(define_insn "truncsihi2" + [(set (match_operand:HI 0 "general_operand" "=g") + (truncate:HI + (match_operand:SI 1 "register_operand" "r")))] + "" + "* +{ + if (GET_CODE (operands[0]) == MEM) + if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) + { + if (! ((cc_prev_status.flags & CC_KNOW_HI_G1) + && XEXP (operands[0], 0) == cc_prev_status.mdep)) + { + cc_status.flags |= CC_KNOW_HI_G1; + cc_status.mdep = XEXP (operands[0], 0); + output_asm_insn (\"sethi %%hi(%m0),%%g1\", operands); + } + return \"sth %1,[%%g1+%%lo(%m0)]\"; + } + else + return \"sth %1,%0\"; + return \"mov %1,%0\"; +}") + +;;- zero extension instructions + +;; Note that the one starting from HImode comes before those for QImode +;; so that a constant operand will match HImode, not QImode. + +(define_insn "zero_extendhisi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (zero_extend:SI + (match_operand:HI 1 "general_operand" "g")))] + "" + "* +{ + if (REG_P (operands[1])) + return \"sll %1,0x10,%0\;srl %0,0x10,%0\"; + if (GET_CODE (operands[1]) == CONST_INT) + { + operands[1] = gen_rtx (CONST_INT, VOIDmode, + INTVAL (operands[1]) & 0xffff); + output_asm_insn (\"set %1,%0\", operands); + return \"\"; + } + if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) + { + cc_status.flags |= CC_KNOW_HI_G1; + cc_status.mdep = XEXP (operands[1], 0); + return \"sethi %%hi(%m1),%%g1\;lduh [%%g1+%%lo(%m1)],%0\"; + } + else + return \"lduh %1,%0\"; +}") + +(define_insn "zero_extendqihi2" + [(set (match_operand:HI 0 "register_operand" "=r") + (zero_extend:HI + (match_operand:QI 1 "general_operand" "g")))] + "" + "* +{ + if (REG_P (operands[1])) + return \"and %1,0xff,%0\"; + if (GET_CODE (operands[1]) == CONST_INT) + { + operands[1] = gen_rtx (CONST_INT, VOIDmode, + INTVAL (operands[1]) & 0xff); + output_asm_insn (\"set %1,%0\", operands); + return \"\"; + } + if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) + { + cc_status.flags |= CC_KNOW_HI_G1; + cc_status.mdep = XEXP (operands[1], 0); + return \"sethi %%hi(%m1),%%g1\;ldub [%%g1+%%lo(%m1)],%0\"; + } + else + return \"ldub %1,%0\"; +}") + +(define_insn "zero_extendqisi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (zero_extend:SI + (match_operand:QI 1 "general_operand" "g")))] + "" + "* +{ + if (REG_P (operands[1])) + return \"and %1,0xff,%0\"; + if (GET_CODE (operands[1]) == CONST_INT) + { + operands[1] = gen_rtx (CONST_INT, VOIDmode, + INTVAL (operands[1]) & 0xff); + output_asm_insn (\"set %1,%0\", operands); + return \"\"; + } + if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) + { + cc_status.flags |= CC_KNOW_HI_G1; + cc_status.mdep = XEXP (operands[1], 0); + return \"sethi %%hi(%m1),%%g1\;ldub [%%g1+%%lo(%m1)],%0\"; + } + else + return \"ldub %1,%0\"; +}") + +;;- sign extension instructions +;; Note that the one starting from HImode comes before those for QImode +;; so that a constant operand will match HImode, not QImode. + +(define_insn "extendhisi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (sign_extend:SI + (match_operand:HI 1 "general_operand" "g")))] + "" + "* +{ + if (REG_P (operands[1])) + return \"sll %1,0x10,%0\;sra %0,0x10,%0\"; + if (GET_CODE (operands[1]) == CONST_INT) + { + int i = (short)INTVAL (operands[1]); + operands[1] = gen_rtx (CONST_INT, VOIDmode, i); + output_asm_insn (\"set %1,%0\", operands); + return \"\"; + } + if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) + { + cc_status.flags |= CC_KNOW_HI_G1; + cc_status.mdep = XEXP (operands[1], 0); + return \"sethi %%hi(%m1),%%g1\;ldsh [%%g1+%%lo(%m1)],%0\"; + } + else + return \"ldsh %1,%0\"; +}") + +(define_insn "extendqihi2" + [(set (match_operand:HI 0 "register_operand" "=r") + (sign_extend:HI + (match_operand:QI 1 "general_operand" "g")))] + "" + "* +{ + if (REG_P (operands[1])) + return \"sll %1,0x18,%0\;sra %0,0x18,%0\"; + if (GET_CODE (operands[1]) == CONST_INT) + { + int i = (char)INTVAL (operands[1]); + operands[1] = gen_rtx (CONST_INT, VOIDmode, i); + output_asm_insn (\"set %1,%0\", operands); + return \"\"; + } + if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) + { + cc_status.flags |= CC_KNOW_HI_G1; + cc_status.mdep = XEXP (operands[1], 0); + return \"sethi %%hi(%m1),%%g1\;ldsb [%%g1+%%lo(%m1)],%0\"; + } + else + return \"ldsb %1,%0\"; +}") + +(define_insn "extendqisi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (sign_extend:SI + (match_operand:QI 1 "general_operand" "g")))] + "" + "* +{ + if (REG_P (operands[1])) + return \"sll %1,0x18,%0\;sra %0,0x18,%0\"; + if (GET_CODE (operands[1]) == CONST_INT) + { + int i = (char)INTVAL (operands[1]); + operands[1] = gen_rtx (CONST_INT, VOIDmode, i); + output_asm_insn (\"set %1,%0\", operands); + return \"\"; + } + if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) + { + cc_status.flags |= CC_KNOW_HI_G1; + cc_status.mdep = XEXP (operands[1], 0); + return \"sethi %%hi(%m1),%%g1\;ldsb [%%g1+%%lo(%m1)],%0\"; + } + else + return \"ldsb %1,%0\"; +}") + +;; Signed bitfield extractions come out looking like +;; (shiftrt (shift (sign_extend ) ) ) +;; which we expand poorly as four shift insns. +;; These patters yeild two shifts: +;; (shiftrt (shift ) ) +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (ashiftrt:SI + (sign_extend:SI + (match_operand:QI 1 "register_operand" "r")) + (match_operand:SI 2 "small_int" "n")))] + "" + "sll %1,0x18,%0\;sra %0,0x18+%2,%0") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (ashiftrt:SI + (sign_extend:SI + (subreg:QI (ashift:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "small_int" "n")) 0)) + (match_operand:SI 3 "small_int" "n")))] + "" + "sll %1,0x18+%2,%0\;sra %0,0x18+%3,%0") + +;; Special patterns for optimizing bit-field instructions. + +;; First two patterns are for bitfields that came from memory +;; testing only the high bit. They work with old combiner. +;; @@ Actually, the second pattern does not work if we +;; @@ need to set the N bit. +(define_insn "" + [(set (cc0) + (zero_extend:SI (subreg:QI (lshiftrt:SI (match_operand:SI 0 "register_operand" "r") + (const_int 7)) 0)))] + "0" + "andcc %0,128,%%g0") + +(define_insn "" + [(set (cc0) + (sign_extend:SI (subreg:QI (ashiftrt:SI (match_operand:SI 0 "register_operand" "r") + (const_int 7)) 0)))] + "0" + "andcc %0,128,%%g0") + +;; next two patterns are good for bitfields coming from memory +;; (via pseudo-register) or from a register, though this optimization +;; is only good for values contained wholly within the bottom 13 bits +(define_insn "" + [(set (cc0) + (and:SI (lshiftrt:SI (match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "small_int" "n")) + (match_operand:SI 2 "small_int" "n")))] + "(unsigned)((INTVAL (operands[2]) << INTVAL (operands[1])) + 0x1000) < 0x2000" + "andcc %0,%2<<%1,%%g0") + +(define_insn "" + [(set (cc0) + (and:SI (ashiftrt:SI (match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "small_int" "n")) + (match_operand:SI 2 "small_int" "n")))] + "(unsigned)((INTVAL (operands[2]) << INTVAL (operands[1])) + 0x1000) < 0x2000" + "andcc %0,%2<<%1,%%g0") + +;; Conversions between float and double. + +(define_insn "extendsfdf2" + [(set (match_operand:DF 0 "register_operand" "=f") + (float_extend:DF + (match_operand:SF 1 "register_operand" "f")))] + "" + "fstod %1,%0") + +(define_insn "truncdfsf2" + [(set (match_operand:SF 0 "register_operand" "=f") + (float_truncate:SF + (match_operand:DF 1 "register_operand" "f")))] + "" + "fdtos %1,%0") + +;; Conversion between fixed point and floating point. +;; Note that among the fix-to-float insns +;; the ones that start with SImode come first. +;; That is so that an operand that is a CONST_INT +;; (and therefore lacks a specific machine mode). +;; will be recognized as SImode (which is always valid) +;; rather than as QImode or HImode. + +;; This pattern forces (set (reg:SF ...) (float:SF (const_int ...))) +;; to be reloaded by putting the constant into memory. +;; It must come before the more general floatsisf2 pattern. +(define_insn "" + [(set (match_operand:SF 0 "general_operand" "=f") + (float:SF (match_operand 1 "" "m")))] + "GET_CODE (operands[1]) == CONST_INT" + "* +{ + if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) + { + cc_status.flags |= CC_KNOW_HI_G1; + cc_status.mdep = XEXP (operands[1], 0); + return \"sethi %%hi(%m1),%%g1\;ld [%%g1+%%lo(%m1)],%0\;fitos %0,%0\"; + } + return \"ld %1,%0\;fitos %0,%0\"; +}") + +(define_insn "floatsisf2" + [(set (match_operand:SF 0 "general_operand" "=f") + (float:SF (match_operand:SI 1 "general_operand" "rfm")))] + "" + "* +{ + if (GET_CODE (operands[1]) == MEM) + if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) + { + cc_status.flags |= CC_KNOW_HI_G1; + cc_status.mdep = XEXP (operands[1], 0); + return \"sethi %%hi(%m1),%%g1\;ld [%%g1+%%lo(%m1)],%0\;fitos %0,%0\"; + } + else + return \"ld %1,%0\;fitos %0,%0\"; + else if (FP_REG_P (operands[1])) + return \"fitos %1,%0\"; + return \"st %r1,[%%fp-4]\;ld [%%fp-4],%0\;fitos %0,%0\"; +}") + +;; This pattern forces (set (reg:DF ...) (float:DF (const_int ...))) +;; to be reloaded by putting the constant into memory. +;; It must come before the more general floatsidf2 pattern. +(define_insn "" + [(set (match_operand:DF 0 "general_operand" "=f") + (float:DF (match_operand 1 "" "m")))] + "GET_CODE (operands[1]) == CONST_INT" + "* +{ + if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) + { + cc_status.flags |= CC_KNOW_HI_G1; + cc_status.mdep = XEXP (operands[1], 0); + return \"sethi %%hi(%m1),%%g1\;ld [%%g1+%%lo(%m1)],%0\;fitod %0,%0\"; + } + return \"ld %1,%0\;fitod %0,%0\"; +}") + +(define_insn "floatsidf2" + [(set (match_operand:DF 0 "general_operand" "=f") + (float:DF (match_operand:SI 1 "general_operand" "rfm")))] + "" + "* +{ + if (GET_CODE (operands[1]) == MEM) + if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) + { + cc_status.flags |= CC_KNOW_HI_G1; + cc_status.mdep = XEXP (operands[1], 0); + return \"sethi %%hi(%m1),%%g1\;ld [%%g1+%%lo(%m1)],%0\;fitod %0,%0\"; + } + else + return \"ld %1,%0\;fitod %0,%0\"; + else if (FP_REG_P (operands[1])) + return \"fitod %1,%0\"; + else + return \"st %r1,[%%fp-4]\;ld [%%fp-4],%0\;fitod %0,%0\"; +}") + +;; Convert a float to an actual integer. +;; Truncation is performed as part of the conversion. +(define_insn "fix_truncsfsi2" + [(set (match_operand:SI 0 "general_operand" "=rm") + (fix:SI (fix:SF (match_operand:SF 1 "general_operand" "fm"))))] + "" + "* +{ + cc_status.flags &= ~(CC_F1_IS_0); + if (FP_REG_P (operands[1])) + output_asm_insn (\"fstoi %1,%%f1\", operands); + else if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) + { + cc_status.flags |= CC_KNOW_HI_G1; + cc_status.mdep = XEXP (operands[1], 0); + output_asm_insn (\"sethi %%hi(%m1),%%g1\;ld [%%g1+%%lo(%m1)],%%f1\;fstoi %%f1,%%f1\", operands); + } + else + output_asm_insn (\"ld %1,%%f1\;fstoi %%f1,%%f1\", operands); + if (GET_CODE (operands[0]) == MEM) + if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) + { + if (! ((cc_prev_status.flags & CC_KNOW_HI_G1) + && XEXP (operands[0], 0) == cc_prev_status.mdep)) + { + cc_status.flags |= CC_KNOW_HI_G1; + cc_status.mdep = XEXP (operands[0], 0); + output_asm_insn (\"sethi %%hi(%m0),%%g1\", operands); + } + return \"st %%f1,[%%g1+%%lo(%m0)]\"; + } + else + return \"st %%f1,%0\"; + else + return \"st %%f1,[%%fp-4]\;ld [%%fp-4],%0\"; +}") + +(define_insn "fix_truncdfsi2" + [(set (match_operand:SI 0 "general_operand" "=rm") + (fix:SI (fix:DF (match_operand:DF 1 "general_operand" "fm"))))] + "" + "* +{ + cc_status.flags &= ~CC_F0_IS_0; + if (FP_REG_P (operands[1])) + output_asm_insn (\"fdtoi %1,%%f0\", operands); + else + { + rtx xoperands[2]; + xoperands[0] = gen_rtx (REG, DFmode, 32); + xoperands[1] = operands[1]; + output_asm_insn (output_fp_move_double (xoperands), xoperands); + output_asm_insn (\"fdtoi %%f0,%%f0\", 0); + } + if (GET_CODE (operands[0]) == MEM) + if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) + { + if (! ((cc_prev_status.flags & CC_KNOW_HI_G1) + && XEXP (operands[0], 0) == cc_prev_status.mdep)) + { + cc_status.flags |= CC_KNOW_HI_G1; + cc_status.mdep = XEXP (operands[0], 0); + output_asm_insn (\"sethi %%hi(%m0),%%g1\", operands); + } + return \"st %%f0,[%%g1+%%lo(%m0)]\"; + } + else + return \"st %%f0,%0\"; + else + return \"st %%f0,[%%fp-4]\;ld [%%fp-4],%0\"; +}") + +;;- arithmetic instructions + +(define_insn "addsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (plus:SI (match_operand:SI 1 "arith32_operand" "%r") + (match_operand:SI 2 "arith32_operand" "rn")))] + "" + "* +{ + if (REG_P (operands[2])) + return \"add %1,%2,%0\"; + if (SMALL_INT (operands[2])) + return \"add %1,%2,%0\"; + cc_status.flags &= ~CC_KNOW_HI_G1; + return \"sethi %%hi(%2),%%g1\;or %%lo(%2),%%g1,%%g1\;add %1,%%g1,%0\"; +}") + +(define_insn "subsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (minus:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "arith32_operand" "rn")))] + "" + "* +{ + if (REG_P (operands[2])) + return \"sub %1,%2,%0\"; + if (SMALL_INT (operands[2])) + return \"sub %1,%2,%0\"; + cc_status.flags &= ~CC_KNOW_HI_G1; + return \"sethi %%hi(%2),%%g1\;or %%lo(%2),%%g1,%%g1\;sub %1,%%g1,%0\"; +}") + +(define_expand "mulsi3" + [(set (match_operand:SI 0 "register_operand" "r") + (mult:SI (match_operand:SI 1 "general_operand" "") + (match_operand:SI 2 "general_operand" "")))] + "" + " +{ + rtx src; + + if (GET_CODE (operands[1]) == CONST_INT) + if (GET_CODE (operands[2]) == CONST_INT) + { + emit_move_insn (operands[0], + gen_rtx (CONST_INT, VOIDmode, + INTVAL (operands[1]) * INTVAL (operands[2]))); + DONE; + } + else + src = gen_rtx (MULT, SImode, + copy_to_mode_reg (SImode, operands[2]), + operands[1]); + else if (GET_CODE (operands[2]) == CONST_INT) + src = gen_rtx (MULT, SImode, + copy_to_mode_reg (SImode, operands[1]), + operands[2]); + else src = 0; + + if (src) + emit_insn (gen_rtx (SET, VOIDmode, operands[0], src)); + else + emit_insn (gen_rtx (PARALLEL, VOIDmode, gen_rtvec (5, + gen_rtx (SET, VOIDmode, operands[0], + gen_rtx (MULT, SImode, operands[1], operands[2])), + gen_rtx (CLOBBER, VOIDmode, gen_rtx (REG, SImode, 8)), + gen_rtx (CLOBBER, VOIDmode, gen_rtx (REG, SImode, 9)), + gen_rtx (CLOBBER, VOIDmode, gen_rtx (REG, SImode, 12)), + gen_rtx (CLOBBER, VOIDmode, gen_rtx (REG, SImode, 13))))); + DONE; +}") + +(define_expand "umulsi3" + [(set (match_operand:SI 0 "register_operand" "r") + (umult:SI (match_operand:SI 1 "general_operand" "") + (match_operand:SI 2 "general_operand" "")))] + "" + " +{ + rtx src; + + if (GET_CODE (operands[1]) == CONST_INT) + if (GET_CODE (operands[2]) == CONST_INT) + { + emit_move_insn (operands[0], + gen_rtx (CONST_INT, VOIDmode, + (unsigned)INTVAL (operands[1]) * (unsigned)INTVAL (operands[2]))); + DONE; + } + else + src = gen_rtx (UMULT, SImode, + copy_to_mode_reg (SImode, operands[2]), + operands[1]); + else if (GET_CODE (operands[2]) == CONST_INT) + src = gen_rtx (UMULT, SImode, + copy_to_mode_reg (SImode, operands[1]), + operands[2]); + else src = 0; + + if (src) + emit_insn (gen_rtx (SET, VOIDmode, operands[0], src)); + else + emit_insn (gen_rtx (PARALLEL, VOIDmode, gen_rtvec (5, + gen_rtx (SET, VOIDmode, operands[0], + gen_rtx (UMULT, SImode, operands[1], operands[2])), + gen_rtx (CLOBBER, VOIDmode, gen_rtx (REG, SImode, 8)), + gen_rtx (CLOBBER, VOIDmode, gen_rtx (REG, SImode, 9)), + gen_rtx (CLOBBER, VOIDmode, gen_rtx (REG, SImode, 12)), + gen_rtx (CLOBBER, VOIDmode, gen_rtx (REG, SImode, 13))))); + DONE; +}") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (mult:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "immediate_operand" "n")))] + "" + "* return output_mul_by_constant (insn, operands, 0);") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (umult:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "immediate_operand" "n")))] + "" + "* return output_mul_by_constant (insn, operands, 1);") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (mult:SI (match_operand:SI 1 "general_operand" "%r") + (match_operand:SI 2 "general_operand" "r"))) + (clobber (reg:SI 8)) + (clobber (reg:SI 9)) + (clobber (reg:SI 12)) + (clobber (reg:SI 13))] + "" + "* return output_mul_insn (operands, 0);") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (umult:SI (match_operand:SI 1 "general_operand" "%r") + (match_operand:SI 2 "general_operand" "r"))) + (clobber (reg:SI 8)) + (clobber (reg:SI 9)) + (clobber (reg:SI 12)) + (clobber (reg:SI 13))] + "" + "* return output_mul_insn (operands, 1);") + +;; this pattern is needed because cse may eliminate the multiplication, +;; but leave the clobbers behind. + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (match_operand:SI 1 "general_operand" "g")) + (clobber (reg:SI 8)) + (clobber (reg:SI 9)) + (clobber (reg:SI 12)) + (clobber (reg:SI 13))] + "" + "* +{ + if (GET_CODE (operands[1]) == CONST_INT) + { + if (SMALL_INT (operands[1])) + return \"mov %1,%0\"; + return \"sethi %%hi(%1),%0\;or %%lo(%1),%0,%0\"; + } + if (GET_CODE (operands[1]) == MEM) + return \"ld %1,%0\"; + return \"mov %1,%0\"; +}") + +;; In case constant factor turns out to be -1. +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (neg:SI (match_operand:SI 1 "general_operand" "rI"))) + (clobber (reg:SI 8)) + (clobber (reg:SI 9)) + (clobber (reg:SI 12)) + (clobber (reg:SI 13))] + "" + "sub %%g0,%1,%0") + +;;- and instructions (with compliment also) +(define_insn "andsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (and:SI (match_operand:SI 1 "arith32_operand" "%r") + (match_operand:SI 2 "arith32_operand" "rn")))] + "" + "* +{ + if (REG_P (operands[2]) || SMALL_INT (operands[2])) + return \"and %1,%2,%0\"; + cc_status.flags &= ~CC_KNOW_HI_G1; + return \"sethi %%hi(%2),%%g1\;or %%lo(%2),%%g1,%%g1\;and %1,%%g1,%0\"; +}") + +(define_insn "andcbsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (and:SI (match_operand:SI 1 "register_operand" "r") + (not:SI (match_operand:SI 2 "register_operand" "r"))))] + "" + "andn %1,%2,%0") + +(define_insn "iorsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (ior:SI (match_operand:SI 1 "arith32_operand" "%r") + (match_operand:SI 2 "arith32_operand" "rn")))] + "" + "* +{ + if (REG_P (operands[2]) || SMALL_INT (operands[2])) + return \"or %1,%2,%0\"; + cc_status.flags &= ~CC_KNOW_HI_G1; + return \"sethi %%hi(%2),%%g1\;or %%lo(%2),%%g1,%%g1\;or %1,%%g1,%0\"; +}") + +(define_insn "iorcbsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (ior:SI (match_operand:SI 1 "register_operand" "r") + (not:SI (match_operand:SI 2 "register_operand" "r"))))] + "" + "orn %1,%2,%0") + +(define_insn "xorsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (xor:SI (match_operand:SI 1 "arith32_operand" "%r") + (match_operand:SI 2 "arith32_operand" "rn")))] + "" + "* +{ + if (REG_P (operands[2]) || SMALL_INT (operands[2])) + return \"xor %1,%2,%0\"; + cc_status.flags &= ~CC_KNOW_HI_G1; + return \"sethi %%hi(%2),%%g1\;or %%lo(%2),%%g1,%%g1\;xor %1,%%g1,%0\"; +}") + +(define_insn "xorcbsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (xor:SI (match_operand:SI 1 "register_operand" "r") + (not:SI (match_operand:SI 2 "register_operand" "r"))))] + "" + "xnor %1,%2,%0") + +;; We cannot use the "neg" pseudo insn because the Sun assembler +;; does not know how to make it work for constants. +(define_insn "negsi2" + [(set (match_operand:SI 0 "general_operand" "=r") + (neg:SI (match_operand:SI 1 "arith_operand" "rI")))] + "" + "sub %%g0,%1,%0") + +;; We cannot use the "not" pseudo insn because the Sun assembler +;; does not know how to make it work for constants. +(define_insn "one_cmplsi2" + [(set (match_operand:SI 0 "general_operand" "=r") + (not:SI (match_operand:SI 1 "arith_operand" "rI")))] + "" + "xnor %%g0,%1,%0") + +;; Floating point arithmetic instructions. + +(define_insn "adddf3" + [(set (match_operand:DF 0 "register_operand" "=f") + (plus:DF (match_operand:DF 1 "register_operand" "f") + (match_operand:DF 2 "register_operand" "f")))] + "" + "faddd %1,%2,%0") + +(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")))] + "" + "fadds %1,%2,%0") + +(define_insn "subdf3" + [(set (match_operand:DF 0 "register_operand" "=f") + (minus:DF (match_operand:DF 1 "register_operand" "f") + (match_operand:DF 2 "register_operand" "f")))] + "" + "fsubd %1,%2,%0") + +(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")))] + "" + "fsubs %1,%2,%0") + +(define_insn "muldf3" + [(set (match_operand:DF 0 "register_operand" "=f") + (mult:DF (match_operand:DF 1 "register_operand" "f") + (match_operand:DF 2 "register_operand" "f")))] + "" + "fmuld %1,%2,%0") + +(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")))] + "" + "fmuls %1,%2,%0") + +(define_insn "divdf3" + [(set (match_operand:DF 0 "register_operand" "=f") + (div:DF (match_operand:DF 1 "register_operand" "f") + (match_operand:DF 2 "register_operand" "f")))] + "" + "fdivd %1,%2,%0") + +(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")))] + "" + "fdivs %1,%2,%0") + +(define_insn "negdf2" + [(set (match_operand:DF 0 "register_operand" "=f") + (neg:DF (match_operand:DF 1 "register_operand" "f")))] + "" + "* +{ + output_asm_insn (\"fnegs %1,%0\", operands); + if (REGNO (operands[0]) != REGNO (operands[1])) + { + operands[0] = gen_rtx (REG, VOIDmode, REGNO (operands[0]) + 1); + operands[1] = gen_rtx (REG, VOIDmode, REGNO (operands[1]) + 1); + output_asm_insn (\"fmovs %1,%0\", operands); + } + return \"\"; +}") + +(define_insn "negsf2" + [(set (match_operand:SF 0 "register_operand" "=f") + (neg:SF (match_operand:SF 1 "register_operand" "f")))] + "" + "fnegs %1,%0") + +(define_insn "absdf2" + [(set (match_operand:DF 0 "register_operand" "=f") + (abs:DF (match_operand:DF 1 "register_operand" "f")))] + "" + "* +{ + output_asm_insn (\"fabss %1,%0\", operands); + if (REGNO (operands[0]) != REGNO (operands[1])) + { + operands[0] = gen_rtx (REG, VOIDmode, REGNO (operands[0]) + 1); + operands[1] = gen_rtx (REG, VOIDmode, REGNO (operands[1]) + 1); + output_asm_insn (\"fmovs %1,%0\", operands); + } + return \"\"; +}") + +(define_insn "abssf2" + [(set (match_operand:SF 0 "register_operand" "=f") + (abs:SF (match_operand:SF 1 "register_operand" "f")))] + "" + "fabss %1,%0") + +;; Shift instructions + +;; Optimized special case of shifting. +;; Must precede the general case. + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (ashiftrt:SI (match_operand:SI 1 "memory_operand" "m") + (const_int 24)))] + "" + "* +{ + if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) + { + cc_status.flags |= CC_KNOW_HI_G1; + cc_status.mdep = XEXP (operands[1], 0); + return \"sethi %%hi(%m1),%%g1\;ldsb [%%g1+%%lo(%m1)],%0\"; + } + return \"ldsb %1,%0\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (lshiftrt:SI (match_operand:SI 1 "memory_operand" "m") + (const_int 24)))] + "" + "* +{ + if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) + { + cc_status.flags |= CC_KNOW_HI_G1; + cc_status.mdep = XEXP (operands[1], 0); + return \"sethi %%hi(%m1),%%g1\;ldub [%%g1+%%lo(%m1)],%0\"; + } + return \"ldub %1,%0\"; +}") + +;;- 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 "arith32_operand" "rn")))] + "" + "* +{ + if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) >= 32) + operands[2] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[2]) & 31); + return \"sll %1,%2,%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 "arith32_operand" "rn")))] + "" + "* +{ + if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) >= 32) + operands[2] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[2]) & 31); + return \"sra %1,%2,%0\"; +}") + +(define_insn "lshrsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (lshiftrt:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "arith32_operand" "rn")))] + "" + "* +{ + if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) >= 32) + operands[2] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[2]) & 31); + return \"srl %1,%2,%0\"; +}") + +;; Unconditional and other jump instructions +;; Note that for the Sparc, by setting the annul bit on an unconditional +;; branch, the following insn is never executed. This saves us a nop, +;; but requires a debugger which can handle annuled branches. +(define_insn "jump" + [(set (pc) (label_ref (match_operand 0 "" "")))] + "" + "* +{ + extern int optimize; + extern int flag_no_peephole; + + if (optimize && !flag_no_peephole) + return \"b,a %l0\"; + return \"b %l0\;nop\"; +}") + +;; Peephole optimizers recognize a few simple cases when delay insns are safe. +;; Complex ones are up front. Simple ones after. + +;; This pattern is just like the following one, but matches when there +;; is a jump insn after the "delay" insn. Without this pattern, we +;; de-optimize that case. + +(define_peephole + [(set (pc) (match_operand 0 "" "")) + (set (match_operand:SI 1 "" "") + (match_operand:SI 2 "" "")) + (set (pc) (label_ref (match_operand 3 "" "")))] + "TARGET_EAGER && operands_satisfy_eager_branch_peephole (operands, 2)" + "* +{ + rtx xoperands[2]; + rtx pat = gen_rtx (SET, VOIDmode, operands[1], operands[2]); + rtx delay_insn = gen_rtx (INSN, VOIDmode, 0, 0, 0, pat, -1, 0, 0); + rtx label, head; + int parity; + + if (GET_CODE (XEXP (operands[0], 1)) == PC) + { + parity = 1; + label = XEXP (XEXP (operands[0], 2), 0); + } + else + { + parity = 0; + label = XEXP (XEXP (operands[0], 1), 0); + } + xoperands[0] = XEXP (operands[0], 0); + xoperands[1] = label; + + head = next_real_insn_no_labels (label); + + /* If at the target of this label we set the condition codes, + and the condition codes are already set for that value, + advance, if we can, to the following insn. */ + if (GET_CODE (PATTERN (head)) == SET + && GET_CODE (SET_DEST (PATTERN (head))) == CC0 + && cc_status.value2 == SET_SRC (PATTERN (head))) + { + rtx nhead = next_real_insn_no_labels (head); + if (nhead + && GET_CODE (nhead) == INSN + && GET_CODE (PATTERN (nhead)) == SET + && strict_single_insn_op_p (SET_SRC (PATTERN (nhead)), + GET_MODE (SET_DEST (PATTERN (nhead)))) + && strict_single_insn_op_p (SET_DEST (PATTERN (nhead)), VOIDmode) + /* Moves between FP regs and CPU regs are two insns. */ + && !(GET_CODE (SET_SRC (PATTERN (nhead))) == REG + && GET_CODE (SET_DEST (PATTERN (nhead))) == REG + && (FP_REG_P (SET_SRC (PATTERN (nhead))) + != FP_REG_P (SET_DEST (PATTERN (nhead)))))) + { + head = nhead; + } + } + + /* Output the branch instruction first. */ + if (cc_prev_status.flags & CC_IN_FCCR) + { + if (parity) + output_asm_insn (\"fb%F0,a %l1 ! eager\", xoperands); + else + output_asm_insn (\"fb%C0,a %l1 ! eager\", xoperands); + } + else if (cc_prev_status.flags & CC_NO_OVERFLOW) + { + if (parity) + output_asm_insn (\"b%U0,a %l1 ! eager\", xoperands); + else + output_asm_insn (\"b%I0,a %l1 ! eager\", xoperands); + } + else + { + if (parity) + output_asm_insn (\"b%N0,a %l1 ! eager\", xoperands); + else + output_asm_insn (\"b%C0,a %l1 ! eager\", xoperands); + } + + /* Now steal the first insn of the target. */ + output_eager_then_insn (head, operands); + + XVECEXP (PATTERN (insn), 0, 0) = XVECEXP (PATTERN (insn), 0, 1); + XVECEXP (PATTERN (insn), 0, 1) = XVECEXP (PATTERN (insn), 0, 2); + + return output_delayed_branch (\"b %l3 ! eager2\", operands, insn); +}") + +;; Here is a peephole which recognizes where delay insns can be made safe: +;; (1) following a conditional branch, if the target of the conditional branch +;; has only one user (this insn), move the first insn into our delay slot +;; and emit an annulled branch. +;; (2) following a conditional branch, if we can execute the fall-through +;; insn without risking any evil effects, then do that instead of a nop. + +(define_peephole + [(set (pc) (match_operand 0 "" "")) + (set (match_operand:SI 1 "" "") + (match_operand:SI 2 "" ""))] + "TARGET_EAGER && operands_satisfy_eager_branch_peephole (operands, 1)" + "* +{ + rtx xoperands[2]; + rtx pat = gen_rtx (SET, VOIDmode, operands[1], operands[2]); + rtx delay_insn = gen_rtx (INSN, VOIDmode, 0, 0, 0, pat, -1, 0, 0); + rtx label, head, prev = (rtx)1; + int parity; + + if (GET_CODE (XEXP (operands[0], 1)) == PC) + { + parity = 1; + label = XEXP (XEXP (operands[0], 2), 0); + } + else + { + parity = 0; + label = XEXP (XEXP (operands[0], 1), 0); + } + xoperands[0] = XEXP (operands[0], 0); + xoperands[1] = label; + + if (LABEL_NUSES (label) == 1) + { + prev = PREV_INSN (label); + while (prev + && (GET_CODE (prev) == NOTE + || (GET_CODE (prev) == INSN + && (GET_CODE (PATTERN (prev)) == CLOBBER + || GET_CODE (PATTERN (prev)) == USE)))) + prev = PREV_INSN (prev); + if (prev == 0 + || GET_CODE (prev) == BARRIER) + { + prev = 0; + head = next_real_insn_no_labels (label); + } + } + if (prev == 0 + && head != 0 + && ! INSN_DELETED_P (head) + && GET_CODE (head) == INSN + && GET_CODE (PATTERN (head)) == SET + && strict_single_insn_op_p (SET_SRC (PATTERN (head)), + GET_MODE (SET_DEST (PATTERN (head)))) + && strict_single_insn_op_p (SET_DEST (PATTERN (head)), VOIDmode) + /* Moves between FP regs and CPU regs are two insns. */ + && !(GET_CODE (SET_SRC (PATTERN (head))) == REG + && GET_CODE (SET_DEST (PATTERN (head))) == REG + && (FP_REG_P (SET_SRC (PATTERN (head))) + != FP_REG_P (SET_DEST (PATTERN (head)))))) + { + /* If at the target of this label we set the condition codes, + and the condition codes are already set for that value, + advance, if we can, to the following insn. */ + if (GET_CODE (PATTERN (head)) == SET + && GET_CODE (SET_DEST (PATTERN (head))) == CC0 + && cc_status.value2 == SET_SRC (PATTERN (head))) + { + rtx nhead = next_real_insn_no_labels (head); + if (nhead + && GET_CODE (nhead) == INSN + && GET_CODE (PATTERN (nhead)) == SET + && strict_single_insn_op_p (SET_SRC (PATTERN (nhead)), + GET_MODE (SET_DEST (nhead))) + && strict_single_insn_op_p (SET_DEST (PATTERN (nhead)), VOIDmode) + /* Moves between FP regs and CPU regs are two insns. */ + && !(GET_CODE (SET_SRC (PATTERN (nhead))) == REG + && GET_CODE (SET_DEST (PATTERN (nhead))) == REG + && (FP_REG_P (SET_SRC (PATTERN (nhead))) + != FP_REG_P (SET_DEST (PATTERN (nhead)))))) + head = nhead; + } + + /* Output the branch instruction first. */ + if (cc_prev_status.flags & CC_IN_FCCR) + { + if (parity) + output_asm_insn (\"fb%F0,a %l1 ! eager\", xoperands); + else + output_asm_insn (\"fb%C0,a %l1 ! eager\", xoperands); + } + else if (cc_prev_status.flags & CC_NO_OVERFLOW) + { + if (parity) + output_asm_insn (\"b%U0,a %l1 ! eager\", xoperands); + else + output_asm_insn (\"b%I0,a %l1 ! eager\", xoperands); + } + else + { + if (parity) + output_asm_insn (\"b%N0,a %l1 ! eager\", xoperands); + else + output_asm_insn (\"b%C0,a %l1 ! eager\", xoperands); + } + + /* Now steal the first insn of the target. */ + output_eager_then_insn (head, operands); + } + else + { + /* Output the branch instruction first. */ + if (cc_prev_status.flags & CC_IN_FCCR) + { + if (parity) + output_asm_insn (\"fb%F0 %l1 ! eager\", xoperands); + else + output_asm_insn (\"fb%C0 %l1 ! eager\", xoperands); + } + else if (cc_prev_status.flags & CC_NO_OVERFLOW) + { + if (parity) + output_asm_insn (\"b%U0,a %l1 ! eager\", xoperands); + else + output_asm_insn (\"b%I0,a %l1 ! eager\", xoperands); + } + else + { + if (parity) + output_asm_insn (\"b%N0 %l1 ! eager\", xoperands); + else + output_asm_insn (\"b%C0 %l1 ! eager\", xoperands); + } + } + return output_delay_insn (delay_insn); +}") + +;; Here are two simple peepholes which fill the delay slot of +;; an unconditional branch. + +(define_peephole + [(set (match_operand:SI 0 "register_operand" "=r") + (match_operand:SI 1 "single_insn_src_p" "p")) + (set (pc) (label_ref (match_operand 2 "" "")))] + "single_insn_extra_test (operands[0], operands[1])" + "* return output_delayed_branch (\"b %l2\", operands, insn);") + +(define_peephole + [(set (match_operand:SI 0 "memory_operand" "=m") + (match_operand:SI 1 "reg_or_0_operand" "rJ")) + (set (pc) (label_ref (match_operand 2 "" "")))] + "" + "* return output_delayed_branch (\"b %l2\", operands, insn);") + +(define_insn "tablejump" + [(set (pc) (match_operand:SI 0 "register_operand" "r")) + (use (label_ref (match_operand 1 "" "")))] + "" + "jmp %0\;nop") + +(define_peephole + [(set (match_operand:SI 0 "register_operand" "=r") + (match_operand:SI 1 "single_insn_src_p" "p")) + (parallel [(set (pc) (match_operand:SI 2 "register_operand" "r")) + (use (label_ref (match_operand 3 "" "")))])] + "REGNO (operands[0]) != REGNO (operands[2]) + && single_insn_extra_test (operands[0], operands[1])" + "* return output_delayed_branch (\"jmp %2\", operands, insn);") + +(define_peephole + [(set (match_operand:SI 0 "memory_operand" "=m") + (match_operand:SI 1 "reg_or_0_operand" "rJ")) + (parallel [(set (pc) (match_operand:SI 2 "register_operand" "r")) + (use (label_ref (match_operand 3 "" "")))])] + "" + "* return output_delayed_branch (\"jmp %2\", operands, insn);") + +;;- jump to subroutine +(define_expand "call" + [(call (match_operand:SI 0 "memory_operand" "m") + (match_operand 1 "" "i"))] + ;; operand[2] is next_arg_register + "" + " +{ + rtx fn_rtx, nregs_rtx; + + if (TARGET_SUN_ASM && GET_CODE (XEXP (operands[0], 0)) == REG) + { + rtx g1_rtx = gen_rtx (REG, SImode, 1); + emit_move_insn (g1_rtx, XEXP (operands[0], 0)); + fn_rtx = gen_rtx (MEM, SImode, g1_rtx); + } + else + 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_rtx (CONST_INT, VOIDmode, REGNO (operands[2]) - 8); + else + nregs_rtx = gen_rtx (CONST_INT, VOIDmode, 6); +#else + nregs_rtx = const0_rtx; +#endif + + emit_call_insn (gen_rtx (PARALLEL, VOIDmode, gen_rtvec (2, + gen_rtx (CALL, VOIDmode, fn_rtx, nregs_rtx), + gen_rtx (USE, VOIDmode, gen_rtx (REG, SImode, 31))))); + DONE; +}") + +(define_insn "" + [(call (match_operand:SI 0 "memory_operand" "m") + (match_operand 1 "" "i")) + (use (reg:SI 31))] + ;;- Don't use operand 1 for most machines. + "CONSTANT_P (XEXP (operands[0], 0)) + || GET_CODE (XEXP (operands[0], 0)) == REG" + "* +{ + /* strip the MEM. */ + operands[0] = XEXP (operands[0], 0); + CC_STATUS_INIT; + if (TARGET_SUN_ASM && GET_CODE (operands[0]) == REG) + return \"jmpl %a0,%%o7\;nop\"; + return \"call %a0,%1\;nop\"; +}") + +(define_peephole + [(set (match_operand:SI 0 "register_operand" "=r") + (match_operand:SI 1 "single_insn_src_p" "p")) + (parallel [(call (match_operand:SI 2 "memory_operand" "m") + (match_operand 3 "" "i")) + (use (reg:SI 31))])] + ;;- Don't use operand 1 for most machines. + "! reg_mentioned_p (operands[0], operands[2]) + && single_insn_extra_test (operands[0], operands[1])" + "* +{ + /* strip the MEM. */ + operands[2] = XEXP (operands[2], 0); + if (TARGET_SUN_ASM && GET_CODE (operands[2]) == REG) + return output_delayed_branch (\"jmpl %a2,%%o7\", operands, insn); + return output_delayed_branch (\"call %a2,%3\", operands, insn); +}") + +(define_peephole + [(set (match_operand:SI 0 "memory_operand" "=m") + (match_operand:SI 1 "reg_or_0_operand" "rJ")) + (parallel [(call (match_operand:SI 2 "memory_operand" "m") + (match_operand 3 "" "i")) + (use (reg:SI 31))])] + ;;- Don't use operand 1 for most machines. + "" + "* +{ + /* strip the MEM. */ + operands[2] = XEXP (operands[2], 0); + if (TARGET_SUN_ASM && GET_CODE (operands[2]) == REG) + return output_delayed_branch (\"jmpl %a2,%%o7\", operands, insn); + return output_delayed_branch (\"call %a2,%3\", operands, insn); +}") + +(define_expand "call_value" + [(set (match_operand 0 "register_operand" "=rf") + (call (match_operand:SI 1 "memory_operand" "m") + (match_operand 2 "" "i")))] + ;; operand 3 is next_arg_register + "" + " +{ + rtx fn_rtx, nregs_rtx; + rtvec vec; + + if (TARGET_SUN_ASM && GET_CODE (XEXP (operands[1], 0)) == REG) + { + rtx g1_rtx = gen_rtx (REG, SImode, 1); + emit_move_insn (g1_rtx, XEXP (operands[1], 0)); + fn_rtx = gen_rtx (MEM, SImode, g1_rtx); + } + else + fn_rtx = operands[1]; + +#if 0 + if (operands[3]) + nregs_rtx = gen_rtx (CONST_INT, VOIDmode, REGNO (operands[3]) - 8); + else + nregs_rtx = gen_rtx (CONST_INT, VOIDmode, 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 (USE, VOIDmode, gen_rtx (REG, SImode, 31))); + + emit_call_insn (gen_rtx (PARALLEL, VOIDmode, vec)); + DONE; +}") + +(define_insn "" + [(set (match_operand 0 "" "=rf") + (call (match_operand:SI 1 "memory_operand" "m") + (match_operand 2 "" "i"))) + (use (reg:SI 31))] + ;;- Don't use operand 2 for most machines. + "CONSTANT_P (XEXP (operands[1], 0)) + || GET_CODE (XEXP (operands[1], 0)) == REG" + "* +{ + /* strip the MEM. */ + operands[1] = XEXP (operands[1], 0); + CC_STATUS_INIT; + if (TARGET_SUN_ASM && GET_CODE (operands[1]) == REG) + return \"jmpl %a1,%%o7\;nop\"; + return \"call %a1,%2\;nop\"; +}") + +(define_peephole + [(set (match_operand:SI 0 "register_operand" "=r") + (match_operand:SI 1 "single_insn_src_p" "p")) + (parallel [(set (match_operand 2 "" "=rf") + (call (match_operand:SI 3 "memory_operand" "m") + (match_operand 4 "" "i"))) + (use (reg:SI 31))])] + ;;- Don't use operand 4 for most machines. + "! reg_mentioned_p (operands[0], operands[3]) + && single_insn_extra_test (operands[0], operands[1])" + "* +{ + /* strip the MEM. */ + operands[3] = XEXP (operands[3], 0); + if (TARGET_SUN_ASM && GET_CODE (operands[3]) == REG) + return output_delayed_branch (\"jmpl %a3,%%o7\", operands, insn); + return output_delayed_branch (\"call %a3,%4\", operands, insn); +}") + +(define_peephole + [(set (match_operand:SI 0 "memory_operand" "=m") + (match_operand:SI 1 "reg_or_0_operand" "rJ")) + (parallel [(set (match_operand 2 "" "=rf") + (call (match_operand:SI 3 "memory_operand" "m") + (match_operand 4 "" "i"))) + (use (reg:SI 31))])] + ;;- Don't use operand 4 for most machines. + "" + "* +{ + /* strip the MEM. */ + operands[3] = XEXP (operands[3], 0); + if (TARGET_SUN_ASM && GET_CODE (operands[3]) == REG) + return output_delayed_branch (\"jmpl %a3,%%o7\", operands, insn); + return output_delayed_branch (\"call %a3,%4\", operands, insn); +}") + +(define_insn "return" + [(return)] + "! TARGET_EPILOGUE" + "ret\;restore") + +(define_peephole + [(set (reg:SI 24) + (match_operand:SI 0 "reg_or_0_operand" "rJ")) + (return)] + "! TARGET_EPILOGUE" + "ret\;restore %r0,0x0,%%o0") + +(define_peephole + [(set (reg:SI 24) + (plus:SI (match_operand:SI 0 "register_operand" "r%") + (match_operand:SI 1 "arith_operand" "rI"))) + (return)] + "! TARGET_EPILOGUE" + "ret\;restore %r0,%1,%%o0") + +(define_peephole + [(set (reg:SI 24) + (minus:SI (match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "small_int" "I"))) + (return)] + "! TARGET_EPILOGUE" + "ret\;restore %0,-(%1),%%o0") + +(define_insn "nop" + [(const_int 0)] + "" + "nop") + +;;- Local variables: +;;- mode:emacs-lisp +;;- comment-start: ";;- " +;;- eval: (set-syntax-table (copy-sequence (syntax-table))) +;;- eval: (modify-syntax-entry ?[ "(]") +;;- eval: (modify-syntax-entry ?] ")[") +;;- eval: (modify-syntax-entry ?{ "(}") +;;- eval: (modify-syntax-entry ?} "){") +;;- End: + diff --git a/gcc-1.40/config/spur.md b/gcc-1.40/config/spur.md new file mode 100644 index 0000000..62070be --- /dev/null +++ b/gcc-1.40/config/spur.md @@ -0,0 +1,1119 @@ +;;- Machine description for SPUR chip for GNU C compiler +;; Copyright (C) 1988 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 1, 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. + + +;;- See file "rtl.def" for documentation on define_insn, match_*, et. al. + +;;- cpp macro #define NOTICE_UPDATE_CC in file tm.h handles condition code +;;- updates for most instructions. + +;;- Operand classes for the register allocator: + +;; Compare instructions. +;; This pattern is used for generating an "insn" +;; which does just a compare and sets a (fictitious) condition code. + +;; The actual SPUR insns are compare-and-conditional-jump. +;; The define_peephole's below recognize the combinations of +;; compares and jumps, and output each pair as a single assembler insn. + +;; Put cmpsi first among compare insns so it matches two CONST_INT operands. + +;; This controls RTL generation and register allocation. +(define_insn "cmpsi" + [(set (cc0) + (compare (match_operand:SI 0 "nonmemory_operand" "rK") + (match_operand:SI 1 "nonmemory_operand" "rK")))] + "" + "* +{ + cc_status.value1 = operands[0], cc_status.value2 = operands[1]; + return \"\"; +}") + +;; Put tstsi first among test insns so it matches a CONST_INT operand. + +;; We have to have this because cse can optimize the previous pattern +;; into this one. + +(define_insn "tstsi" + [(set (cc0) + (match_operand:SI 0 "register_operand" "r"))] + "" + "* +{ + cc_status.value1 = operands[0], cc_status.value2 = const0_rtx; + return \"\"; +}") + + +;; These control RTL generation for conditional jump insns +;; and match them for register allocation. + +(define_insn "beq" + [(set (pc) + (if_then_else (eq (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* return output_compare (operands, \"eq\", \"eq\", \"ne\", \"ne\"); ") + +(define_insn "bne" + [(set (pc) + (if_then_else (ne (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* return output_compare (operands, \"ne\", \"ne\", \"eq\", \"eq\"); ") + +(define_insn "bgt" + [(set (pc) + (if_then_else (gt (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* return output_compare (operands, \"gt\", \"lt\", \"le\", \"ge\"); ") + +(define_insn "bgtu" + [(set (pc) + (if_then_else (gtu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* return output_compare (operands, \"ugt\", \"ult\", \"ule\", \"uge\"); ") + +(define_insn "blt" + [(set (pc) + (if_then_else (lt (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* return output_compare (operands, \"lt\", \"gt\", \"ge\", \"le\"); ") + +(define_insn "bltu" + [(set (pc) + (if_then_else (ltu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* return output_compare (operands, \"ult\", \"ugt\", \"uge\", \"ule\"); ") + +(define_insn "bge" + [(set (pc) + (if_then_else (ge (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* return output_compare (operands, \"ge\", \"le\", \"lt\", \"gt\"); ") + +(define_insn "bgeu" + [(set (pc) + (if_then_else (geu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* return output_compare (operands, \"uge\", \"ule\", \"ult\", \"ugt\"); ") + +(define_insn "ble" + [(set (pc) + (if_then_else (le (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* return output_compare (operands, \"le\", \"ge\", \"gt\", \"lt\"); ") + +(define_insn "bleu" + [(set (pc) + (if_then_else (leu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* return output_compare (operands, \"ule\", \"uge\", \"ugt\", \"ult\"); ") + +;; These match inverted jump insns for register allocation. + +(define_insn "" + [(set (pc) + (if_then_else (eq (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* return output_compare (operands, \"ne\", \"ne\", \"eq\", \"eq\"); ") + +(define_insn "" + [(set (pc) + (if_then_else (ne (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* return output_compare (operands, \"eq\", \"eq\", \"ne\", \"ne\"); ") + +(define_insn "" + [(set (pc) + (if_then_else (gt (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* return output_compare (operands, \"le\", \"ge\", \"gt\", \"lt\"); ") + +(define_insn "" + [(set (pc) + (if_then_else (gtu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* return output_compare (operands, \"ule\", \"uge\", \"ugt\", \"ult\"); ") + +(define_insn "" + [(set (pc) + (if_then_else (lt (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* return output_compare (operands, \"ge\", \"le\", \"lt\", \"gt\"); ") + +(define_insn "" + [(set (pc) + (if_then_else (ltu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* return output_compare (operands, \"uge\", \"ule\", \"ult\", \"ugt\"); ") + +(define_insn "" + [(set (pc) + (if_then_else (ge (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* return output_compare (operands, \"lt\", \"gt\", \"ge\", \"le\"); ") + +(define_insn "" + [(set (pc) + (if_then_else (geu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* return output_compare (operands, \"ult\", \"ugt\", \"uge\", \"ule\"); ") + +(define_insn "" + [(set (pc) + (if_then_else (le (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* return output_compare (operands, \"gt\", \"lt\", \"le\", \"ge\"); ") + +(define_insn "" + [(set (pc) + (if_then_else (leu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* return output_compare (operands, \"ugt\", \"ult\", \"ule\", \"uge\"); ") + +;; Move instructions + +(define_insn "movsi" + [(set (match_operand:SI 0 "general_operand" "=r,m") + (match_operand:SI 1 "general_operand" "rmi,rJ"))] + "" + "* +{ + if (GET_CODE (operands[0]) == MEM) + return \"st_32 %r1,%0\"; + if (GET_CODE (operands[1]) == MEM) + return \"ld_32 %0,%1\;nop\"; + if (GET_CODE (operands[1]) == REG) + return \"add_nt %0,%1,$0\"; + if (GET_CODE (operands[1]) == SYMBOL_REF && operands[1]->unchanging) + return \"add_nt %0,r24,$(%1-0b)\"; + return \"add_nt %0,r0,%1\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (mem:SI (plus:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "register_operand" "r"))))] + "" + "ld_32 %0,%1,%2\;nop") + +;; Generate insns for moving single bytes. + +(define_expand "movqi" + [(set (match_operand:QI 0 "general_operand" "") + (match_operand:QI 1 "general_operand" ""))] + "" + " +{ + if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM) + operands[1] = copy_to_reg (operands[1]); + + if (GET_CODE (operands[1]) == MEM) + { + rtx tem = gen_reg_rtx (SImode); + rtx addr = force_reg (SImode, XEXP (operands[1], 0)); + rtx subreg; + + emit_move_insn (tem, gen_rtx (MEM, SImode, addr)); + if (GET_CODE (operands[0]) == SUBREG) + subreg = gen_rtx (SUBREG, SImode, SUBREG_REG (operands[0]), + SUBREG_WORD (operands[0])); + else + subreg = gen_rtx (SUBREG, SImode, operands[0], 0); + + emit_insn (gen_rtx (SET, VOIDmode, subreg, + gen_rtx (ZERO_EXTRACT, SImode, tem, + gen_rtx (CONST_INT, VOIDmode, 8), + addr))); + } + else if (GET_CODE (operands[0]) == MEM) + { + rtx tem = gen_reg_rtx (SImode); + rtx addr = force_reg (SImode, XEXP (operands[0], 0)); + rtx subreg; + + emit_move_insn (tem, gen_rtx (MEM, SImode, addr)); + if (! CONSTANT_ADDRESS_P (operands[1])) + { + if (GET_CODE (operands[1]) == SUBREG) + subreg = gen_rtx (SUBREG, SImode, SUBREG_REG (operands[1]), + SUBREG_WORD (operands[1])); + else + subreg = gen_rtx (SUBREG, SImode, operands[1], 0); + } + + emit_insn (gen_rtx (SET, VOIDmode, + gen_rtx (ZERO_EXTRACT, SImode, tem, + gen_rtx (CONST_INT, VOIDmode, 8), + addr), + subreg)); + emit_move_insn (gen_rtx (MEM, SImode, addr), tem); + } + else + { + emit_insn (gen_rtx (SET, VOIDmode, operands[0], operands[1])); + } + DONE; +}") + +;; Recognize insns generated for moving single bytes. + +(define_insn "" + [(set (match_operand:QI 0 "general_operand" "=r,m") + (match_operand:QI 1 "general_operand" "rmi,r"))] + "" + "* +{ + if (GET_CODE (operands[0]) == MEM) + return \"st_32 %1,%0\"; + if (GET_CODE (operands[1]) == MEM) + return \"ld_32 %0,%1\;nop\"; + if (GET_CODE (operands[1]) == REG) + return \"add_nt %0,%1,$0\"; + return \"add_nt %0,r0,%1\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (zero_extract:SI (match_operand:SI 1 "register_operand" "r") + (const_int 8) + (match_operand:SI 2 "nonmemory_operand" "rI")))] + "" + "extract %0,%1,%2") + +(define_insn "" + [(set (zero_extract:SI (match_operand:SI 0 "register_operand" "+r") + (const_int 8) + (match_operand:SI 1 "nonmemory_operand" "rI")) + (match_operand:SI 2 "nonmemory_operand" "ri"))] + "" + "wr_insert %1\;insert %0,%0,%2") + +;; Constant propagation can optimize the previous pattern into this pattern. +;[Not any more. It could when the position-operand contains a MULT.] + +;(define_insn "" +; [(set (zero_extract:QI (match_operand:SI 0 "register_operand" "+r") +; (const_int 8) +; (match_operand:SI 1 "immediate_operand" "I")) +; (match_operand:QI 2 "register_operand" "r"))] +; "GET_CODE (operands[1]) == CONST_INT +; && INTVAL (operands[1]) % 8 == 0 +; && (unsigned) INTVAL (operands[1]) < 32" +; "* +;{ +; operands[1] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[1]) / 8); +; return \"wr_insert 0,0,%1\;insert %0,%0,%2\"; +;}") + +;; The three define_expand patterns on this page +;; serve as subroutines of "movhi". + +;; Generate code to fetch an aligned halfword from memory. +;; Operand 0 is the destination register (HImode). +;; Operand 1 is the memory address (SImode). +;; Operand 2 is a temporary (SImode). +;; Operand 3 is a temporary (SImode). +;; Operand 4 is a temporary (QImode). + +;; Operand 5 is an internal temporary (HImode). + +(define_expand "loadhi" + [(set (match_operand:SI 2 "register_operand" "") + (mem:SI (match_operand:SI 1 "register_operand" ""))) + ;; Extract the low byte. + (set (subreg:SI (match_dup 5) 0) + (zero_extract:SI (match_dup 2) (const_int 8) (match_dup 1))) + ;; Form address of high byte. + (set (match_operand:SI 3 "register_operand" "") + (plus:SI (match_dup 1) (const_int 1))) + ;; Extract the high byte. + (set (subreg:SI (match_operand:QI 4 "register_operand" "") 0) + (zero_extract:SI (match_dup 2) (const_int 8) (match_dup 3))) + ;; Put the high byte in with the low one. + (set (zero_extract:SI (match_dup 5) (const_int 8) (const_int 1)) + (subreg:SI (match_dup 4) 0)) + (set (match_operand:HI 0 "register_operand" "") (match_dup 5))] + "" + "operands[5] = gen_reg_rtx (HImode);") + +;; Generate code to store an aligned halfword into memory. +;; Operand 0 is the destination address (SImode). +;; Operand 1 is the source register (HImode, not constant). +;; Operand 2 is a temporary (SImode). +;; Operand 3 is a temporary (SImode). +;; Operand 4 is a temporary (QImode). + +;; Operand 5 is an internal variable made from operand 1. + +(define_expand "storehi" + [(set (match_operand:SI 2 "register_operand" "") + (mem:SI (match_operand:SI 0 "register_operand" ""))) + ;; Insert the low byte. + (set (zero_extract:SI (match_dup 2) (const_int 8) (match_dup 0)) + (match_dup 5)) + ;; Form address of high byte. + (set (match_operand:SI 3 "register_operand" "") + (plus:SI (match_dup 0) (const_int 1))) + ;; Extract the high byte from the source. + (set (subreg:SI (match_operand:QI 4 "register_operand" "") 0) + (zero_extract:SI (match_operand:HI 1 "register_operand" "") + (const_int 8) (const_int 1))) + ;; Store high byte into the memory word + (set (zero_extract:SI (match_dup 2) (const_int 8) (match_dup 3)) + (subreg:SI (match_dup 4) 0)) + ;; Put memory word back into memory. + (set (mem:SI (match_dup 0)) + (match_dup 2))] + "" + " +{ + if (GET_CODE (operands[1]) == SUBREG) + operands[5] = gen_rtx (SUBREG, SImode, SUBREG_REG (operands[1]), + SUBREG_WORD (operands[1])); + else + operands[5] = gen_rtx (SUBREG, SImode, operands[1], 0); +}") + +;; Like storehi but operands[1] is a CONST_INT. + +(define_expand "storeinthi" + [(set (match_operand:SI 2 "register_operand" "") + (mem:SI (match_operand:SI 0 "register_operand" ""))) + ;; Insert the low byte. + (set (zero_extract:SI (match_dup 2) (const_int 8) (match_dup 0)) + (match_dup 5)) + ;; Form address of high byte. + (set (match_operand:SI 3 "register_operand" "") + (plus:SI (match_dup 0) (const_int 1))) + ;; Store high byte into the memory word + (set (zero_extract:SI (match_dup 2) (const_int 8) (match_dup 3)) + (match_dup 6)) + ;; Put memory word back into memory. + (set (mem:SI (match_dup 0)) + (match_dup 2))] + "" + " operands[5] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[1]) & 255); + operands[6] = gen_rtx (CONST_INT, VOIDmode, + (INTVAL (operands[1]) >> 8) & 255); +") + +;; Main entry for generating insns to move halfwords. + +(define_expand "movhi" + [(set (match_operand:HI 0 "general_operand" "") + (match_operand:HI 1 "general_operand" ""))] + "" + " +{ + if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM) + operands[1] = copy_to_reg (operands[1]); + + if (GET_CODE (operands[1]) == MEM) + { + rtx insn = + emit_insn (gen_loadhi (operands[0], + force_reg (SImode, XEXP (operands[1], 0)), + gen_reg_rtx (SImode), gen_reg_rtx (SImode), + gen_reg_rtx (QImode))); + /* Tell cse what value the loadhi produces, so it detect duplicates. */ + REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_EQUAL, operands[1], + REG_NOTES (insn)); + } + else if (GET_CODE (operands[0]) == MEM) + { + if (GET_CODE (operands[1]) == CONST_INT) + emit_insn (gen_storeinthi (force_reg (SImode, XEXP (operands[0], 0)), + operands[1], + gen_reg_rtx (SImode), gen_reg_rtx (SImode), + gen_reg_rtx (QImode))); + else + { + if (CONSTANT_P (operands[1])) + operands[1] = force_reg (HImode, operands[1]); + emit_insn (gen_storehi (force_reg (SImode, XEXP (operands[0], 0)), + operands[1], + gen_reg_rtx (SImode), gen_reg_rtx (SImode), + gen_reg_rtx (QImode))); + } + } + else + emit_insn (gen_rtx (SET, VOIDmode, operands[0], operands[1])); + DONE; +}") + +;; Recognize insns generated for moving halfwords. +;; (Note that the extract and insert patterns for single-byte moves +;; are also involved in recognizing some of the insns used for this purpose.) + +(define_insn "" + [(set (match_operand:HI 0 "general_operand" "=r,m") + (match_operand:HI 1 "general_operand" "rmi,r"))] + "" + "* +{ + if (GET_CODE (operands[0]) == MEM) + return \"st_32 %1,%0\"; + if (GET_CODE (operands[1]) == MEM) + return \"ld_32 %0,%1\;nop\"; + if (GET_CODE (operands[1]) == REG) + return \"add_nt %0,%1,$0\"; + return \"add_nt %0,r0,%1\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (zero_extract:SI (match_operand:HI 1 "register_operand" "r") + (const_int 8) + (match_operand:SI 2 "nonmemory_operand" "rI")))] + "" + "extract %0,%1,%2") + +(define_insn "" + [(set (zero_extract:SI (match_operand:HI 0 "register_operand" "+r") + (const_int 8) + (match_operand:SI 1 "nonmemory_operand" "rI")) + (match_operand:SI 2 "nonmemory_operand" "ri"))] + "" + "wr_insert %1\;insert %0,%0,%2") + +;; Constant propagation can optimize the previous pattern into this pattern. + +;(define_insn "" +; [(set (zero_extract:QI (match_operand:HI 0 "register_operand" "+r") +; (const_int 8) +; (match_operand:SI 1 "immediate_operand" "I")) +; (match_operand:QI 2 "register_operand" "r"))] +; "GET_CODE (operands[1]) == CONST_INT +; && INTVAL (operands[1]) % 8 == 0 +; && (unsigned) INTVAL (operands[1]) < 32" +; "* +;{ +; operands[1] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[1]) / 8); +; return \"wr_insert 0,0,%1\;insert %0,%0,%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 "" + [(set (match_operand:DF 0 "general_operand" "=&r,f,&o") + (match_operand:DF 1 "" "mG,m,G"))] + "GET_CODE (operands[1]) == CONST_DOUBLE" + "* +{ + if (FP_REG_P (operands[0])) + return output_fp_move_double (operands); + if (operands[1] == dconst0_rtx && GET_CODE (operands[0]) == REG) + { + operands[1] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); + return \"add_nt %0,r0,$0\;add_nt %1,r0,$0\"; + } + if (operands[1] == dconst0_rtx && GET_CODE (operands[0]) == MEM) + { + operands[1] = adj_offsettable_operand (operands[0], 4); + return \"st_32 r0,%0\;st_32 r0,%1\"; + } + return output_move_double (operands); +} +") + +(define_insn "movdf" + [(set (match_operand:DF 0 "general_operand" "=r,&r,m,?f,?rm") + (match_operand:DF 1 "general_operand" "r,m,r,rfm,f"))] + "" + "* +{ + if (FP_REG_P (operands[0]) || FP_REG_P (operands[1])) + return output_fp_move_double (operands); + return output_move_double (operands); +} +") + +(define_insn "movdi" + [(set (match_operand:DI 0 "general_operand" "=r,&r,m,?f,?rm") + (match_operand:DI 1 "general_operand" "r,m,r,rfm,f"))] + "" + "* +{ + if (FP_REG_P (operands[0]) || FP_REG_P (operands[1])) + return output_fp_move_double (operands); + return output_move_double (operands); +} +") + +(define_insn "movsf" + [(set (match_operand:SF 0 "general_operand" "=rf,m") + (match_operand:SF 1 "general_operand" "rfm,rf"))] + "" + "* +{ + if (FP_REG_P (operands[0])) + { + if (FP_REG_P (operands[1])) + return \"fmov %0,%1\"; + if (GET_CODE (operands[1]) == REG) + { + rtx xoperands[2]; + int offset = - get_frame_size () - 8; + xoperands[1] = operands[1]; + xoperands[0] = gen_rtx (CONST_INT, VOIDmode, offset); + output_asm_insn (\"st_32 %1,r25,%0\", xoperands); + xoperands[1] = operands[0]; + output_asm_insn (\"ld_sgl %1,r25,%0\;nop\", xoperands); + return \"\"; + } + return \"ld_sgl %0,%1\;nop\"; + } + if (FP_REG_P (operands[1])) + { + if (GET_CODE (operands[0]) == REG) + { + rtx xoperands[2]; + int offset = - get_frame_size () - 8; + xoperands[0] = gen_rtx (CONST_INT, VOIDmode, offset); + xoperands[1] = operands[1]; + output_asm_insn (\"st_sgl %1,r25,%0\", xoperands); + xoperands[1] = operands[0]; + output_asm_insn (\"ld_32 %1,r25,%0\;nop\", xoperands); + return \"\"; + } + return \"st_sgl %1,%0\"; + } + if (GET_CODE (operands[0]) == MEM) + return \"st_32 %r1,%0\"; + if (GET_CODE (operands[1]) == MEM) + return \"ld_32 %0,%1\;nop\"; + if (GET_CODE (operands[1]) == REG) + return \"add_nt %0,%1,$0\"; + return \"add_nt %0,r0,%1\"; +}") + +;;- truncation instructions +(define_insn "truncsiqi2" + [(set (match_operand:QI 0 "register_operand" "=r") + (truncate:QI + (match_operand:SI 1 "register_operand" "r")))] + "" + "add_nt %0,%1,$0") + +(define_insn "trunchiqi2" + [(set (match_operand:QI 0 "register_operand" "=r") + (truncate:QI + (match_operand:HI 1 "register_operand" "r")))] + "" + "add_nt %0,%1,$0") + +(define_insn "truncsihi2" + [(set (match_operand:HI 0 "register_operand" "=r") + (truncate:HI + (match_operand:SI 1 "register_operand" "r")))] + "" + "add_nt %0,%1,$0") + +;;- zero extension instructions + +;; Note that the one starting from HImode comes before those for QImode +;; so that a constant operand will match HImode, not QImode. +(define_expand "zero_extendhisi2" + [(set (match_operand:SI 0 "register_operand" "") + (and:SI (match_operand:HI 1 "register_operand" "") ;Changed to SI below + ;; This constant is invalid, but reloading will handle it. + ;; It's useless to generate here the insns to construct it + ;; because constant propagation would simplify them anyway. + (match_dup 2)))] + "" + " +{ + if (GET_CODE (operands[1]) == SUBREG) + operands[1] = gen_rtx (SUBREG, SImode, SUBREG_REG (operands[1]), + SUBREG_WORD (operands[1])); + else + operands[1] = gen_rtx (SUBREG, SImode, operands[1], 0); + + operands[2] = force_reg (SImode, gen_rtx (CONST_INT, VOIDmode, 65535)); +}") + +(define_insn "zero_extendqihi2" + [(set (match_operand:HI 0 "register_operand" "=r") + (zero_extend:HI + (match_operand:QI 1 "register_operand" "r")))] + "" + "extract %0,%1,$0") + +(define_insn "zero_extendqisi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (zero_extend:SI + (match_operand:QI 1 "register_operand" "r")))] + "" + "extract %0,%1,$0") + +;;- sign extension instructions +;; Note that the one starting from HImode comes before those for QImode +;; so that a constant operand will match HImode, not QImode. + +(define_expand "extendhisi2" + [(set (match_dup 2) + (and:SI (match_operand:HI 1 "register_operand" "") ;Changed to SI below + (match_dup 4))) + (set (match_dup 3) (plus:SI (match_dup 2) (match_dup 5))) + (set (match_operand:SI 0 "register_operand" "") + (xor:SI (match_dup 3) (match_dup 5)))] + "" + " +{ + if (GET_CODE (operands[1]) == SUBREG) + operands[1] = gen_rtx (SUBREG, SImode, SUBREG_REG (operands[1]), + SUBREG_WORD (operands[1])); + else + operands[1] = gen_rtx (SUBREG, SImode, operands[1], 0); + + operands[2] = gen_reg_rtx (SImode); + operands[3] = gen_reg_rtx (SImode); + operands[4] = force_reg (SImode, gen_rtx (CONST_INT, VOIDmode, 65535)); + operands[5] = force_reg (SImode, gen_rtx (CONST_INT, VOIDmode, -32768)); +}") + +(define_expand "extendqihi2" + [(set (match_dup 2) + (and:HI (match_operand:QI 1 "register_operand" "") ;Changed to SI below + (const_int 255))) + (set (match_dup 3) + (plus:SI (match_dup 2) (const_int -128))) + (set (match_operand:HI 0 "register_operand" "") + (xor:SI (match_dup 3) (const_int -128)))] + "" + " +{ + if (GET_CODE (operands[1]) == SUBREG) + operands[1] = gen_rtx (SUBREG, HImode, SUBREG_REG (operands[1]), + SUBREG_WORD (operands[1])); + else + operands[1] = gen_rtx (SUBREG, HImode, operands[1], 0); + + operands[2] = gen_reg_rtx (HImode); + operands[3] = gen_reg_rtx (HImode); +}") + +(define_expand "extendqisi2" + [(set (match_dup 2) + (and:SI (match_operand:QI 1 "register_operand" "") ;Changed to SI below + (const_int 255))) + (set (match_dup 3) (plus:SI (match_dup 2) (const_int -128))) + (set (match_operand:SI 0 "register_operand" "") + (xor:SI (match_dup 3) (const_int -128)))] + "" + " +{ + if (GET_CODE (operands[1]) == SUBREG) + operands[1] = gen_rtx (SUBREG, SImode, SUBREG_REG (operands[1]), + SUBREG_WORD (operands[1])); + else + operands[1] = gen_rtx (SUBREG, SImode, operands[1], 0); + + operands[2] = gen_reg_rtx (SImode); + operands[3] = gen_reg_rtx (SImode); +}") + +;;- arithmetic instructions + +(define_insn "addsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (plus:SI (match_operand:SI 1 "nonmemory_operand" "%r") + (match_operand:SI 2 "nonmemory_operand" "rI")))] + "" + "add %0,%1,%2") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (plus:SI (match_operand:SI 1 "nonmemory_operand" "%r") + (match_operand:SI 2 "big_immediate_operand" "g")))] + "GET_CODE (operands[2]) == CONST_INT + && (unsigned) (INTVAL (operands[2]) + 0x8000000) < 0x10000000" + "* +{ + return + output_add_large_offset (operands[0], operands[1], INTVAL (operands[2])); +}") + +(define_insn "subsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (minus:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "nonmemory_operand" "rI")))] + "" + "sub %0,%1,%2") + +(define_insn "andsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (and:SI (match_operand:SI 1 "nonmemory_operand" "%r") + (match_operand:SI 2 "nonmemory_operand" "rI")))] + "" + "and %0,%1,%2") + +(define_insn "iorsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (ior:SI (match_operand:SI 1 "nonmemory_operand" "%r") + (match_operand:SI 2 "nonmemory_operand" "rI")))] + "" + "or %0,%1,%2") + +(define_insn "xorsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (xor:SI (match_operand:SI 1 "nonmemory_operand" "%r") + (match_operand:SI 2 "nonmemory_operand" "rI")))] + "" + "xor %0,%1,%2") + +(define_insn "negsi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (neg:SI (match_operand:SI 1 "nonmemory_operand" "rI")))] + "" + "sub %0,r0,%1") + +(define_insn "one_cmplsi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (not:SI (match_operand:SI 1 "register_operand" "r")))] + "" + "xor %0,%1,$-1") + +;; Floating point arithmetic instructions. + +(define_insn "adddf3" + [(set (match_operand:DF 0 "register_operand" "=f") + (plus:DF (match_operand:DF 1 "register_operand" "f") + (match_operand:DF 2 "register_operand" "f")))] + "TARGET_FPU" + "fadd %0,%1,%2") + +(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" + "fadd %0,%1,%2") + +(define_insn "subdf3" + [(set (match_operand:DF 0 "register_operand" "=f") + (minus:DF (match_operand:DF 1 "register_operand" "f") + (match_operand:DF 2 "register_operand" "f")))] + "TARGET_FPU" + "fsub %0,%1,%2") + +(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" + "fsub %0,%1,%2") + +(define_insn "muldf3" + [(set (match_operand:DF 0 "register_operand" "=f") + (mult:DF (match_operand:DF 1 "register_operand" "f") + (match_operand:DF 2 "register_operand" "f")))] + "TARGET_FPU" + "fmul %0,%1,%2") + +(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" + "fmul %0,%1,%2") + +(define_insn "divdf3" + [(set (match_operand:DF 0 "register_operand" "=f") + (div:DF (match_operand:DF 1 "register_operand" "f") + (match_operand:DF 2 "register_operand" "f")))] + "TARGET_FPU" + "fdiv %0,%1,%2") + +(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" + "fdiv %0,%1,%2") + +(define_insn "negdf2" + [(set (match_operand:DF 0 "register_operand" "=f") + (neg:DF (match_operand:DF 1 "nonmemory_operand" "f")))] + "TARGET_FPU" + "fneg %0,%1") + +(define_insn "negsf2" + [(set (match_operand:SF 0 "register_operand" "=f") + (neg:SF (match_operand:SF 1 "nonmemory_operand" "f")))] + "TARGET_FPU" + "fneg %0,%1") + +(define_insn "absdf2" + [(set (match_operand:DF 0 "register_operand" "=f") + (abs:DF (match_operand:DF 1 "nonmemory_operand" "f")))] + "TARGET_FPU" + "fabs %0,%1") + +(define_insn "abssf2" + [(set (match_operand:SF 0 "register_operand" "=f") + (abs:SF (match_operand:SF 1 "nonmemory_operand" "f")))] + "TARGET_FPU" + "fabs %0,%1") + +;; Shift instructions + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (ashift:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "immediate_operand" "I")))] + "GET_CODE (operands[2]) == CONST_INT" + "* +{ + unsigned int amount = INTVAL (operands[2]); + + switch (amount) + { + case 0: + return \"add_nt %0,%1,$0\"; + case 1: + return \"sll %0,%1,$1\"; + case 2: + return \"sll %0,%1,$2\"; + default: + output_asm_insn (\"sll %0,%1,$3\", operands); + + for (amount -= 3; amount >= 3; amount -= 3) + output_asm_insn (\"sll %0,%0,$3\", operands); + + if (amount > 0) + output_asm_insn (amount == 1 ? \"sll %0,%0,$1\" : \"sll %0,%0,$2\", + operands); + return \"\"; + } +}") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (ashiftrt:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "immediate_operand" "I")))] + "GET_CODE (operands[2]) == CONST_INT" + "* +{ + unsigned int amount = INTVAL (operands[2]); + + if (amount == 0) + return \"add_nt %0,%1,$0\"; + else + output_asm_insn (\"sra %0,%1,$1\", operands); + + for (amount -= 1; amount > 0; amount -= 1) + output_asm_insn (\"sra %0,%0,$1\", operands); + + return \"\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (lshiftrt:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "immediate_operand" "I")))] + "GET_CODE (operands[2]) == CONST_INT" + "* +{ + unsigned int amount = INTVAL (operands[2]); + + if (amount == 0) + return \"add_nt %0,%1,$0\"; + else + output_asm_insn (\"srl %0,%1,$1\", operands); + + for (amount -= 1; amount > 0; amount -= 1) + output_asm_insn (\"srl %0,%0,$1\", operands); + + return \"\"; +}") + +(define_expand "ashlsi3" + [(set (match_operand:SI 0 "register_operand" "") + (ashift:SI (match_operand:SI 1 "register_operand" "") + (match_operand:SI 2 "nonmemory_operand" "")))] + "" + " +{ + if (GET_CODE (operands[2]) != CONST_INT + || (! TARGET_EXPAND_SHIFTS && (unsigned) INTVAL (operands[2]) > 3)) + FAIL; +}") + +(define_expand "lshlsi3" + [(set (match_operand:SI 0 "register_operand" "") + (ashift:SI (match_operand:SI 1 "register_operand" "") + (match_operand:SI 2 "nonmemory_operand" "")))] + "" + " +{ + if (GET_CODE (operands[2]) != CONST_INT + || (! TARGET_EXPAND_SHIFTS && (unsigned) INTVAL (operands[2]) > 3)) + FAIL; +}") + +(define_expand "ashrsi3" + [(set (match_operand:SI 0 "register_operand" "") + (ashiftrt:SI (match_operand:SI 1 "register_operand" "") + (match_operand:SI 2 "nonmemory_operand" "")))] + "" + " +{ + if (GET_CODE (operands[2]) != CONST_INT + || (! TARGET_EXPAND_SHIFTS && (unsigned) INTVAL (operands[2]) > 1)) + FAIL; +}") + +(define_expand "lshrsi3" + [(set (match_operand:SI 0 "register_operand" "") + (lshiftrt:SI (match_operand:SI 1 "register_operand" "") + (match_operand:SI 2 "nonmemory_operand" "")))] + "" + " +{ + if (GET_CODE (operands[2]) != CONST_INT + || (! TARGET_EXPAND_SHIFTS && (unsigned) INTVAL (operands[2]) > 1)) + FAIL; +}") + +;; Unconditional and other jump instructions +(define_insn "jump" + [(set (pc) + (label_ref (match_operand 0 "" "")))] + "" + "jump %l0\;nop") + +(define_insn "tablejump" + [(set (pc) (match_operand:SI 0 "register_operand" "r")) + (use (label_ref (match_operand 1 "" "")))] + "" + "jump_reg r0,%0\;nop") + +;;- jump to subroutine +(define_insn "call" + [(call (match_operand:SI 0 "memory_operand" "m") + (match_operand:SI 1 "general_operand" "g"))] + ;;- Don't use operand 1 for most machines. + "" + "add_nt r2,%0\;call .+8\;jump_reg r0,r2\;nop") + +(define_insn "call_value" + [(set (match_operand 0 "" "=g") + (call (match_operand:SI 1 "memory_operand" "m") + (match_operand:SI 2 "general_operand" "g")))] + ;;- Don't use operand 1 for most machines. + "" + "add_nt r2,%1\;call .+8\;jump_reg r0,r2\;nop") + +;; A memory ref with constant address is not normally valid. +;; But it is valid in a call insns. This pattern allows the +;; loading of the address to combine with the call. +(define_insn "" + [(call (mem:SI (match_operand:SI 0 "" "i")) + (match_operand:SI 1 "general_operand" "g"))] + ;;- Don't use operand 1 for most machines. + "GET_CODE (operands[0]) == SYMBOL_REF" + "call %0\;nop") + +(define_insn "" + [(set (match_operand 0 "" "=g") + (call (mem:SI (match_operand:SI 1 "" "i")) + (match_operand:SI 2 "general_operand" "g")))] + ;;- Don't use operand 1 for most machines. + "GET_CODE (operands[1]) == SYMBOL_REF" + "call %1\;nop") + +(define_insn "nop" + [(const_int 0)] + "" + "nop") + +;;- Local variables: +;;- mode:emacs-lisp +;;- comment-start: ";;- " +;;- eval: (set-syntax-table (copy-sequence (syntax-table))) +;;- eval: (modify-syntax-entry ?[ "(]") +;;- eval: (modify-syntax-entry ?] ")[") +;;- eval: (modify-syntax-entry ?{ "(}") +;;- eval: (modify-syntax-entry ?} "){") +;;- End: + diff --git a/gcc-1.40/config/tahoe.md b/gcc-1.40/config/tahoe.md new file mode 100644 index 0000000..a96dd45 --- /dev/null +++ b/gcc-1.40/config/tahoe.md @@ -0,0 +1,1497 @@ +;;- Machine description for GNU compiler +;;- Tahoe version +;; Copyright (C) 1989 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 1, 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. + + +; File: tahoe.md +; +; This port made at the University of Buffalo by Devon Bowen, +; Dale Wiles and Kevin Zachmann. +; +; Mail bugs reports or fixes to: gcc@cs.buffalo.edu + + +; movdi must call the output_move_double routine to move it around since +; the tahoe doesn't efficiently support 8 bit moves. + +(define_insn "movdi" + [(set (match_operand:DI 0 "general_operand" "=g") + (match_operand:DI 1 "general_operand" "g"))] + "" + "* +{ + CC_STATUS_INIT; + return output_move_double (operands); +}") + + +; The trick in the movsi is accessing the contents of the sp register. The +; tahoe doesn't allow you to access it directly so you have to access the +; address of the top of the stack instead. + +(define_insn "movsi" + [(set (match_operand:SI 0 "general_operand" "=g") + (match_operand:SI 1 "general_operand" "g"))] + "" + "* +{ + rtx link; + if (operands[1] == const1_rtx + && (link = find_reg_note (insn, REG_WAS_0, 0)) + && ! XEXP (link, 0)->volatil + && GET_CODE (XEXP (link, 0)) != NOTE + && no_labels_between_p (XEXP (link, 0), insn)) + return \"incl %0\"; + if (GET_CODE (operands[1]) == SYMBOL_REF || GET_CODE (operands[1]) == CONST) + { + if (push_operand (operands[0], SImode)) + return \"pushab %a1\"; + return \"movab %a1,%0\"; + } + if (operands[1] == const0_rtx) + return \"clrl %0\"; + if (push_operand (operands[0], SImode)) + return \"pushl %1\"; + if (GET_CODE (operands[1]) == REG && REGNO (operands[1]) == 14) + return \"moval (sp),%0\"; + return \"movl %1,%0\"; +}") + + +(define_insn "movhi" + [(set (match_operand:HI 0 "general_operand" "=g") + (match_operand:HI 1 "general_operand" "g"))] + "" + "* +{ + rtx link; + if (operands[1] == const1_rtx + && (link = find_reg_note (insn, REG_WAS_0, 0)) + && ! XEXP (link, 0)->volatil + && GET_CODE (XEXP (link, 0)) != NOTE + && no_labels_between_p (XEXP (link, 0), insn)) + return \"incw %0\"; + if (operands[1] == const0_rtx) + return \"clrw %0\"; + return \"movw %1,%0\"; +}") + + +(define_insn "movqi" + [(set (match_operand:QI 0 "general_operand" "=g") + (match_operand:QI 1 "general_operand" "g"))] + "" + "* +{ + if (operands[1] == const0_rtx) + return \"clrb %0\"; + return \"movb %1,%0\"; +}") + + +; movsf has three cases since they can move from one place to another +; or to/from the fpp and since different instructions are needed for +; each case. The fpp related instructions don't set the flags properly. + +(define_insn "movsf" + [(set (match_operand:SF 0 "general_operand" "=g,=a,=g") + (match_operand:SF 1 "general_operand" "g,g,a"))] + "" + "* +{ + CC_STATUS_INIT; + switch (which_alternative) + { + case 0: + return \"movl %1,%0\"; + case 1: + return \"ldf %1\"; + case 2: + return \"stf %0\"; + } +}") + + +; movdf has a number of different cases. If it's going to or from +; the fpp, use the special instructions to do it. If not, use the +; output_move_double function. + +(define_insn "movdf" + [(set (match_operand:DF 0 "general_operand" "=a,=g,?=g") + (match_operand:DF 1 "general_operand" "g,a,g"))] + "" + "* +{ + CC_STATUS_INIT; + switch (which_alternative) + { + case 0: + return \"ldd %1\"; + case 1: + if (push_operand (operands[0], DFmode)) + return \"pushd\"; + else + return \"std %0\"; + case 2: + return output_move_double (operands); + } +}") + + +(define_insn "addsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (plus:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")))] + "" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + { + if (operands[2] == const1_rtx) + return \"incl %0\"; + if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) == -1) + return \"decl %0\"; + if (GET_CODE (operands[2]) == CONST_INT + && (unsigned) (- INTVAL (operands[2])) < 64) + return \"subl2 $%n2,%0\"; + return \"addl2 %2,%0\"; + } + if (rtx_equal_p (operands[0], operands[2])) + return \"addl2 %1,%0\"; + if (GET_CODE (operands[2]) == CONST_INT + && GET_CODE (operands[1]) == REG) + { + if (push_operand (operands[0], SImode)) + return \"pushab %c2(%1)\"; + return \"movab %c2(%1),%0\"; + } + if (GET_CODE (operands[2]) == CONST_INT + && (unsigned) (- INTVAL (operands[2])) < 64) + return \"subl3 $%n2,%1,%0\"; + return \"addl3 %1,%2,%0\"; +}") + + +(define_insn "addhi3" + [(set (match_operand:HI 0 "general_operand" "=g") + (plus:HI (match_operand:HI 1 "general_operand" "g") + (match_operand:HI 2 "general_operand" "g")))] + "" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + { + if (operands[2] == const1_rtx) + return \"incw %0\"; + if (GET_CODE (operands[1]) == CONST_INT + && INTVAL (operands[1]) == -1) + return \"decw %0\"; + if (GET_CODE (operands[2]) == CONST_INT + && (unsigned) (- INTVAL (operands[2])) < 64) + return \"subw2 $%n2,%0\"; + return \"addw2 %2,%0\"; + } + if (rtx_equal_p (operands[0], operands[2])) + return \"addw2 %1,%0\"; + if (GET_CODE (operands[2]) == CONST_INT + && (unsigned) (- INTVAL (operands[2])) < 64) + return \"subw3 $%n2,%1,%0\"; + return \"addw3 %1,%2,%0\"; +}") + + +(define_insn "addqi3" + [(set (match_operand:QI 0 "general_operand" "=g") + (plus:QI (match_operand:QI 1 "general_operand" "g") + (match_operand:QI 2 "general_operand" "g")))] + "" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + { + if (operands[2] == const1_rtx) + return \"incb %0\"; + if (GET_CODE (operands[1]) == CONST_INT + && INTVAL (operands[1]) == -1) + return \"decb %0\"; + if (GET_CODE (operands[2]) == CONST_INT + && (unsigned) (- INTVAL (operands[2])) < 64) + return \"subb2 $%n2,%0\"; + return \"addb2 %2,%0\"; + } + if (rtx_equal_p (operands[0], operands[2])) + return \"addb2 %1,%0\"; + if (GET_CODE (operands[2]) == CONST_INT + && (unsigned) (- INTVAL (operands[2])) < 64) + return \"subb3 $%n2,%1,%0\"; + return \"addb3 %1,%2,%0\"; +}") + + +; addsf3 can only add into the fpp register since the fpp is treated +; as a separate unit in the machine. It also doesn't set the flags at +; all. + +(define_insn "addsf3" + [(set (match_operand:SF 0 "register_operand" "=a") + (plus:SF (match_operand:SF 1 "register_operand" "%0") + (match_operand:SF 2 "general_operand" "g")))] + "" + "* +{ + CC_STATUS_INIT; + return \"addf %2\"; +}") + + +; adddf3 can only add into the fpp reg since the fpp is treated as a +; separate entity. Doubles can only be read from a register or memory +; since a double is not an immediate mode. Flags are not set by this +; instruction. + +(define_insn "adddf3" + [(set (match_operand:DF 0 "register_operand" "=a") + (plus:DF (match_operand:DF 1 "register_operand" "%0") + (match_operand:DF 2 "general_operand" "rm")))] + "" + "* +{ + CC_STATUS_INIT; + return \"addd %2\"; +}") + + +; Subtraction from the sp (needed by the built in alloc funtion) needs +; to be different since the sp cannot be directly read on the tahoe. +; If it's a simple constant, you just use displacment. Otherwise, you +; push the sp, and then do the subtraction off the stack. + +(define_insn "subsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (minus:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")))] + "" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + { + if (operands[2] == const1_rtx) + return \"decl %0\"; + if (GET_CODE (operands[0]) == REG && REGNO (operands[0]) == 14) + if (GET_CODE (operands[2]) == CONST_INT) + return \"movab %n2(sp),sp\"; + else + return \"pushab (sp)\;subl3 %2,(sp),sp\"; + return \"subl2 %2,%0\"; + } + if (rtx_equal_p (operands[1], operands[2])) + return \"clrl %0\"; + return \"subl3 %2,%1,%0\"; +}") + + +(define_insn "subhi3" + [(set (match_operand:HI 0 "general_operand" "=g") + (minus:HI (match_operand:HI 1 "general_operand" "g") + (match_operand:HI 2 "general_operand" "g")))] + "" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + { + if (operands[2] == const1_rtx) + return \"decw %0\"; + return \"subw2 %2,%0\"; + } + if (rtx_equal_p (operands[1], operands[2])) + return \"clrw %0\"; + return \"subw3 %2,%1,%0\"; +}") + + +(define_insn "subqi3" + [(set (match_operand:QI 0 "general_operand" "=g") + (minus:QI (match_operand:QI 1 "general_operand" "g") + (match_operand:QI 2 "general_operand" "g")))] + "" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + { + if (operands[2] == const1_rtx) + return \"decb %0\"; + return \"subb2 %2,%0\"; + } + if (rtx_equal_p (operands[1], operands[2])) + return \"clrb %0\"; + return \"subb3 %2,%1,%0\"; +}") + + +; subsf3 can only subtract into the fpp accumulator due to the way +; the fpp reg is limited by the instruction set. This also doesn't +; bother setting up flags. + +(define_insn "subsf3" + [(set (match_operand:SF 0 "register_operand" "=a") + (minus:SF (match_operand:SF 1 "register_operand" "0") + (match_operand:SF 2 "general_operand" "g")))] + "" + "* +{ + CC_STATUS_INIT; + return \"subf %2\"; +}") + + +; subdf3 is set up to subtract into the fpp reg due to limitations +; of the fpp instruction set. Doubles can not be immediate. This +; instruction does not set the flags. + +(define_insn "subdf3" + [(set (match_operand:DF 0 "register_operand" "=a") + (minus:DF (match_operand:DF 1 "register_operand" "0") + (match_operand:DF 2 "general_operand" "rm")))] + "" + "* +{ + CC_STATUS_INIT; + return \"subd %2\"; +}") + + +(define_insn "mulsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (mult:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")))] + "" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + return \"mull2 %2,%0\"; + if (rtx_equal_p (operands[0], operands[2])) + return \"mull2 %1,%0\"; + return \"mull3 %1,%2,%0\"; +}") + + +; mulsf3 can only multiply into the fpp accumulator due to limitations +; of the fpp. It also does not set the condition codes properly. + +(define_insn "mulsf3" + [(set (match_operand:SF 0 "register_operand" "=a") + (mult:SF (match_operand:SF 1 "register_operand" "%0") + (match_operand:SF 2 "general_operand" "g")))] + "" + "* +{ + CC_STATUS_INIT; + return \"mulf %2\"; +}") + + +; muldf3 can only multiply into the fpp reg since the fpp is limited +; from the rest. Doubles may not be immediate mode. This does not set +; the flags like GCC would expect. + +(define_insn "muldf3" + [(set (match_operand:DF 0 "register_operand" "=a") + (mult:DF (match_operand:DF 1 "register_operand" "%0") + (match_operand:DF 2 "general_operand" "rm")))] + "" + "* +{ + CC_STATUS_INIT; + return \"muld %2\"; +}") + + +(define_insn "divsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (div:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")))] + "" + "* +{ + if (rtx_equal_p (operands[1], operands[2])) + return \"movl $1,%0\"; + if (operands[1] == const0_rtx) + return \"clrl %0\"; + if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) == -1) + return \"mnegl %1,%0\"; + if (rtx_equal_p (operands[0], operands[1])) + return \"divl2 %2,%0\"; + return \"divl3 %2,%1,%0\"; +}") + + +; divsf3 must divide into the fpp accumulator. Flags are not set by +; this instruction, so they are cleared. + +(define_insn "divsf3" + [(set (match_operand:SF 0 "register_operand" "=a") + (div:SF (match_operand:SF 1 "register_operand" "0") + (match_operand:SF 2 "general_operand" "g")))] + "" + "* +{ + CC_STATUS_INIT; + return \"divf %2\"; +}") + + +; divdf3 also must divide into the fpp reg so optimization isn't +; possible. Note that doubles cannot be immediate. The flags here +; are not set correctly so they must be ignored. + +(define_insn "divdf3" + [(set (match_operand:DF 0 "register_operand" "=a") + (div:DF (match_operand:DF 1 "register_operand" "0") + (match_operand:DF 2 "general_operand" "rm")))] + "" + "* +{ + CC_STATUS_INIT; + return \"divd %2\"; +}") + + +(define_insn "andsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (and:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")))] + "" + "andl3 %2,%1,%0") + + +(define_insn "andhi3" + [(set (match_operand:HI 0 "general_operand" "=g") + (and:HI (match_operand:HI 1 "general_operand" "g") + (match_operand:HI 2 "general_operand" "g")))] + "" + "andw3 %1,%2,%0") + + +(define_insn "andqi3" + [(set (match_operand:QI 0 "general_operand" "=g") + (and:QI (match_operand:QI 1 "general_operand" "g") + (match_operand:QI 2 "general_operand" "g")))] + "" + "andb3 %1,%2,%0") + + +(define_insn "iorsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (ior:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")))] + "" + "orl3 %2,%1,%0") + + +(define_insn "iorhi3" + [(set (match_operand:HI 0 "general_operand" "=g") + (ior:HI (match_operand:HI 1 "general_operand" "g") + (match_operand:HI 2 "general_operand" "g")))] + "" + "orw3 %2,%1,%0") + + +(define_insn "iorqi3" + [(set (match_operand:QI 0 "general_operand" "=g") + (ior:QI (match_operand:QI 1 "general_operand" "g") + (match_operand:QI 2 "general_operand" "g")))] + "" + "orb3 %2,%1,%0") + + +(define_insn "xorsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (xor:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")))] + "" + "xorl3 %1,%2,%0") + + +(define_insn "xorhi3" + [(set (match_operand:HI 0 "general_operand" "=g") + (xor:HI (match_operand:HI 1 "general_operand" "g") + (match_operand:HI 2 "general_operand" "g")))] + "" + "xorw3 %1,%2,%0") + + +(define_insn "xorqi3" + [(set (match_operand:QI 0 "general_operand" "=g") + (xor:QI (match_operand:QI 1 "general_operand" "g") + (match_operand:QI 2 "general_operand" "g")))] + "" + "xorb3 %1,%2,%0") + + +; Shifts on the tahoe are expensive, so try to do an add instead. + +(define_insn "ashlsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (ashift:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:QI 2 "general_operand" "g")))] + "" + "* +{ + if (operands[2] == const1_rtx && rtx_equal_p (operands[0], operands[1])) + { + CC_STATUS_INIT; + return \"addl2 %0,%0\"; + } + return \"shal %2,%1,%0\"; +}") + + +(define_insn "ashrsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (ashiftrt:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:QI 2 "general_operand" "g")))] + "" + "shar %2,%1,%0") + + +; Shifts are very expensive, so try to do an add if possible. + +(define_insn "lshlsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (lshift:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:QI 2 "general_operand" "g")))] + "" + "* +{ + if (operands[2] == const1_rtx && rtx_equal_p (operands[0], operands[1])) + { + CC_STATUS_INIT; + return \"addl2 %0,%0\"; + } + return \"shll %2,%1,%0\"; +}") + + +(define_insn "lshrsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (lshiftrt:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:QI 2 "general_operand" "g")))] + "" + "shrl %2,%1,%0") + + +(define_insn "negsi2" + [(set (match_operand:SI 0 "general_operand" "=g") + (neg:SI (match_operand:SI 1 "general_operand" "g")))] + "" + "mnegl %1,%0") + + +(define_insn "neghi2" + [(set (match_operand:HI 0 "general_operand" "=g") + (neg:HI (match_operand:HI 1 "general_operand" "g")))] + "" + "mnegw %1,%0") + + +(define_insn "negqi2" + [(set (match_operand:QI 0 "general_operand" "=g") + (neg:QI (match_operand:QI 1 "general_operand" "g")))] + "" + "mnegb %1,%0") + + +; negsf2 can only negate the value already in the fpp accumulator. +; The value remains in the fpp accumulator. No flags are set. + +(define_insn "negsf2" + [(set (match_operand:SF 0 "register_operand" "=a,=a") + (neg:SF (match_operand:SF 1 "register_operand" "a,g")))] + "" + "* +{ + CC_STATUS_INIT; + switch (which_alternative) + { + case 0: + return \"negf\"; + case 1: + return \"lnf %1\"; + } +}") + + +; negdf2 can only negate the value already in the fpp accumulator. +; The value remains in the fpp accumulator. No flags are set. + +(define_insn "negdf2" + [(set (match_operand:DF 0 "register_operand" "=a,=a") + (neg:DF (match_operand:DF 1 "register_operand" "a,g")))] + "" + "* +{ + CC_STATUS_INIT; + switch (which_alternative) + { + case 0: + return \"negd\"; + case 1: + return \"lnd %1\"; + } +}") + + +; sqrtsf2 tahoe can calculate the square root of a float in the +; fpp accumulator. The answer remains in the fpp accumulator. No +; flags are set by this function. + +(define_insn "sqrtsf2" + [(set (match_operand:SF 0 "register_operand" "=a") + (sqrt:SF (match_operand:SF 1 "register_operand" "0")))] + "" + "* +{ + CC_STATUS_INIT; + return \"sqrtf\"; +}") + + +; ffssi2 tahoe instruction gives one less than GCC desired result for +; any given input. So the increment is necessary here. + +(define_insn "ffssi2" + [(set (match_operand:SI 0 "general_operand" "=g") + (ffs:SI (match_operand:SI 1 "general_operand" "g")))] + "" + "ffs %1,%0\;incl %0") + + +(define_insn "one_cmplsi2" + [(set (match_operand:SI 0 "general_operand" "=g") + (not:SI (match_operand:SI 1 "general_operand" "g")))] + "" + "mcoml %1,%0") + + +(define_insn "one_cmplhi2" + [(set (match_operand:HI 0 "general_operand" "=g") + (not:HI (match_operand:HI 1 "general_operand" "g")))] + "" + "mcomw %1,%0") + + +(define_insn "one_cmplqi2" + [(set (match_operand:QI 0 "general_operand" "=g") + (not:QI (match_operand:QI 1 "general_operand" "g")))] + "" + "mcomb %1,%0") + + +; cmpsi works fine, but due to microcode problems, the tahoe doesn't +; properly compare hi's and qi's. Leaving them out seems to be acceptable +; to the compiler, so they were left out. Compares of the stack are +; possible, though. + +;; Put cmpsi first among compare insns so it matches two CONST_INT operands. + +(define_insn "cmpsi" + [(set (cc0) + (compare (match_operand:SI 0 "general_operand" "g") + (match_operand:SI 1 "general_operand" "g")))] + "" + "cmpl %0,%1") + + +; cmpsf similar to vax, but first operand is expected to be in the +; fpp accumulator. + +(define_insn "cmpsf" + [(set (cc0) + (compare (match_operand:SF 0 "register_operand" "a") + (match_operand:SF 1 "general_operand" "g")))] + "" + "cmpf %1") + + +; cmpdf similar to vax, but first operand is expected to be in the +; fpp accumulator. Immediate doubles not allowed. + +(define_insn "cmpdf" + [(set (cc0) + (compare (match_operand:DF 0 "register_operand" "a") + (match_operand:DF 1 "general_operand" "rm")))] + "" + "cmpd %1") + + +;; Put tstsi first among test insns so it matches a CONST_INT operand. + +(define_insn "tstsi" + [(set (cc0) + (match_operand:SI 0 "general_operand" "g"))] + "" + "tstl %0") + + +; Small tests from memory are normal, but testing from registers don't +; expand the data properly. So test in this case does a convert and tests +; the new register data from the stack. + +(define_insn "tsthi" + [(set (cc0) + (match_operand:HI 0 "general_operand" "m,?r"))] + "" + "* +{ + switch (which_alternative) + { + case 0: + return \"tstw %0\"; + case 1: + return \"pushl %0\;cvtwl 2(sp),(sp)\;tstl (sp)+\"; + } +}") + + +; Small tests from memory are normal, but testing from registers don't +; expand the data properly. So test in this case does a convert and tests +; the new register data from the stack. + +(define_insn "tstqi" + [(set (cc0) + (match_operand:QI 0 "general_operand" "m,?r"))] + "" + "* +{ + switch (which_alternative) + { + case 0: + return \"tstb %0\"; + case 1: + return \"pushl %0\;cvtbl 3(sp),(sp)\;tstl (sp)+\"; + } +}") + + +; tstsf compares a given value to a value already in the fpp accumulator. +; No flags are set by this so ignore them. + +(define_insn "tstsf" + [(set (cc0) + (match_operand:SF 0 "register_operand" "a"))] + "" + "tstf") + + +; tstdf compares a given value to a value already in the fpp accumulator. +; immediate doubles not allowed. Flags are ignored after this. + +(define_insn "tstdf" + [(set (cc0) + (match_operand:DF 0 "register_operand" "a"))] + "" + "tstd") + + +; movstrhi tahoe instruction does not load registers by itself like +; the vax counterpart does. registers 0-2 must be primed by hand. +; we have loaded the registers in the order: dst, src, count. + +(define_insn "movstrhi" + [(set (match_operand:BLK 0 "general_operand" "p") + (match_operand:BLK 1 "general_operand" "p")) + (use (match_operand:HI 2 "general_operand" "g")) + (clobber (reg:SI 0)) + (clobber (reg:SI 1)) + (clobber (reg:SI 2))] + "" + "movab %0,r1\;movab %1,r0\;movl %2,r2\;movblk") + + +; floatsisf2 on tahoe converts the long from reg/mem into the fpp +; accumulator. There are no hi and qi counterparts. Flags are not +; set correctly here. + +(define_insn "floatsisf2" + [(set (match_operand:SF 0 "register_operand" "=a") + (float:SF (match_operand:SI 1 "general_operand" "g")))] + "" + "* +{ + CC_STATUS_INIT; + return \"cvlf %1\"; +}") + + +; floatsidf2 on tahoe converts the long from reg/mem into the fpp +; accumulator. There are no hi and qi counterparts. Flags are not +; set correctly here. + +(define_insn "floatsidf2" + [(set (match_operand:DF 0 "register_operand" "=a") + (float:DF (match_operand:SI 1 "general_operand" "g")))] + "" + "* +{ + CC_STATUS_INIT; + return \"cvld %1\"; +}") + + +; fix_truncsfsi2 to convert a float to long, tahoe must have the float +; in the fpp accumulator. Flags are not set here. + +(define_insn "fix_truncsfsi2" + [(set (match_operand:SI 0 "general_operand" "=g") + (fix:SI (fix:SF (match_operand:SF 1 "register_operand" "a"))))] + "" + "* +{ + CC_STATUS_INIT; + return \"cvfl %0\"; +}") + + +; fix_truncsfsi2 to convert a double to long, tahoe must have the double +; in the fpp accumulator. Flags are not set here. + +(define_insn "fix_truncdfsi2" + [(set (match_operand:SI 0 "general_operand" "=g") + (fix:SI (fix:DF (match_operand:DF 1 "register_operand" "a"))))] + "" + "* +{ + CC_STATUS_INIT; + return \"cvdl %0\"; +}") + + +(define_insn "truncsihi2" + [(set (match_operand:HI 0 "general_operand" "=g") + (truncate:HI (match_operand:SI 1 "general_operand" "g")))] + "" + "cvtlw %1,%0") + + +(define_insn "truncsiqi2" + [(set (match_operand:QI 0 "general_operand" "=g") + (truncate:QI (match_operand:SI 1 "general_operand" "g")))] + "" + "cvtlb %1,%0") + + +(define_insn "trunchiqi2" + [(set (match_operand:QI 0 "general_operand" "=g") + (truncate:QI (match_operand:HI 1 "general_operand" "g")))] + "" + "cvtwb %1,%0") + + +; The fpp related instructions don't set flags, so ignore them +; after this instruction. + +(define_insn "truncdfsf2" + [(set (match_operand:SF 0 "register_operand" "=a") + (float_truncate:SF (match_operand:DF 1 "register_operand" "0")))] + "" + "* +{ + CC_STATUS_INIT; + return \"cvdf\"; +}") + + +; This monster is to cover for the Tahoe's nasty habit of not extending +; a number if the source is in a register. (It just moves it!) Case 0 is +; a normal extend from memory. Case 1 does the extension from the top of +; the stack. Extension from the stack doesn't set the flags right since +; the moval changes them. + +(define_insn "extendhisi2" + [(set (match_operand:SI 0 "general_operand" "=g,?=g") + (sign_extend:SI (match_operand:HI 1 "general_operand" "m,r")))] + "" + "* +{ + switch (which_alternative) + { + case 0: + return \"cvtwl %1,%0\"; + case 1: + if (push_operand(operands[0], SImode)) + return \"pushl %1\;cvtwl 2(sp),(sp)\"; + else + { + CC_STATUS_INIT; + return \"pushl %1\;cvtwl 2(sp),%0\;moval 4(sp),sp\"; + } + } +}") + + +; This monster is to cover for the Tahoe's nasty habit of not extending +; a number if the source is in a register. (It just moves it!) Case 0 is +; a normal extend from memory. Case 1 does the extension from the top of +; the stack. Extension from the stack doesn't set the flags right since +; the moval changes them. + +(define_insn "extendqisi2" + [(set (match_operand:SI 0 "general_operand" "=g,?=g") + (sign_extend:SI (match_operand:QI 1 "general_operand" "m,r")))] + "" + "* +{ + switch (which_alternative) + { + case 0: + return \"cvtbl %1,%0\"; + case 1: + if (push_operand(operands[0], SImode)) + return \"pushl %1\;cvtbl 3(sp),(sp)\"; + else + { + CC_STATUS_INIT; + return \"pushl %1\;cvtbl 3(sp),%0\;moval 4(sp),sp\"; + } + } +}") + + +; This monster is to cover for the Tahoe's nasty habit of not extending +; a number if the source is in a register. (It just moves it!) Case 0 is +; a normal extend from memory. Case 1 does the extension from the top of +; the stack. Extension from the stack doesn't set the flags right since +; the moval changes them. + +(define_insn "extendqihi2" + [(set (match_operand:HI 0 "general_operand" "=g,?=g") + (sign_extend:HI (match_operand:QI 1 "general_operand" "m,r")))] + "" + "* +{ + switch (which_alternative) + { + case 0: + return \"cvtbw %1,%0\"; + case 1: + if (push_operand(operands[0], SImode)) + return \"pushl %1\;cvtbw 3(sp),2(sp)\"; + else { + CC_STATUS_INIT; + return \"pushl %1\;cvtbw 3(sp),%0\;moval 4(sp),sp\"; + } + } +}") + + +; extendsfdf2 tahoe uses the fpp accumulator to do the extension. +; It takes a float and loads it up directly as a double. + +(define_insn "extendsfdf2" + [(set (match_operand:DF 0 "register_operand" "=a") + (float_extend:DF (match_operand:SF 1 "general_operand" "g")))] + "" + "* +{ + CC_STATUS_INIT; + return \"ldfd %1\"; +}") + + +; movz works fine from memory but not from register for the same reasons +; the cvt instructions don't work right. So we use the normal instruction +; from memory and we use an and to simulate it from register. This is faster +; than pulling it off the stack. + +(define_insn "zero_extendhisi2" + [(set (match_operand:SI 0 "general_operand" "=g,?=g") + (zero_extend:SI (match_operand:HI 1 "general_operand" "m,r")))] + "" + "* +{ + switch (which_alternative) + { + case 0: + return \"movzwl %1,%0\"; + case 1: + return \"andl3 $0xffff,%1,%0\"; + } +}") + + +; movz works fine from memory but not from register for the same reasons +; the cvt instructions don't work right. So we use the normal instruction +; from memory and we use an and to simulate it from register. This is faster +; than pulling it off the stack. + +(define_insn "zero_extendqihi2" + [(set (match_operand:HI 0 "general_operand" "=g,?=g") + (zero_extend:HI (match_operand:QI 1 "general_operand" "m,r")))] + "" + "* +{ + switch (which_alternative) + { + case 0: + return \"movzbw %1,%0\"; + case 1: + return \"andw3 $0xff,%1,%0\"; + } +}") + + +; movz works fine from memory but not from register for the same reasons +; the cvt instructions don't work right. So we use the normal instruction +; from memory and we use an and to simulate it from register. This is faster +; than pulling it off the stack. + +(define_insn "zero_extendqisi2" + [(set (match_operand:SI 0 "general_operand" "=g,?=g") + (zero_extend:SI (match_operand:QI 1 "general_operand" "m,r")))] + "" + "* +{ + switch (which_alternative) + { + case 0: + return \"movzbl %1,%0\"; + case 1: + return \"andl3 $0xff,%1,%0\"; + } +}") + + +(define_insn "beq" + [(set (pc) + (if_then_else (eq (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "jeql %l0") + + +(define_insn "bne" + [(set (pc) + (if_then_else (ne (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "jneq %l0") + + +(define_insn "bgt" + [(set (pc) + (if_then_else (gt (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "jgtr %l0") + + +(define_insn "bgtu" + [(set (pc) + (if_then_else (gtu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "jgtru %l0") + + +(define_insn "blt" + [(set (pc) + (if_then_else (lt (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "jlss %l0") + + +(define_insn "bltu" + [(set (pc) + (if_then_else (ltu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "jlssu %l0") + + +(define_insn "bge" + [(set (pc) + (if_then_else (ge (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "jgeq %l0") + + +(define_insn "bgeu" + [(set (pc) + (if_then_else (geu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "jgequ %l0") + + +(define_insn "ble" + [(set (pc) + (if_then_else (le (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "jleq %l0") + + +(define_insn "bleu" + [(set (pc) + (if_then_else (leu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "jlequ %l0") + + +; GCC does not account for register mask/argc longword. Thus the number +; for the call = number bytes for args + 4 + +(define_insn "call" + [(call (match_operand:QI 0 "general_operand" "g") + (match_operand:QI 1 "general_operand" "g"))] + "" + "* +{ + operands[1] = gen_rtx (CONST_INT, VOIDmode, (INTVAL (operands[1]) + 4)); + return \"calls %1,%0\"; +}") + + +; GCC does not account for register mask/argc longword. Thus the number +; for the call = number bytes for args + 4 + +(define_insn "call_value" + [(set (match_operand 0 "" "=g") + (call (match_operand:QI 1 "general_operand" "g") + (match_operand:QI 2 "general_operand" "g")))] + "" + "* +{ + operands[2] = gen_rtx (CONST_INT, VOIDmode, (INTVAL (operands[2]) + 4)); + return \"calls %2,%1\"; +}") + + +(define_insn "nop" + [(const_int 0)] + "" + "nop") + + +(define_insn "return" + [(return)] + "" + "ret") + + +; casesi, extracted from the vax code. The instructions are +; very similar. Tahoe requires that the table be word aligned. GCC +; places the table immediately after, thus the alignment directive. + +(define_insn "casesi" + [(set (pc) + (if_then_else (le (minus:SI (match_operand:SI 0 "general_operand" "g") + (match_operand:SI 1 "general_operand" "g")) + (match_operand:SI 2 "general_operand" "g")) + (plus:SI (sign_extend:SI + (mem:HI (plus:SI (pc) + (minus:SI (match_dup 0) + (match_dup 1))))) + (label_ref:SI (match_operand 3 "" ""))) + (pc)))] + "" + "casel %0,%1,%2\;.align %@") + + +(define_insn "jump" + [(set (pc) + (label_ref (match_operand 0 "" "")))] + "" + "jbr %l0") + + +;; This is the list of all the non-standard insn patterns + + +; This is used to access the address of a byte. This is similar to +; movqi, but the second operand had to be "address_operand" type, so +; it had to be an unnamed one. + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=g") + (match_operand:QI 1 "address_operand" "p"))] + "" + "* +{ + if (push_operand (operands[0], SImode)) + return \"pushab %a1\"; + return \"movab %a1,%0\"; +}") + +; This is used to access the address of a word. This is similar to +; movhi, but the second operand had to be "address_operand" type, so +; it had to be an unnamed one. + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=g") + (match_operand:HI 1 "address_operand" "p"))] + "" + "* +{ + if (push_operand (operands[0], SImode)) + return \"pushaw %a1\"; + return \"movaw %a1,%0\"; +}") + +; This is used to access the address of a long. This is similar to +; movsi, but the second operand had to be "address_operand" type, so +; it had to be an unnamed one. + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=g") + (match_operand:SI 1 "address_operand" "p"))] + "" + "* +{ + if (push_operand (operands[0], SImode)) + return \"pushal %a1\"; + return \"moval %a1,%0\"; +}") + +; The tahoe doesn't have an 8 byte indexed move address command +; and GCC needs it. To work around it, double the index (%2) and +; then use the 4 byte indexed move address command. +; +;(define_insn "" +; [(set (match_operand:SI 0 "general_operand" "=g") +; (plus:SI (match_operand:SI 1 "general_operand" "g") +; (mult:SI (match_operand:SI 2 "register_operand" "r") +; (const_int 8))))] +; "" +; "* +;{ +; if (GET_CODE (operands[0]) == REG && +; REGNO (operands[0]) == REGNO (operands[2])) { +; return \"shll $3,%2,%2\;addl3 %1,%2,%0\"; +; } else { +; return \"shll $3,%2,%2\;addl3 %1,%2,%0\;shrl $3,%2,%2\"; } +;}") + + +; Bit test longword instruction, same as vax. + +(define_insn "" + [(set (cc0) + (and:SI (match_operand:SI 0 "general_operand" "g") + (match_operand:SI 1 "general_operand" "g")))] + "" + "bitl %0,%1") + + +; Bit test word instructions, same as vax. + +(define_insn "" + [(set (cc0) + (and:HI (match_operand:HI 0 "general_operand" "g") + (match_operand:HI 1 "general_operand" "g")))] + "" + "bitw %0,%1") + + +; Bit test instructions, same as vax. + +(define_insn "" + [(set (cc0) + (and:QI (match_operand:QI 0 "general_operand" "g") + (match_operand:QI 1 "general_operand" "g")))] + "" + "bitb %0,%1") + + +; bne counterpart. In case GCC reverses the conditional. + +(define_insn "" + [(set (pc) + (if_then_else (eq (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "jneq %l0") + + +; beq counterpart. In case GCC reverses the conditional. + +(define_insn "" + [(set (pc) + (if_then_else (ne (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "jeql %l0") + + +; ble counterpart. In case GCC reverses the conditional. + +(define_insn "" + [(set (pc) + (if_then_else (gt (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "jleq %l0") + + +; bleu counterpart. In case GCC reverses the conditional. + +(define_insn "" + [(set (pc) + (if_then_else (gtu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "jlequ %l0") + + +; bge counterpart. In case GCC reverses the conditional. + +(define_insn "" + [(set (pc) + (if_then_else (lt (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "jgeq %l0") + + +; bgeu counterpart. In case GCC reverses the conditional. + +(define_insn "" + [(set (pc) + (if_then_else (ltu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "jgequ %l0") + + +; blt counterpart. In case GCC reverses the conditional. + +(define_insn "" + [(set (pc) + (if_then_else (ge (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "jlss %l0") + + +; bltu counterpart. In case GCC reverses the conditional. + +(define_insn "" + [(set (pc) + (if_then_else (geu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "jlssu %l0") + + +; bgt counterpart. In case GCC reverses the conditional. + +(define_insn "" + [(set (pc) + (if_then_else (le (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "jgtr %l0") + + +; bgtu counterpart. In case GCC reverses the conditional. + +(define_insn "" + [(set (pc) + (if_then_else (leu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "jgtru %l0") + + +; casesi alternate form as found in vax code. This form is to +; compensate for the table's offset being no distance (0 displacement) + +(define_insn "" + [(set (pc) + (if_then_else (le (match_operand:SI 0 "general_operand" "g") + (match_operand:SI 1 "general_operand" "g")) + (plus:SI (sign_extend:SI + (mem:HI (plus:SI (pc) + (minus:SI (match_dup 0) + (const_int 0))))) + (label_ref:SI (match_operand 3 "" ""))) + (pc)))] + "" + "casel %0,$0,%1\;.align %@") + + +; casesi alternate form as found in vax code. Another form to +; compensate for the table's offset being no distance (0 displacement) + +(define_insn "" + [(set (pc) + (if_then_else (le (match_operand:SI 0 "general_operand" "g") + (match_operand:SI 1 "general_operand" "g")) + (plus:SI (sign_extend:SI + (mem:HI (plus:SI (pc) + (match_dup 0)))) + (label_ref:SI (match_operand 3 "" ""))) + (pc)))] + "" + "casel %0,$0,%1 \;.align %@") diff --git a/gcc-1.40/config/tm-3b1.h b/gcc-1.40/config/tm-3b1.h new file mode 100644 index 0000000..13b8f12 --- /dev/null +++ b/gcc-1.40/config/tm-3b1.h @@ -0,0 +1,482 @@ +/* Definitions of target machine for GNU compiler. + AT&T UNIX PC version (pc7300, 3b1) + + Written by Alex Crain + bug reports to alex@umbc3.umd.edu + + Copyright (C) 1987 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 1, 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. */ + +#define SGS_3B1 + +#include "tm-hp9k320.h" + +/* See tm-m68k.h. 0 means 680[01]0 with no 68881. */ + +#undef TARGET_DEFAULT +#define TARGET_DEFAULT 0 + +/* -m68020 requires special flags to the assembler. */ + +#undef ASM_SPEC +#define ASM_SPEC "%{m68020:-68020}%{!m68020:-68010}" + +/* we use /lib/libp/lib* when profiling */ + +#undef LIB_SPEC +#define LIB_SPEC "%{!shlib:%{p:-L/lib/libp} %{pg:-L/lib/libp} -lc}" + +/* shared libraries need to use crt0s.o */ + +#undef STARTFILE_SPEC +#define STARTFILE_SPEC \ + "%{!shlib:%{pg:mcrt0.o%s}%{!pg:%{p:mcrt0.o%s}%{!p:crt0.o%s}}}\ + %{shlib:crt0s.o%s shlib.ifile%s} " + +/* cpp has to support a #sccs directive for the /usr/include files */ + +#define SCCS_DIRECTIVE + +/* Make output for SDB. */ + +#define SDB_DEBUGGING_INFO + +/* The .file command should always begin the output. */ + +#undef ASM_FILE_START +#define ASM_FILE_START(FILE) sdbout_filename ((FILE), main_input_filename) + +/* Don't try to define `gcc_compiled.' since the assembler might not + accept symbols with periods and GDB doesn't run on this machine anyway. */ +#define ASM_IDENTIFY_GCC(FILE) + +/* Define __HAVE_68881__ in preprocessor if -m68881 is specified. + This will control the use of inline 68881 insns in certain macros. */ + +#undef CPP_SPEC +#define CPP_SPEC "%{m68881:-D__HAVE_68881__}" + +/* Names to predefine in the preprocessor for this target machine. */ +/* ihnp4!lmayk!lgm@eddie.mit.edu says mc68000 and m68k should not be here. */ + +#undef CPP_PREDEFINES +#define CPP_PREDEFINES "-Dmc68k -Dunix -Dunixpc" + +/* Specify how to pad function arguments. + Value should be `upward', `downward' or `none'. + Same as the default, except no padding for large or variable-size args. */ + +#define FUNCTION_ARG_PADDING(mode, size) \ + (((mode) == BLKmode \ + ? (GET_CODE (size) == CONST_INT \ + && INTVAL (size) < PARM_BOUNDARY / BITS_PER_UNIT) \ + : GET_MODE_BITSIZE (mode) < PARM_BOUNDARY) \ + ? downward : none) + +/* Override part of the obstack macros. */ + +#define __PTR_TO_INT(P) ((int)(P)) +#define __INT_TO_PTR(P) ((char *)(P)) + +/* Override parts of tm-m68k.h to fit the SGS-3b1 assembler. */ + +#undef TARGET_VERSION +#undef ASM_FORMAT_PRIVATE_NAME +#undef ASM_OUTPUT_DOUBLE +#undef ASM_OUTPUT_FLOAT +#undef ASM_OUTPUT_ALIGN +#undef ASM_OUTPUT_SOURCE_FILENAME +#undef ASM_OUTPUT_SOURCE_LINE +#undef PRINT_OPERAND_ADDRESS +#undef ASM_GENERATE_INTERNAL_LABEL +#undef FUNCTION_PROFILER +#undef ASM_OUTPUT_ADDR_VEC_ELT +#undef ASM_OUTPUT_ADDR_DIFF_ELT +#undef ASM_OUTPUT_INTERNAL_LABEL +#undef ASM_OUTPUT_OPCODE +#undef ASM_OUTPUT_LOCAL +#undef ASM_OUTPUT_LABELREF +#undef ASM_OUTPUT_ASCII + +#define TARGET_VERSION fprintf (stderr, " (68k, SGS/AT&T unixpc syntax)"); + +/* 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)) + 12), \ + sprintf ((OUTPUT), "%s_%%%d", (NAME), (LABELNO))) + +/* The unixpc doesn't know about double's and float's */ + +#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \ +do { union { double d; long l[2]; } tem; \ + tem.d = (VALUE); \ + fprintf(FILE, "\tlong 0x%x,0x%x\n", tem.l[0], tem.l[1]); \ + } while (0) + +#define ASM_OUTPUT_FLOAT(FILE,VALUE) \ +do { union { float f; long l;} tem; \ + tem.f = (VALUE); \ + fprintf (FILE, "\tlong 0x%x\n", tem.l); \ + } while (0) + +#define ASM_OUTPUT_ALIGN(FILE,LOG) \ + if ((LOG) == 1) \ + fprintf (FILE, "\teven\n"); \ + else if ((LOG) != 0) \ + abort (); + +/* The `space' pseudo in the text segment outputs nop insns rather than 0s, + so we must output 0s explicitly in the text segment. */ +#undef ASM_OUTPUT_SKIP +#define ASM_OUTPUT_SKIP(FILE,SIZE) \ + if (in_text_section ()) \ + { \ + int i; \ + for (i = 0; i < (SIZE) - 20; i += 20) \ + fprintf (FILE, "\tbyte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\n"); \ + if (i < (SIZE)) \ + { \ + fprintf (FILE, "\tbyte 0"); \ + i++; \ + for (; i < (SIZE); i++) \ + fprintf (FILE, ",0"); \ + fprintf (FILE, "\n"); \ + } \ + } \ + else \ + fprintf (FILE, "\tspace %u\n", (SIZE)) + +/* The beginnings of sdb support... */ + +#define ASM_OUTPUT_SOURCE_FILENAME(FILE, FILENAME) \ + fprintf (FILE, "\tfile\t\"%s\"\n", FILENAME) + +#define ASM_OUTPUT_SOURCE_LINE(FILE, LINENO) \ + fprintf (FILE, "\tln\t%d\n", \ + (sdb_begin_function_line \ + ? last_linenum - sdb_begin_function_line : 1)) + +/* Yet another null terminated string format. */ + +#define ASM_OUTPUT_ASCII(FILE,PTR,LEN) \ + { register int sp = 0, lp = 0; \ + fprintf (FILE, "\tbyte\t"); \ + loop: \ + if (PTR[sp] > ' ' && ! (PTR[sp] & 0x80) && PTR[sp] != '\\') \ + { lp += 3; \ + fprintf (FILE, "'%c", PTR[sp]); } \ + else \ + { lp += 5; \ + fprintf (FILE, "0x%x", PTR[sp]); } \ + if (++sp < LEN) \ + { if (lp > 60) \ + { lp = 0; \ + fprintf (FILE, "\n%s ", ASCII_DATA_ASM_OP); } \ + else \ + putc (',', FILE); \ + goto loop; } \ + putc ('\n', FILE); } + +/* Note that in the case of the movhi which fetches an element of + an ADDR_DIFF_VEC the offset output is too large by 2. + This is because the 3b1 assembler refuses to subtract 2. + ASM_OUTPUT_CASE_LABEL, below, compensates for this. */ + +#define PRINT_OPERAND_ADDRESS(FILE, ADDR) \ +{ register rtx reg1, reg2, breg, ireg; \ + register rtx addr = ADDR; \ + rtx offset; \ + switch (GET_CODE (addr)) \ + { \ + case REG: \ + fprintf (FILE, "(%s)", reg_names[REGNO (addr)]); \ + break; \ + case PRE_DEC: \ + fprintf (FILE, "-(%s)", reg_names[REGNO (XEXP (addr, 0))]); \ + break; \ + case POST_INC: \ + fprintf (FILE, "(%s)+", reg_names[REGNO (XEXP (addr, 0))]); \ + break; \ + case PLUS: \ + reg1 = 0; reg2 = 0; \ + ireg = 0; breg = 0; \ + offset = 0; \ + if (CONSTANT_ADDRESS_P (XEXP (addr, 0))) \ + { \ + offset = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (CONSTANT_ADDRESS_P (XEXP (addr, 1))) \ + { \ + offset = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + if (GET_CODE (addr) != PLUS) ; \ + else if (GET_CODE (XEXP (addr, 0)) == SIGN_EXTEND) \ + { \ + reg1 = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (GET_CODE (XEXP (addr, 1)) == SIGN_EXTEND) \ + { \ + reg1 = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + else if (GET_CODE (XEXP (addr, 0)) == MULT) \ + { \ + reg1 = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (GET_CODE (XEXP (addr, 1)) == MULT) \ + { \ + reg1 = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + else if (GET_CODE (XEXP (addr, 0)) == REG) \ + { \ + reg1 = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (GET_CODE (XEXP (addr, 1)) == REG) \ + { \ + reg1 = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + if (GET_CODE (addr) == REG || GET_CODE (addr) == MULT \ + || GET_CODE (addr) == SIGN_EXTEND) \ + { if (reg1 == 0) reg1 = addr; else reg2 = addr; addr = 0; } \ +/* for OLD_INDEXING \ + else if (GET_CODE (addr) == PLUS) \ + { \ + if (GET_CODE (XEXP (addr, 0)) == REG) \ + { \ + reg2 = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (GET_CODE (XEXP (addr, 1)) == REG) \ + { \ + reg2 = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + } \ + */ \ + if (offset != 0) { if (addr != 0) abort (); addr = offset; } \ + if ((reg1 && (GET_CODE (reg1) == SIGN_EXTEND \ + || GET_CODE (reg1) == MULT)) \ + || (reg2 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg2)))) \ + { breg = reg2; ireg = reg1; } \ + else if (reg1 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg1))) \ + { breg = reg1; ireg = reg2; } \ + if (ireg != 0 && breg == 0 && GET_CODE (addr) == LABEL_REF) \ + { int scale = 1; \ + if (GET_CODE (ireg) == MULT) \ + { scale = INTVAL (XEXP (ireg, 1)); \ + ireg = XEXP (ireg, 0); } \ + if (GET_CODE (ireg) == SIGN_EXTEND) \ + fprintf (FILE, "LD%%%d(%%pc,%s.w", \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + reg_names[REGNO (XEXP (ireg, 0))]); \ + else \ + fprintf (FILE, "LD%%%d(%%pc,%s.l", \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + reg_names[REGNO (ireg)]); \ + if (scale != 1) fprintf (FILE, ":%d", scale); \ + fprintf (FILE, ")"); \ + break; } \ + if (breg != 0 && ireg == 0 && GET_CODE (addr) == LABEL_REF) \ + { fprintf (FILE, "LD%%%d(%%pc,%s.l", \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + reg_names[REGNO (breg)]); \ + putc (')', FILE); \ + break; } \ + if (ireg != 0 || breg != 0) \ + { int scale = 1; \ + if (breg == 0) \ + abort (); \ + if (addr != 0) \ + output_addr_const (FILE, addr); \ + fprintf (FILE, "(%s", reg_names[REGNO (breg)]); \ + if (ireg != 0) \ + putc (',', FILE); \ + if (ireg != 0 && GET_CODE (ireg) == MULT) \ + { scale = INTVAL (XEXP (ireg, 1)); \ + ireg = XEXP (ireg, 0); } \ + if (ireg != 0 && GET_CODE (ireg) == SIGN_EXTEND) \ + fprintf (FILE, "%s.w", reg_names[REGNO (XEXP (ireg, 0))]); \ + else if (ireg != 0) \ + fprintf (FILE, "%s.l", reg_names[REGNO (ireg)]); \ + if (scale != 1) fprintf (FILE, ":%d", scale); \ + putc (')', FILE); \ + break; \ + } \ + else if (reg1 != 0 && GET_CODE (addr) == LABEL_REF) \ + { fprintf (FILE, "LD%%%d(%%pc,%s.w)", \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + reg_names[REGNO (reg1)]); \ + break; } \ + default: \ + if (GET_CODE (addr) == CONST_INT \ + && INTVAL (addr) < 0x8000 \ + && INTVAL (addr) >= -0x8000) \ + fprintf (FILE, "%d", INTVAL (addr)); \ + else \ + output_addr_const (FILE, addr); \ + }} + +#define ASM_GENERATE_INTERNAL_LABEL(LABEL, PREFIX, NUM) \ + sprintf ((LABEL), "%s%%%d", (PREFIX), (NUM)) + +#define ASM_OUTPUT_INTERNAL_LABEL(FILE,PREFIX,NUM) \ + fprintf (FILE, "%s%%%d:\n", PREFIX, NUM) + +/* Must put address in %a0 , not %d0 . -- LGM, 7/15/88 */ +#define FUNCTION_PROFILER(FILE, LABEL_NO) \ + fprintf (FILE, "\tmov.l &LP%%%d,%%a0\n\tjsr mcount\n", (LABEL_NO)) + +#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \ + fprintf (FILE, "\tlong L%%%d\n", (VALUE)) + +#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, VALUE, REL) \ + fprintf (FILE, "\tshort L%%%d-L%%%d\n", (VALUE), (REL)) + +/* ihnp4!lmayk!lgm says that `short 0' triggers assembler bug; + `short L%nn-L%nn' supposedly works. */ +#define ASM_OUTPUT_CASE_LABEL(FILE,PREFIX,NUM,TABLE) \ + if (! RTX_INTEGRATED_P (TABLE)) \ + fprintf (FILE, "\tswbeg &%d\n%s%%%d:\n", \ + XVECLEN (PATTERN (TABLE), 1), (PREFIX), (NUM)); \ + else \ + fprintf (FILE, "\tswbeg &%d\n%s%%%d:\n\tshort %s%%%d-%s%%%d\n", \ + XVECLEN (PATTERN (TABLE), 1) + 1, (PREFIX), (NUM), \ + (PREFIX), (NUM), (PREFIX), (NUM)) + +/* At end of a switch table, define LD%n iff the symbol LI%n was defined. */ +#define ASM_OUTPUT_CASE_END(FILE,NUM,TABLE) \ + if (RTX_INTEGRATED_P (TABLE)) \ + fprintf (FILE, "\tset LD%%%d,L%%%d-LI%%%d\n", (NUM), (NUM), (NUM)) + +#define ASM_OUTPUT_OPCODE(FILE, PTR) \ +{ if ((PTR)[0] == 'j' && (PTR)[1] == 'b') \ + { ++(PTR); \ + while (*(PTR) != ' ') \ + { putc (*(PTR), (FILE)); ++(PTR); } \ + fprintf ((FILE), ".w"); } \ + else if ((PTR)[0] == 'f') \ + { \ + if (!strncmp ((PTR), "fmove", 5)) \ + { fprintf ((FILE), "fmov"); (PTR) += 5; } \ + else if (!strncmp ((PTR), "ftst", 4)) \ + { fprintf ((FILE), "ftest"); (PTR) += 4; } \ + } \ +/* MOVE, MOVEA, MOVEQ, MOVEC ==> MOV */ \ + else if ((PTR)[0] == 'm' && (PTR)[1] == 'o' \ + && (PTR)[2] == 'v' && (PTR)[3] == 'e') \ + { fprintf ((FILE), "mov"); (PTR) += 4; \ + if ((PTR)[0] == 'q' || (PTR)[0] == 'a' || \ + (PTR)[0] == 'c') (PTR)++; } \ +/* SUB, SUBQ, SUBA, SUBI ==> SUB */ \ + else if ((PTR)[0] == 's' && (PTR)[1] == 'u' \ + && (PTR)[2] == 'b') \ + { fprintf ((FILE), "sub"); (PTR) += 3; \ + if ((PTR)[0] == 'q' || (PTR)[0] == 'i' || \ + (PTR)[0] == 'a') (PTR)++; } \ +/* CMP, CMPA, CMPI, CMPM ==> CMP */ \ + else if ((PTR)[0] == 'c' && (PTR)[1] == 'm' \ + && (PTR)[2] == 'p') \ + { fprintf ((FILE), "cmp"); (PTR) += 3; \ + if ((PTR)[0] == 'a' || (PTR)[0] == 'i' || \ + (PTR)[0] == 'm') (PTR)++; } \ +} + +#define ASM_OUTPUT_LOCAL(FILE, NAME, SIZE, ROUNDED) \ +( fputs ("\tlcomm ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%u\n", (ROUNDED))) + +#define ASM_OUTPUT_LABELREF(FILE,NAME) \ + fprintf (FILE, "%s", NAME) + +/* Override usual definitions of SDB output macros. + These definitions differ only in the absence of the period + at the beginning of the name of the directive + and in the use of `~' as the symbol for the current location. */ + +#define PUT_SDB_SCL(a) fprintf(asm_out_file, "\tscl\t%d;", (a)) +#define PUT_SDB_INT_VAL(a) fprintf (asm_out_file, "\tval\t%d;", (a)) +#define PUT_SDB_VAL(a) \ +( fputs ("\tval\t", asm_out_file), \ + output_addr_const (asm_out_file, (a)), \ + fputc (';', asm_out_file)) + +#define PUT_SDB_DEF(a) \ +do { fprintf (asm_out_file, "\tdef\t"); \ + ASM_OUTPUT_LABELREF (asm_out_file, a); \ + fprintf (asm_out_file, ";"); } while (0) + +#define PUT_SDB_PLAIN_DEF(a) fprintf(asm_out_file,"\tdef\t~%s;",a) +#define PUT_SDB_ENDEF fputs("\tendef\n", asm_out_file) +#define PUT_SDB_TYPE(a) fprintf(asm_out_file, "\ttype\t0%o;", a) +#define PUT_SDB_SIZE(a) fprintf(asm_out_file, "\tsize\t%d;", a) +#define PUT_SDB_START_DIM fprintf(asm_out_file, "\tdim\t") + +#define PUT_SDB_TAG(a) \ +do { fprintf (asm_out_file, "\ttag\t"); \ + ASM_OUTPUT_LABELREF (asm_out_file, a); \ + fprintf (asm_out_file, ";"); } while (0) + +#define PUT_SDB_BLOCK_START(LINE) \ + fprintf (asm_out_file, \ + "\tdef\t~bb;\tval\t~;\tscl\t100;\tline\t%d;\tendef\n", \ + (LINE)) + +#define PUT_SDB_BLOCK_END(LINE) \ + fprintf (asm_out_file, \ + "\tdef\t~eb;\tval\t~;\tscl\t100;\tline\t%d;\tendef\n", \ + (LINE)) + +#define PUT_SDB_FUNCTION_START(LINE) \ + fprintf (asm_out_file, \ + "\tdef\t~bf;\tval\t~;\tscl\t101;\tline\t%d;\tendef\n", \ + (LINE)) + +#define PUT_SDB_FUNCTION_END(LINE) \ + fprintf (asm_out_file, \ + "\tdef\t~ef;\tval\t~;\tscl\t101;\tline\t%d;\tendef\n", \ + (LINE)) + +#define PUT_SDB_EPILOGUE_END(NAME) \ + fprintf (asm_out_file, \ + "\tdef\t%s;\tval\t~;\tscl\t-1;\tendef\n", \ + (NAME)) + +#define SDB_GENERATE_FAKE(BUFFER, NUMBER) \ + sprintf ((BUFFER), "~%dfake", (NUMBER)); + +/* Define subroutines to call to handle multiply, divide, and remainder. + Use the subroutines that the 3b1's library provides. + The `*' prevents an underscore from being prepended by the compiler. */ + +#define DIVSI3_LIBCALL "*ldiv" +#define UDIVSI3_LIBCALL "*uldiv" +#define MODSI3_LIBCALL "*lrem" +#define UMODSI3_LIBCALL "*ulrem" +#define MULSI3_LIBCALL "*lmul" +#define UMULSI3_LIBCALL "*ulmul" diff --git a/gcc-1.40/config/tm-3b1g.h b/gcc-1.40/config/tm-3b1g.h new file mode 100644 index 0000000..783613e --- /dev/null +++ b/gcc-1.40/config/tm-3b1g.h @@ -0,0 +1,63 @@ +/* Definitions of target machine for GNU compiler, for a 3b1 using GAS. + Copyright (C) 1987, 1988 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 1, 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 "tm-m68k.h" + +/* See tm-m68k.h. 0 means 68000 with no 68881. */ +#define TARGET_DEFAULT 0 + +/* Define __HAVE_68881 in preprocessor only if -m68881 is specified. + This will control the use of inline 68881 insns in certain macros. + Also inform the program which CPU this is for. */ +#define CPP_SPEC "%{m68881:-D__HAVE_68881__} \ +%{!ansi:%{m68020:-Dmc68020}%{mc68020:-Dmc68020}%{!mc68020:%{!m68020:-Dmc68010}}}" + +/* -m68020 requires special flags to the assembler. */ +#define ASM_SPEC \ + "%{m68020:-mc68020}%{mc68020:-mc68020}%{!mc68020:%{!m68020:-mc68010}}" + +/* Names to predefine in the preprocessor for this target machine. */ +#define CPP_PREDEFINES "-Dmc68000 -Dmc68k -Dunix -Dunixpc" + +/* This is (not really) BSD, so (but) it wants DBX format. */ +#define DBX_DEBUGGING_INFO + +/* Brain damage. */ +#define SCCS_DIRECTIVE + +/* Specify how to pad function arguments. + Value should be `upward', `downward' or `none'. + Same as the default, except no padding for large or variable-size args. */ +#define FUNCTION_ARG_PADDING(mode, size) \ + (((mode) == BLKmode \ + ? (GET_CODE (size) == CONST_INT \ + && INTVAL (size) < PARM_BOUNDARY / BITS_PER_UNIT) \ + : GET_MODE_BITSIZE (mode) < PARM_BOUNDARY) \ + ? downward : none) + +/* Override part of the obstack macros. */ +#define __PTR_TO_INT(P) ((int)(P)) +#define __INT_TO_PTR(P) ((char *)(P)) + +/* Every structure or union's size must be a multiple of 2 bytes. */ +#define STRUCTURE_SIZE_BOUNDARY 16 + +/* Generate calls to memcpy, memcmp and memset. */ +#define TARGET_MEM_FUNCTIONS + diff --git a/gcc-1.40/config/tm-aix386.h b/gcc-1.40/config/tm-aix386.h new file mode 100644 index 0000000..b9fd6ed --- /dev/null +++ b/gcc-1.40/config/tm-aix386.h @@ -0,0 +1,129 @@ +/* Definitions for IBM PS2 running AIX/386. + From: Minh Tran-Le + Copyright (C) 1988 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 1, 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 "tm-i386.h" + +/* Use the ATT assembler syntax. */ + +#include "tm-att386.h" + +/* By default, target has a 80387. */ + +#define TARGET_DEFAULT 1 + +/* Use crt1.o as a startup file and crtn.o as a closing file. */ + +#define STARTFILE_SPEC \ + "%{pg:gcrt1.o%s}%{!pg:%{p:mcrt1.o%s}%{!p:crt1.o%s}}" + +#define LIB_SPEC "%{p:-L/usr/lib/libp}%{pg:-L/usr/lib/libp} -lc crtn.o%s" + +/* Special flags for the linker. I don't know what they do. */ + +#define LINK_SPEC "%{K} %{!K:-K} %{T*} %{z:-lm}" + +/* Specify predefined symbols in preprocessor. */ + +#define CPP_PREDEFINES "-D_I386 -Di386 -DAIX -D_AIX" + +/* special flags for the aix assembler to generate the short form for all + qualifying forward reference */ + +#define ASM_SPEC "-s2" + +/* Allow #sccs in preprocessor. */ + +#define SCCS_DIRECTIVE + +/* Output #ident as a .ident. */ + +#define ASM_OUTPUT_IDENT(FILE, NAME) fprintf (FILE, "\t.ident \"%s\"\n", NAME); + +#undef ASM_FILE_START +#define ASM_FILE_START(FILE) \ + do { \ + char *p = (char *) strrchr (main_input_filename, '/'); \ + if (!p) \ + p = main_input_filename; \ + else p++; \ + fprintf ((FILE), "\t.file\t\"%s\"\n", p); \ + } while (0) + +/* This used to output .noopt if nonoptimizing and run ASM_FILE_START_1 + if optimizing, but that loses with the AIX assembler. */ + +/* This was suggested, but it shouldn't be right for DBX output. -- RMS + #define ASM_OUTPUT_SOURCE_FILENAME(FILE, NAME) */ + +/* We want to output SDB debugging information. */ + +#define SDB_DEBUGGING_INFO + +/* We don't want to output DBX debugging information. Becaus IBM AIX dbx + use COFF format */ + +#undef DBX_DEBUGGING_INFO + +/* Implicit library calls should use memcpy, not bcopy, etc. */ + +#define TARGET_MEM_FUNCTIONS + +/* Writing `int' for a bitfield forces int alignment for the structure. */ + +#define PCC_BITFIELD_TYPE_MATTERS 1 + +/* Don't write a `.optim' pseudo; this assembler + is said to have a bug when .optim is used. */ + +#if 0 +#undef ASM_FILE_START_1 +#define ASM_FILE_START_1(FILE) fprintf (FILE, "\t.noopt\n"); +#endif + +/* Machines that use the AT&T assembler syntax + also return floating point values in an FP register. */ +/* 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. */ + +#define VALUE_REGNO(MODE) \ + (((MODE)==SFmode || (MODE)==DFmode) ? FIRST_FLOAT_REG : 0) + +/* 1 if N is a possible register number for a function value. */ + +#define FUNCTION_VALUE_REGNO_P(N) ((N) == 0 || (N)== FIRST_FLOAT_REG) + +/* 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, "\tleal %sP%d,%%eax\n\tcall mcount\n", LPREFIX, (LABELNO)); + +/* Note that using bss_section here caused errors + in building shared libraries on system V.3. + but AIX 1.2 does not have yet shareable libraries on PS2 */ +#undef ASM_OUTPUT_LOCAL +#define ASM_OUTPUT_LOCAL(FILE, NAME, SIZE, ROUNDED) \ + (bss_section (), \ + ASM_OUTPUT_LABEL ((FILE), (NAME)), \ + fprintf ((FILE), "\t.set .,.+%u\n", (ROUNDED))) diff --git a/gcc-1.40/config/tm-alliant.h b/gcc-1.40/config/tm-alliant.h new file mode 100644 index 0000000..c1926e6 --- /dev/null +++ b/gcc-1.40/config/tm-alliant.h @@ -0,0 +1,1440 @@ +/* Definitions of target machine for GNU compiler. Alliant FX version. + Copyright (C) 1989 Free Software Foundation, Inc. + Adapted from tm-m68k.h by Paul Petersen (petersen@uicsrd.csrd.uiuc.edu) + and Joe Weening (weening@gang-of-four.stanford.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 1, 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 based on tm-m68k.h, simplified by removing support for + the Sun FPA and other things not applicable to the Alliant. Some + remnants of these features remain. */ + +/* Names to predefine in the preprocessor for this target machine. */ + +#define CPP_PREDEFINES "-Dmc68000 -Dalliant -Dunix" + +/* Print subsidiary information on the compiler version in use. */ + +#define TARGET_VERSION fprintf (stderr, " (Alliant)"); + +/* Run-time compilation parameters selecting different hardware + subsets. The Alliant IP is an mc68020. (Older mc68010-based IPs + are no longer supported.) The Alliant CE is 68020-compatible, and + also has floating point, vector and concurrency instructions. + + Although the IP doesn't have floating point, it emulates it in the + operating system. Using this generally is faster than running code + compiled with -msoft-float, because the soft-float code still uses + (simulated) FP registers and ends up emulating several fmove{s,d} + instructions per call. So I don't recommend using soft-float for + any Alliant code. -- JSW +*/ + +extern int target_flags; + +/* Macros used in the machine description to test the flags. */ + +/* Compile for a 68020 (not a 68000 or 68010). */ +#define TARGET_68020 (target_flags & 1) +/* Compile CE insns for floating point (not library calls). */ +#define TARGET_CE (target_flags & 2) +/* Compile using 68020 bitfield insns. */ +#define TARGET_BITFIELD (target_flags & 4) +/* Compile with 16-bit `int'. */ +#define TARGET_SHORT (target_flags & 040) + +/* Default 3 means compile 68020 and CE instructions. We don't use + bitfield instructions because there appears to be a bug in the + implementation of bfins on the CE. */ + +#define TARGET_DEFAULT 3 + +/* Define __HAVE_CE__ in preprocessor according to the -m flags. + This will control the use of inline FP insns in certain macros. + Also inform the program which CPU this is for. */ + +#if TARGET_DEFAULT & 02 + +/* -mce is the default */ +#define CPP_SPEC \ +"%{!msoft-float:-D__HAVE_CE__ }\ +%{m68000:-Dmc68010}%{mc68000:-Dmc68010}%{!mc68000:%{!m68000:-Dmc68020}}" + +#else + +/* -msoft-float is the default */ +#define CPP_SPEC \ +"%{mce:-D__HAVE_CE__ }\ +%{m68000:-Dmc68010}%{mc68000:-Dmc68010}%{!mc68000:%{!m68000:-Dmc68020}}" + +#endif + +/* Every structure or union's size must be a multiple of 2 bytes. */ + +#define STRUCTURE_SIZE_BOUNDARY 16 + +/* This is BSD, so it wants DBX format. */ + +#define DBX_DEBUGGING_INFO + +/* 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 \ + { { "68020", 5}, \ + { "c68020", 5}, \ + { "bitfield", 4}, \ + { "68000", -7}, \ + { "c68000", -7}, \ + { "soft-float", -2}, \ + { "nobitfield", -4}, \ + { "short", 040}, \ + { "noshort", -040}, \ + { "", TARGET_DEFAULT}} + +/* target machine storage layout */ + +/* Define this if most significant bit is lowest numbered + in instructions that operate on numbered bit-fields. + This is true for 68020 insns such as bfins and bfexts. + We make it true always by avoiding using the single-bit insns + except in special cases with constant bit numbers. */ +#define BITS_BIG_ENDIAN + +/* Define this if most significant byte of a word is the lowest numbered. */ +/* That is true on the 68000. */ +#define BYTES_BIG_ENDIAN + +/* Define this if most significant word of a multiword number is numbered. */ +/* For 68000 we can decide arbitrarily + since there are no machine instructions for them. */ +/* #define WORDS_BIG_ENDIAN */ + +/* number of bits in an addressible 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 32 + +/* Width of a word, in units (bytes). */ +#define UNITS_PER_WORD 4 + +/* Width in bits of a pointer. + See also the macro `Pmode' defined below. */ +#define POINTER_SIZE 32 + +/* Allocation boundary (in *bits*) for storing pointers in memory. */ +#define POINTER_BOUNDARY 16 + +/* Allocation boundary (in *bits*) for storing arguments in argument list. */ +#define PARM_BOUNDARY (TARGET_SHORT ? 16 : 32) + +/* Boundary (in *bits*) on which stack pointer should be aligned. */ +#define STACK_BOUNDARY 16 + +/* Allocation boundary (in *bits*) for the code of a function. */ +#define FUNCTION_BOUNDARY 16 + +/* Alignment of field after `int : 0' in a structure. */ +#define EMPTY_FIELD_BOUNDARY 16 + +/* No data type wants to be aligned rounder than this. */ +#define BIGGEST_ALIGNMENT 16 + +/* Define this if move instructions will actually fail to work + when given unaligned data. */ +#define STRICT_ALIGNMENT + +/* Define number of bits in most basic integer type. + (If undefined, default is BITS_PER_WORD). */ + +#define INT_TYPE_SIZE (TARGET_SHORT ? 16 : 32) + +/* 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. + For the Alliant, we give the data registers numbers 0-7, + the address registers numbers 010-017, + and the floating point registers numbers 020-027. */ +#define FIRST_PSEUDO_REGISTER 24 + +/* 1 for registers that have pervasive standard uses + and are not available for the register allocator. + On the Alliant, these are a0 (argument pointer), + a6 (frame pointer) and a7 (stack pointer). */ +#define FIXED_REGISTERS \ + {0, 0, 0, 0, 0, 0, 0, 0, \ + 1, 0, 0, 0, 0, 0, 1, 1, \ + 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. + The Alliant calling sequence allows a function to use any register, + so we include them all here. */ + +#define CALL_USED_REGISTERS \ + {1, 1, 1, 1, 1, 1, 1, 1, \ + 1, 1, 1, 1, 1, 1, 1, 1, \ + 1, 1, 1, 1, 1, 1, 1, 1 } + +/* 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 the Alliant, ordinary registers hold 32 bits worth; + for the FP registers, a single register is always enough for + anything that can be stored in them at all. */ +#define HARD_REGNO_NREGS(REGNO, MODE) \ + ((REGNO) >= 16 ? 1 \ + : ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)) + +/* Value is 1 if hard register REGNO can hold a value of machine-mode MODE. + On the Alliant, the cpu registers can hold any mode but the FP registers + can hold only SFmode or DFmode. */ +#define HARD_REGNO_MODE_OK(REGNO, MODE) \ + ((REGNO) < 16 || (MODE) == SFmode || (MODE) == DFmode) + +/* 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) == SFmode || (MODE1) == DFmode) \ + == ((MODE2) == SFmode || (MODE2) == DFmode)) + +/* Specify the registers used for certain standard purposes. + The values of these macros are register numbers. */ + +/* m68000 pc isn't overloaded on a register. */ +/* #define PC_REGNUM */ + +/* Register to use for pushing function arguments. */ +#define STACK_POINTER_REGNUM 15 + +/* Base register for access to local variables of the function. */ +#define FRAME_POINTER_REGNUM 14 + +/* 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. */ +/* Set for now on Alliant until we find a way to make this work with + their calling sequence. */ +#define FRAME_POINTER_REQUIRED 1 + +/* Base register for access to arguments of the function. */ +#define ARG_POINTER_REGNUM 8 + +/* Register in which static-chain is passed to a function. */ +#define STATIC_CHAIN_REGNUM 8 + +/* Register in which address to store a structure value + is passed to a function. */ +#define STRUCT_VALUE_REGNUM 9 + +/* 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 Alliant has three kinds of registers, so eight classes would be + a complete set. One of them is not needed. */ + +enum reg_class { NO_REGS, FP_REGS, DATA_REGS, DATA_OR_FP_REGS, + ADDR_REGS, GENERAL_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", "FP_REGS", "DATA_REGS", "DATA_OR_FP_REGS", \ + "ADDR_REGS", "GENERAL_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, /* NO_REGS */ \ + 0x00ff0000, /* FP_REGS */ \ + 0x000000ff, /* DATA_REGS */ \ + 0x00ff00ff, /* DATA_OR_FP_REGS */ \ + 0x0000ff00, /* ADDR_REGS */ \ + 0x0000ffff, /* GENERAL_REGS */ \ + 0x00ffffff /* ALL_REGS */ \ +} + +/* 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 regno_reg_class[]; +#define REGNO_REG_CLASS(REGNO) (regno_reg_class[(REGNO)>>3]) + +/* The class value for index registers, and the one for base regs. */ + +#define INDEX_REG_CLASS GENERAL_REGS +#define BASE_REG_CLASS ADDR_REGS + +/* Get reg_class from a letter such as appears in the machine description. */ + +#define REG_CLASS_FROM_LETTER(C) \ + ((C) == 'a' ? ADDR_REGS : \ + ((C) == 'd' ? DATA_REGS : \ + ((C) == 'f' ? FP_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. + + For the 68000, `I' is used for the range 1 to 8 + allowed as immediate shift counts and in addq. + `J' is used for the range of signed numbers that fit in 16 bits. + `K' is for numbers that moveq can't handle. + `L' is for range -8 to -1, range of values that can be added with subq. */ + +#define CONST_OK_FOR_LETTER_P(VALUE, C) \ + ((C) == 'I' ? (VALUE) > 0 && (VALUE) <= 8 : \ + (C) == 'J' ? (VALUE) >= -0x8000 && (VALUE) <= 0x7FFF : \ + (C) == 'K' ? (VALUE) < -0x80 || (VALUE) >= 0x80 : \ + (C) == 'L' ? (VALUE) < 0 && (VALUE) >= -8 : 0) + +#define CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C) 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. + On the 68000 series, use a data reg if possible when the + value is a constant in the range where moveq could be used + and we ensure that QImodes are reloaded into data regs. */ + +#define PREFERRED_RELOAD_CLASS(X,CLASS) \ + ((GET_CODE (X) == CONST_INT \ + && (unsigned) (INTVAL (X) + 0x80) < 0x100 \ + && (CLASS) != ADDR_REGS) \ + ? DATA_REGS \ + : GET_MODE (X) == QImode \ + ? DATA_REGS \ + : (CLASS)) + +/* Return the maximum number of consecutive registers + needed to represent mode MODE in a register of class CLASS. */ +/* On the 68000, this is the size of MODE in words, + except in the FP regs, where a single reg is always enough. */ +#define CLASS_MAX_NREGS(CLASS, MODE) \ + ((CLASS) == FP_REGS ? 1 \ + : ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)) + +/* Stack layout; function entry, exit and calling. */ + +/* 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 + +/* The Alliant uses -fcaller-saves by default. */ +#define DEFAULT_CALLER_SAVES + +/* 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. */ +#define STARTING_FRAME_OFFSET -4 + +/* If we generate an insn to push BYTES bytes, + this says how many the stack pointer really advances by. + On the 68000, sp@- in a byte insn really pushes a word. */ +#define PUSH_ROUNDING(BYTES) (((BYTES) + 1) & ~1) + +/* Offset of first parameter from the argument pointer register value. */ +#define FIRST_PARM_OFFSET(FNDECL) 0 + +/* Value is 1 if returning from a function call automatically + pops the arguments described by the number-of-args field in the call. + 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. + + On the Alliant we define this as 1 and make the calling sequence + (in alliant.md) pop the args. This wouldn't be necessary if we + could add to the pending stack adjustment the size of the argument + descriptors that are pushed after the arguments. */ + +#define RETURN_POPS_ARGS(FUNTYPE) 1 + +/* 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 the Alliant the return value is in FP0 if real, else D0. */ + +#define FUNCTION_VALUE(VALTYPE, FUNC) \ + (TREE_CODE (VALTYPE) == REAL_TYPE \ + ? gen_rtx (REG, TYPE_MODE (VALTYPE), 16) \ + : gen_rtx (REG, TYPE_MODE (VALTYPE), 0)) + +/* Define how to find the value returned by a library function + assuming the value has mode MODE. */ + +/* On the Alliant the return value is in FP0 if real, else D0. The + Alliant library functions for floating-point emulation return their + values both in FP0 and in D0/D1. But since not all gnulib functions + return the results of these directly, we cannot assume that D0/D1 + contain the values we expect on return from a gnulib function. */ + +#define LIBCALL_VALUE(MODE) \ + (((MODE) == DFmode || (MODE) == SFmode) \ + ? gen_rtx (REG, MODE, 16) \ + : gen_rtx (REG, MODE, 0)) + +/* 1 if N is a possible register number for a function value. + On the Alliant, D0 and FP0 are the only registers thus used. + (No need to mention D1 when used as a pair with D0.) */ + +#define FUNCTION_VALUE_REGNO_P(N) (((N) & ~16) == 0) + +/* Define this if PCC uses the nonreentrant convention for returning + structure and union values. */ + +#define PCC_STATIC_STRUCT_RETURN + +/* 1 if N is a possible register number for function argument passing. + On the Alliant, no registers are used in this way. */ + +#define FUNCTION_ARG_REGNO_P(N) 0 + +/* 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 the Alliant, this is a single integer, which is a number of bytes + of arguments scanned so far. */ + +#define CUMULATIVE_ARGS int + +/* 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. + + On the Alliant, the offset starts at 0. */ + +#define INIT_CUMULATIVE_ARGS(CUM,FNTYPE) \ + ((CUM) = 0) + +/* 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.) */ + +#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \ + ((CUM) += ((MODE) != BLKmode \ + ? (GET_MODE_SIZE (MODE) + 3) & ~3 \ + : (int_size_in_bytes (TYPE) + 3) & ~3)) + +/* Define where to put the arguments 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). */ + +/* On the Alliant all args are pushed. */ + +#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) 0 + +/* 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. */ + +#define FUNCTION_ARG_PARTIAL_NREGS(CUM, MODE, TYPE, NAMED) 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. + The Alliant uses caller-saves, so this macro is very simple. */ + +#define FUNCTION_PROLOGUE(FILE, SIZE) \ +{ int fsize = ((SIZE) - STARTING_FRAME_OFFSET + 3) & -4; \ + if (frame_pointer_needed) \ + { \ + if (fsize < 0x8000) \ + fprintf(FILE,"\tlinkw a6,#%d\n", -fsize); \ + else if (TARGET_68020) \ + fprintf(FILE,"\tlinkl a6,#%d\n", -fsize); \ + else \ + fprintf(FILE,"\tlinkw a6,#0\n\tsubl #%d,sp\n", fsize); \ + fprintf(FILE, "\tmovl a0,a6@(-4)\n" ); }} + +/* Output assembler code to FILE to increment profiler label # LABELNO + for profiling a function entry. */ + +#define FUNCTION_PROFILER(FILE, LABELNO) \ + fprintf (FILE, "\tjbsr __mcount_\n") + +/* 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. */ + +#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) \ +{ if (frame_pointer_needed) \ + fprintf (FILE, "\tunlk a6\n"); \ + fprintf (FILE, "\trts\n"); } + +/* If the memory address ADDR is relative to the frame pointer, + correct it to be relative to the stack pointer instead. + This is for when we don't use a frame pointer. + ADDR should be a variable name. */ + +#define FIX_FRAME_POINTER_ADDRESS(ADDR,DEPTH) \ +{ int offset = -1; \ + rtx regs = stack_pointer_rtx; \ + if (ADDR == frame_pointer_rtx) \ + offset = 0; \ + else if (GET_CODE (ADDR) == PLUS && XEXP (ADDR, 0) == frame_pointer_rtx \ + && GET_CODE (XEXP (ADDR, 1)) == CONST_INT) \ + offset = INTVAL (XEXP (ADDR, 1)); \ + else if (GET_CODE (ADDR) == PLUS && XEXP (ADDR, 0) == frame_pointer_rtx) \ + { rtx other_reg = XEXP (ADDR, 1); \ + offset = 0; \ + regs = gen_rtx (PLUS, Pmode, stack_pointer_rtx, other_reg); } \ + else if (GET_CODE (ADDR) == PLUS && XEXP (ADDR, 1) == frame_pointer_rtx) \ + { rtx other_reg = XEXP (ADDR, 0); \ + offset = 0; \ + regs = gen_rtx (PLUS, Pmode, stack_pointer_rtx, other_reg); } \ + else if (GET_CODE (ADDR) == PLUS \ + && GET_CODE (XEXP (ADDR, 0)) == PLUS \ + && XEXP (XEXP (ADDR, 0), 0) == frame_pointer_rtx \ + && GET_CODE (XEXP (ADDR, 1)) == CONST_INT) \ + { rtx other_reg = XEXP (XEXP (ADDR, 0), 1); \ + offset = INTVAL (XEXP (ADDR, 1)); \ + regs = gen_rtx (PLUS, Pmode, stack_pointer_rtx, other_reg); } \ + else if (GET_CODE (ADDR) == PLUS \ + && GET_CODE (XEXP (ADDR, 0)) == PLUS \ + && XEXP (XEXP (ADDR, 0), 1) == frame_pointer_rtx \ + && GET_CODE (XEXP (ADDR, 1)) == CONST_INT) \ + { rtx other_reg = XEXP (XEXP (ADDR, 0), 0); \ + offset = INTVAL (XEXP (ADDR, 1)); \ + regs = gen_rtx (PLUS, Pmode, stack_pointer_rtx, other_reg); } \ + if (offset >= 0) \ + { int regno; \ + extern char call_used_regs[]; \ + for (regno = 16; regno < FIRST_PSEUDO_REGISTER; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + offset += 12; \ + for (regno = 0; regno < 16; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + offset += 4; \ + offset -= 4; \ + ADDR = plus_constant (regs, offset + (DEPTH)); } } \ + +/* 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) < 16 || (unsigned) reg_renumber[REGNO] < 16) +#define REGNO_OK_FOR_BASE_P(REGNO) \ +(((REGNO) ^ 010) < 8 || (unsigned) (reg_renumber[REGNO] ^ 010) < 8) +#define REGNO_OK_FOR_DATA_P(REGNO) \ +((REGNO) < 8 || (unsigned) reg_renumber[REGNO] < 8) +#define REGNO_OK_FOR_FP_P(REGNO) \ +(((REGNO) ^ 020) < 8 || (unsigned) (reg_renumber[REGNO] ^ 020) < 8) + +/* 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 68000, and may be used only + in code for printing assembler insns and in conditions for + define_optimization. */ + +/* 1 if X is a data register. */ + +#define DATA_REG_P(X) (REG_P (X) && REGNO_OK_FOR_DATA_P (REGNO (X))) + +/* 1 if X is an fp register. */ + +#define FP_REG_P(X) (REG_P (X) && REGNO_OK_FOR_FP_P (REGNO (X))) + +/* 1 if X is an address register */ + +#define ADDRESS_REG_P(X) (REG_P (X) && REGNO_OK_FOR_BASE_P (REGNO (X))) + +/* 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. */ + +#define CONSTANT_ADDRESS_P(X) CONSTANT_P (X) + +/* Nonzero if the constant value X is a legitimate general operand. + It is given that X satisfies CONSTANT_P or is a CONST_DOUBLE. */ + +/* Alliant FP instructions don't take immediate operands, so this + forces them into memory. */ +#define LEGITIMATE_CONSTANT_P(X) (GET_CODE (X) != CONST_DOUBLE) + +/* 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. */ + +#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) ((REGNO (X) ^ 020) >= 8) +/* 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) ((REGNO (X) & ~027) != 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)) + +#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. + + The other macros defined here are used only in GO_IF_LEGITIMATE_ADDRESS. */ + +#define INDIRECTABLE_1_ADDRESS_P(X) \ + (CONSTANT_ADDRESS_P (X) \ + || (GET_CODE (X) == REG && REG_OK_FOR_BASE_P (X)) \ + || ((GET_CODE (X) == PRE_DEC || GET_CODE (X) == POST_INC) \ + && REG_P (XEXP (X, 0)) \ + && REG_OK_FOR_BASE_P (XEXP (X, 0))) \ + || (GET_CODE (X) == PLUS \ + && REG_P (XEXP (X, 0)) && REG_OK_FOR_BASE_P (XEXP (X, 0)) \ + && GET_CODE (XEXP (X, 1)) == CONST_INT \ + && ((unsigned) INTVAL (XEXP (X, 1)) + 0x8000) < 0x10000)) + +#define GO_IF_NONINDEXED_ADDRESS(X, ADDR) \ +{ if (INDIRECTABLE_1_ADDRESS_P (X)) goto ADDR; } + +#define GO_IF_INDEXABLE_BASE(X, ADDR) \ +{ if (GET_CODE (X) == LABEL_REF) goto ADDR; \ + if (GET_CODE (X) == REG && REG_OK_FOR_BASE_P (X)) goto ADDR; } + +#define GO_IF_INDEXING(X, ADDR) \ +{ if (GET_CODE (X) == PLUS && LEGITIMATE_INDEX_P (XEXP (X, 0))) \ + { GO_IF_INDEXABLE_BASE (XEXP (X, 1), ADDR); } \ + if (GET_CODE (X) == PLUS && LEGITIMATE_INDEX_P (XEXP (X, 1))) \ + { GO_IF_INDEXABLE_BASE (XEXP (X, 0), ADDR); } } + +#define GO_IF_INDEXED_ADDRESS(X, ADDR) \ +{ GO_IF_INDEXING (X, ADDR); \ + if (GET_CODE (X) == PLUS) \ + { if (GET_CODE (XEXP (X, 1)) == CONST_INT \ + && (unsigned) INTVAL (XEXP (X, 1)) + 0x80 < 0x100) \ + { rtx go_temp = XEXP (X, 0); GO_IF_INDEXING (go_temp, ADDR); } \ + if (GET_CODE (XEXP (X, 0)) == CONST_INT \ + && (unsigned) INTVAL (XEXP (X, 0)) + 0x80 < 0x100) \ + { rtx go_temp = XEXP (X, 1); GO_IF_INDEXING (go_temp, ADDR); } } } + +#define LEGITIMATE_INDEX_REG_P(X) \ + ((GET_CODE (X) == REG && REG_OK_FOR_INDEX_P (X)) \ + || (GET_CODE (X) == SIGN_EXTEND \ + && GET_CODE (XEXP (X, 0)) == REG \ + && GET_MODE (XEXP (X, 0)) == HImode \ + && REG_OK_FOR_INDEX_P (XEXP (X, 0)))) + +#define LEGITIMATE_INDEX_P(X) \ + (LEGITIMATE_INDEX_REG_P (X) \ + || (TARGET_68020 && GET_CODE (X) == MULT \ + && LEGITIMATE_INDEX_REG_P (XEXP (X, 0)) \ + && GET_CODE (XEXP (X, 1)) == CONST_INT \ + && (INTVAL (XEXP (X, 1)) == 2 \ + || INTVAL (XEXP (X, 1)) == 4 \ + || INTVAL (XEXP (X, 1)) == 8))) + +#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \ +{ GO_IF_NONINDEXED_ADDRESS (X, ADDR); \ + GO_IF_INDEXED_ADDRESS (X, 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. + + For the 68000, we handle X+REG by loading X into a register R and + using R+REG. R will go in an address reg and indexing will be used. + However, if REG is a broken-out memory address or multiplication, + nothing needs to be done because REG can certainly go in an address reg. */ + +#define LEGITIMIZE_ADDRESS(X,OLDX,MODE,WIN) \ +{ register int ch = (X) != (OLDX); \ + if (GET_CODE (X) == PLUS) \ + { if (GET_CODE (XEXP (X, 0)) == MULT) \ + ch = 1, XEXP (X, 0) = force_operand (XEXP (X, 0), 0); \ + if (GET_CODE (XEXP (X, 1)) == MULT) \ + ch = 1, XEXP (X, 1) = force_operand (XEXP (X, 1), 0); \ + if (ch && GET_CODE (XEXP (X, 1)) == REG \ + && GET_CODE (XEXP (X, 0)) == REG) \ + return X; \ + if (ch) { GO_IF_LEGITIMATE_ADDRESS (MODE, X, WIN); } \ + if (GET_CODE (XEXP (X, 0)) == REG \ + || (GET_CODE (XEXP (X, 0)) == SIGN_EXTEND \ + && GET_CODE (XEXP (XEXP (X, 0), 0)) == REG \ + && GET_MODE (XEXP (XEXP (X, 0), 0)) == HImode)) \ + { register rtx temp = gen_reg_rtx (Pmode); \ + register rtx val = force_operand (XEXP (X, 1), 0); \ + emit_move_insn (temp, val); \ + XEXP (X, 1) = temp; \ + return X; } \ + else if (GET_CODE (XEXP (X, 1)) == REG \ + || (GET_CODE (XEXP (X, 1)) == SIGN_EXTEND \ + && GET_CODE (XEXP (XEXP (X, 1), 0)) == REG \ + && GET_MODE (XEXP (XEXP (X, 1), 0)) == HImode)) \ + { register rtx temp = gen_reg_rtx (Pmode); \ + register rtx val = force_operand (XEXP (X, 0), 0); \ + emit_move_insn (temp, val); \ + XEXP (X, 0) = temp; \ + return X; }}} + +/* Go to LABEL if ADDR (a legitimate address expression) + has an effect that depends on the machine mode it is used for. + On the 68000, only predecrement and postincrement address depend thus + (the amount of decrement or increment being the length of the operand). */ + +#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR,LABEL) \ + if (GET_CODE (ADDR) == POST_INC || GET_CODE (ADDR) == PRE_DEC) goto LABEL + +/* Specify the machine mode that this machine uses + for the index in the tablejump instruction. */ +#define CASE_VECTOR_MODE HImode + +/* 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 + +/* 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 4 + +/* Define this if zero-extension is slow (more than one real instruction). */ +#define SLOW_ZERO_EXTEND + +/* Nonzero if access to memory by bytes is slow and undesirable. */ +#define SLOW_BYTE_ACCESS 0 + +/* Define if shifts truncate the shift count + which implies one can omit a sign-extension or zero-extension + of a shift count. */ +#define SHIFT_COUNT_TRUNCATED + +/* 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 + +/* 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 + +/* 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 SImode + +/* 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 QImode + +/* 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) \ + case CONST_INT: \ + /* Constant zero is super cheap due to clr instruction. */ \ + if (RTX == const0_rtx) return 0; \ + if ((unsigned) INTVAL (RTX) < 077) return 1; \ + case CONST: \ + case LABEL_REF: \ + case SYMBOL_REF: \ + return 3; \ + case CONST_DOUBLE: \ + return 5; + +/* Check a `double' value for validity for a particular machine mode. + This is defined to avoid crashes outputting certain constants. */ + +#define CHECK_FLOAT_VALUE(mode, d) \ + if ((mode) == SFmode) \ + { \ + if ((d) > 3.4028234663852890e+38) \ + { warning ("magnitude of value too large for `float'"); \ + (d) = 3.4028234663852890e+38; } \ + else if ((d) < -3.4028234663852890e+38) \ + { warning ("magnitude of value too large for `float'"); \ + (d) = -3.4028234663852890e+38; } \ + else if (((d) > 0) && ((d) < 1.1754943508222873e-38)) \ + (d) = 0.0; \ + else if (((d) < 0) && ((d) > -1.1754943508222873e-38)) \ + (d) = 0.0; \ + } + +/* Tell final.c how to eliminate redundant test instructions. */ + +/* Here we define machine-dependent flags and fields in cc_status + (see `conditions.h'). */ + +/* On the Alliant, floating-point instructions do not modify the + ordinary CC register. Only fcmp and ftest instructions modify the + floating-point CC register. We should actually keep track of what + both kinds of CC registers contain, but for now we only consider + the most recent instruction that has set either register. */ + +/* Set if the cc value came from a floating point test, so a floating + point conditional branch must be output. */ +#define CC_IN_FP 04000 + +/* Store in cc_status the expressions + that the condition codes will describe + after execution of an instruction whose pattern is EXP. + Do not alter them if the instruction would not alter the cc's. */ + +/* On the 68000, all the insns to store in an address register + fail to set the cc's. However, in some cases these instructions + can make it possibly invalid to use the saved cc's. In those + cases we clear out some or all of the saved cc's so they won't be used. */ + +#define NOTICE_UPDATE_CC(EXP, INSN) \ +{ \ + if (GET_CODE (EXP) == SET) \ + { if (ADDRESS_REG_P (SET_DEST (EXP)) || FP_REG_P (SET_DEST (EXP))) \ + { 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; } \ + else if (SET_DEST (EXP) != cc0_rtx \ + && (FP_REG_P (SET_SRC (EXP)) \ + || GET_CODE (SET_SRC (EXP)) == FIX \ + || GET_CODE (SET_SRC (EXP)) == FLOAT_TRUNCATE \ + || GET_CODE (SET_SRC (EXP)) == FLOAT_EXTEND)) \ + { CC_STATUS_INIT; } \ + /* A pair of move insns doesn't produce a useful overall cc. */ \ + else if (!FP_REG_P (SET_DEST (EXP)) \ + && !FP_REG_P (SET_SRC (EXP)) \ + && GET_MODE_SIZE (GET_MODE (SET_SRC (EXP))) > 4 \ + && (GET_CODE (SET_SRC (EXP)) == REG \ + || GET_CODE (SET_SRC (EXP)) == MEM \ + || GET_CODE (SET_SRC (EXP)) == CONST_DOUBLE))\ + { CC_STATUS_INIT; } \ + else if (GET_CODE (SET_SRC (EXP)) == CALL) \ + { CC_STATUS_INIT; } \ + else if (XEXP (EXP, 0) != pc_rtx) \ + { cc_status.flags = 0; \ + cc_status.value1 = XEXP (EXP, 0); \ + cc_status.value2 = XEXP (EXP, 1); } } \ + else if (GET_CODE (EXP) == PARALLEL \ + && GET_CODE (XVECEXP (EXP, 0, 0)) == SET) \ + { \ + if (ADDRESS_REG_P (XEXP (XVECEXP (EXP, 0, 0), 0))) \ + CC_STATUS_INIT; \ + else if (XEXP (XVECEXP (EXP, 0, 0), 0) != pc_rtx) \ + { cc_status.flags = 0; \ + cc_status.value1 = XEXP (XVECEXP (EXP, 0, 0), 0); \ + cc_status.value2 = XEXP (XVECEXP (EXP, 0, 0), 1); } } \ + else CC_STATUS_INIT; \ + if (cc_status.value2 != 0 \ + && ADDRESS_REG_P (cc_status.value2) \ + && GET_MODE (cc_status.value2) == QImode) \ + CC_STATUS_INIT; \ + if (cc_status.value2 != 0) \ + switch (GET_CODE (cc_status.value2)) \ + { case PLUS: case MINUS: case MULT: case UMULT: \ + case DIV: case UDIV: case MOD: case UMOD: case NEG: \ + case ASHIFT: case LSHIFT: case ASHIFTRT: case LSHIFTRT: \ + case ROTATE: case ROTATERT: \ + if (GET_MODE (cc_status.value2) != VOIDmode) \ + cc_status.flags |= CC_NO_OVERFLOW; \ + break; \ + case ZERO_EXTEND: \ + /* (SET r1 (ZERO_EXTEND r2)) on this machine + ends with a move insn moving r2 in r2's mode. + Thus, the cc's are set for r2. + This can set N bit spuriously. */ \ + cc_status.flags |= CC_NOT_NEGATIVE; } \ + if (cc_status.value1 && GET_CODE (cc_status.value1) == REG \ + && cc_status.value2 \ + && reg_overlap_mentioned_p (cc_status.value1, cc_status.value2)) \ + cc_status.value2 = 0; \ + if ((cc_status.value1 && FP_REG_P (cc_status.value1)) \ + || (cc_status.value2 && FP_REG_P (cc_status.value2))) \ + cc_status.flags = CC_IN_FP; } + +#define OUTPUT_JUMP(NORMAL, FLOAT, NO_OV) \ +{ if (cc_prev_status.flags & CC_IN_FP) \ + return FLOAT; \ + if (cc_prev_status.flags & CC_NO_OVERFLOW) \ + return NO_OV; \ + return NORMAL; } + +/* Control the assembler format that we output. */ + +/* Output at beginning of assembler file. */ + +#define ASM_FILE_START(FILE) \ + fprintf (FILE, "#NO_APP\n"); + +/* Output to assembler file text saying following lines + may contain character constants, extra white space, comments, etc. */ + +#define ASM_APP_ON "#APP\n" + +/* Output to assembler file text saying following lines + no longer contain unusual constructs. */ + +#define ASM_APP_OFF "#NO_APP\n" + +/* Output before read-only data. */ + +#define TEXT_SECTION_ASM_OP "\t.text" + +/* Output before writable data. */ + +#define DATA_SECTION_ASM_OP "\t.data" + +/* How to refer to registers in assembler output. + This sequence is indexed by compiler's hard-register-number (see above). */ + +#define REGISTER_NAMES \ +{"d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", \ + "a0", "a1", "a2", "a3", "a4", "a5", "a6", "sp", \ + "fp0", "fp1", "fp2", "fp3", "fp4", "fp5", "fp6", "fp7" } + +/* How to renumber registers for dbx and gdb. + On the Sun-3, the floating point registers have numbers + 18 to 25, not 16 to 23 as they do in the compiler. */ +/* (On the Alliant, dbx isn't working yet at all. */ + +#define DBX_REGISTER_NUMBER(REGNO) ((REGNO) < 16 ? (REGNO) : (REGNO) + 2) + +/* 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.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. */ + +#define ASM_OUTPUT_LABELREF(FILE,NAME) \ + fprintf (FILE, "_%s", NAME) + +/* 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) \ + 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%d", PREFIX, NUM) + +/* This is how to output an assembler line defining a `double' constant. */ + +#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \ +do { union { double d; long v[2];} tem; \ + tem.d = (VALUE); \ + fprintf (FILE, "\t.long 0x%x,0x%x\n", tem.v[0], tem.v[1]); \ + } while (0) + +/* This is how to output an assembler line defining a `float' constant. */ + +#define ASM_OUTPUT_FLOAT(FILE,VALUE) \ +do { union { float f; long l;} tem; \ + tem.f = (VALUE); \ + fprintf (FILE, "\t.long 0x%x\n", tem.l); \ + } while (0) + +/* This is how to output an assembler line defining an `int' constant. */ + +#define ASM_OUTPUT_INT(FILE,VALUE) \ +( fprintf (FILE, "\t.long "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +/* Likewise for `char' and `short' constants. */ + +#define ASM_OUTPUT_SHORT(FILE,VALUE) \ +( fprintf (FILE, "\t.word "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +#define ASM_OUTPUT_CHAR(FILE,VALUE) \ +( fprintf (FILE, "\t.byte "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +#define ASM_OUTPUT_ASCII(FILE,PTR,SIZE) \ +{ int i; unsigned char *pp = (unsigned char *) PTR; \ + fprintf(FILE, "\t.byte %d", (unsigned int)*pp++); \ + for (i = 1; i < SIZE; ++i, ++pp) { \ + if ((i % 8) == 0) \ + fprintf(FILE, "\n\t.byte %d", (unsigned int) *pp); \ + else \ + fprintf(FILE, ",%d", (unsigned int) *pp); } \ + 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.byte 0x%x\n", (VALUE)) + +/* This is how to output an insn to push a register on the stack. + It need not be very fast code. */ + +#define ASM_OUTPUT_REG_PUSH(FILE,REGNO) \ + fprintf (FILE, "\tmovl %s,sp@-\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, "\tmovl sp@+,%s\n", reg_names[REGNO]) + +/* 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.) */ + +#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \ + fprintf (FILE, "\t.long L%d\n", VALUE) + +/* This is how to output an element of a case-vector that is relative. */ + +#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, VALUE, REL) \ + fprintf (FILE, "\t.word L%d-L%d\n", VALUE, REL) + +/* 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) == 1) \ + fprintf (FILE, "\t.even\n"); \ + else if ((LOG) != 0) \ + fprintf (FILE, "\t.align %dn", (LOG)); + +#define ASM_OUTPUT_SKIP(FILE,SIZE) \ + fprintf (FILE, "\t. = . + %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.comm ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%u\n", (ROUNDED))) + +/* This says how to output an assembler line + to define a local common symbol. */ + +#define ASM_OUTPUT_LOCAL(FILE, NAME, SIZE, ROUNDED) \ +( fputs ("\t.lcomm ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%u\n", (ROUNDED))) + +/* 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 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 + +/* 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. + + On the Alliant, we use several CODE characters: + '.' for dot needed in Motorola-style opcode names. + '-' for an operand pushing on the stack: + sp@-, -(sp) or -(%sp) depending on the style of syntax. + '+' for an operand pushing on the stack: + sp@+, (sp)+ or (%sp)+ depending on the style of syntax. + '@' for a reference to the top word on the stack: + sp@, (sp) or (%sp) depending on the style of syntax. + '#' for an immediate operand prefix (# in MIT and Motorola syntax + but & in SGS syntax). + '!' for the cc register (used in an `and to cc' insn). + + 'b' for byte insn (no effect, on the Sun; this is for the ISI). + 'd' to force memory addressing to be absolute, not relative. + 'f' for float insn (print a CONST_DOUBLE as a float rather than in hex) + 'x' for float insn (print a CONST_DOUBLE as a float rather than in hex), + or print pair of registers as rx:ry. */ + +#define PRINT_OPERAND_PUNCT_VALID_P(CODE) \ + ((CODE) == '.' || (CODE) == '#' || (CODE) == '-' \ + || (CODE) == '+' || (CODE) == '@' || (CODE) == '!') + +#define PRINT_OPERAND(FILE, X, CODE) \ +{ int i; \ + if (CODE == '.') ; \ + else if (CODE == '#') fprintf (FILE, "#"); \ + else if (CODE == '-') fprintf (FILE, "sp@-"); \ + else if (CODE == '+') fprintf (FILE, "sp@+"); \ + else if (CODE == '@') fprintf (FILE, "sp@"); \ + else if (CODE == '!') fprintf (FILE, "cc"); \ + else if ((X) == 0 ) ; \ + else if (GET_CODE (X) == REG) \ + { if (REGNO (X) < 16 && (CODE == 'y' || CODE == 'x') && GET_MODE (X) == DFmode) \ + fprintf (FILE, "%s,%s", reg_names[REGNO (X)], reg_names[REGNO (X)+1]); \ + else \ + fprintf (FILE, "%s", reg_names[REGNO (X)]); \ + } \ + else if (GET_CODE (X) == MEM) \ + { \ + output_address (XEXP (X, 0)); \ + if (CODE == 'd' && ! TARGET_68020 \ + && CONSTANT_ADDRESS_P (XEXP (X, 0)) \ + && !(GET_CODE (XEXP (X, 0)) == CONST_INT \ + && INTVAL (XEXP (X, 0)) < 0x8000 \ + && INTVAL (XEXP (X, 0)) >= -0x8000)) \ + fprintf (FILE, ":l"); \ + } \ + else if (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) == SFmode) \ + { union { double d; int i[2]; } u; \ + union { float f; int i; } u1; \ + u.i[0] = CONST_DOUBLE_LOW (X); u.i[1] = CONST_DOUBLE_HIGH (X); \ + u1.f = u.d; \ + if (CODE == 'f') \ + fprintf (FILE, "#0r%.9g", u1.f); \ + else \ + fprintf (FILE, "#0x%x", u1.i); } \ + else if (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) != DImode) \ + { union { double d; int i[2]; } u; \ + u.i[0] = CONST_DOUBLE_LOW (X); u.i[1] = CONST_DOUBLE_HIGH (X); \ + fprintf (FILE, "#0r%.20g", u.d); } \ + else { putc ('#', FILE); output_addr_const (FILE, X); }} + +/* Note that this contains a kludge that knows that the only reason + we have an address (plus (label_ref...) (reg...)) + is in the insn before a tablejump, and we know that m68k.md + generates a label LInnn: on such an insn. */ +#define PRINT_OPERAND_ADDRESS(FILE, ADDR) \ +{ register rtx reg1, reg2, breg, ireg; \ + register rtx addr = ADDR; \ + static char *sz = ".BW.L...D"; \ + rtx offset; \ + switch (GET_CODE (addr)) \ + { \ + case REG: \ + fprintf (FILE, "%s@", reg_names[REGNO (addr)]); \ + break; \ + case PRE_DEC: \ + fprintf (FILE, "%s@-", reg_names[REGNO (XEXP (addr, 0))]); \ + break; \ + case POST_INC: \ + fprintf (FILE, "%s@+", reg_names[REGNO (XEXP (addr, 0))]); \ + break; \ + case PLUS: \ + reg1 = 0; reg2 = 0; \ + ireg = 0; breg = 0; \ + offset = 0; \ + if (CONSTANT_ADDRESS_P (XEXP (addr, 0))) \ + { \ + offset = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (CONSTANT_ADDRESS_P (XEXP (addr, 1))) \ + { \ + offset = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + if (GET_CODE (addr) != PLUS) ; \ + else if (GET_CODE (XEXP (addr, 0)) == SIGN_EXTEND) \ + { \ + reg1 = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (GET_CODE (XEXP (addr, 1)) == SIGN_EXTEND) \ + { \ + reg1 = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + else if (GET_CODE (XEXP (addr, 0)) == MULT) \ + { \ + reg1 = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (GET_CODE (XEXP (addr, 1)) == MULT) \ + { \ + reg1 = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + else if (GET_CODE (XEXP (addr, 0)) == REG) \ + { \ + reg1 = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (GET_CODE (XEXP (addr, 1)) == REG) \ + { \ + reg1 = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + if (GET_CODE (addr) == REG || GET_CODE (addr) == MULT \ + || GET_CODE (addr) == SIGN_EXTEND) \ + { if (reg1 == 0) reg1 = addr; else reg2 = addr; addr = 0; } \ +/* for OLD_INDEXING \ + else if (GET_CODE (addr) == PLUS) \ + { \ + if (GET_CODE (XEXP (addr, 0)) == REG) \ + { \ + reg2 = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (GET_CODE (XEXP (addr, 1)) == REG) \ + { \ + reg2 = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + } \ + */ \ + if (offset != 0) { if (addr != 0) abort (); addr = offset; } \ + if ((reg1 && (GET_CODE (reg1) == SIGN_EXTEND \ + || GET_CODE (reg1) == MULT)) \ + || (reg2 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg2)))) \ + { breg = reg2; ireg = reg1; } \ + else if (reg1 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg1))) \ + { breg = reg1; ireg = reg2; } \ + if (ireg != 0 && breg == 0 && GET_CODE (addr) == LABEL_REF) \ + { int scale = 1; \ + if (GET_CODE (ireg) == MULT) \ + { scale = INTVAL (XEXP (ireg, 1)); \ + ireg = XEXP (ireg, 0); } \ + if (GET_CODE (ireg) == SIGN_EXTEND) \ + fprintf (FILE, "pc@(L%d-LI%d-2:B)[%s:W", \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + reg_names[REGNO (XEXP (ireg, 0))]); \ + else \ + fprintf (FILE, "pc@(L%d-LI%d-2:B)[%s:L", \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + reg_names[REGNO (ireg)]); \ + fprintf (FILE, ":%c", sz[scale]); \ + putc (']', FILE); \ + break; } \ + if (breg != 0 && ireg == 0 && GET_CODE (addr) == LABEL_REF) \ + { fprintf (FILE, "pc@(L%d-LI%d-2:B)[%s:L:B]", \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + reg_names[REGNO (breg)]); \ + break; } \ + if (ireg != 0 || breg != 0) \ + { int scale = 1; \ + if (breg == 0) \ + abort (); \ + if (addr && GET_CODE (addr) == LABEL_REF) abort (); \ + fprintf (FILE, "%s@", reg_names[REGNO (breg)]); \ + if (addr != 0) { \ + putc( '(', FILE ); \ + output_addr_const (FILE, addr); \ + if (ireg != 0) { \ + if (GET_CODE(addr) == CONST_INT) { \ + int size_of = 1, val = INTVAL(addr); \ + if (val < -0x8000 || val >= 0x8000) \ + size_of = 4; \ + else if (val < -0x80 || val >= 0x80) \ + size_of = 2; \ + fprintf(FILE, ":%c", sz[size_of]); \ + } \ + else \ + fprintf(FILE, ":L"); } \ + putc( ')', FILE ); } \ + if (ireg != 0) { \ + putc ('[', FILE); \ + if (ireg != 0 && GET_CODE (ireg) == MULT) \ + { scale = INTVAL (XEXP (ireg, 1)); \ + ireg = XEXP (ireg, 0); } \ + if (ireg != 0 && GET_CODE (ireg) == SIGN_EXTEND) \ + fprintf (FILE, "%s:W", reg_names[REGNO (XEXP (ireg, 0))]); \ + else if (ireg != 0) \ + fprintf (FILE, "%s:L", reg_names[REGNO (ireg)]); \ + fprintf (FILE, ":%c", sz[scale]); \ + putc (']', FILE); \ + } \ + break; \ + } \ + else if (reg1 != 0 && GET_CODE (addr) == LABEL_REF) \ + { fprintf (FILE, "pc@(L%d-LI%d-2:B)[%s:L:B]", \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + reg_names[REGNO (reg1)]); \ + break; } \ + default: \ + if (GET_CODE (addr) == CONST_INT \ + && INTVAL (addr) < 0x8000 \ + && INTVAL (addr) >= -0x8000) \ + fprintf (FILE, "%d:W", INTVAL (addr)); \ + else \ + output_addr_const (FILE, addr); \ + }} + +/* +Local variables: +version-control: t +End: +*/ + diff --git a/gcc-1.40/config/tm-altos3068.h b/gcc-1.40/config/tm-altos3068.h new file mode 100644 index 0000000..36c63c5 --- /dev/null +++ b/gcc-1.40/config/tm-altos3068.h @@ -0,0 +1,107 @@ +/* Definitions of target machine for GNU compiler. Altos 3068 68020 version. + Copyright (C) 1988,1989 Free Software Foundation, Inc. + +Written by Jyrki Kuoppala +Last modified: Mon Mar 6 22:47:58 1989 + +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 1, 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 "tm-m68k.h" + +/* See tm-m68k.h. 7 means 68020 with 68881. */ +/* 5 is without 68881. Change to 7 if you have 68881 */ + +#ifndef TARGET_DEFAULT +#define TARGET_DEFAULT 5 +#endif + +/* Define __HAVE_68881__ in preprocessor, + according to the -m flags. + This will control the use of inline 68881 insns in certain macros. + Also inform the program which CPU this is for. */ + +#if TARGET_DEFAULT & 02 + +/* -m68881 is the default */ +#define CPP_SPEC \ +"%{!msoft-float:-D__HAVE_68881__ }\ +%{!ansi:%{m68000:-Dmc68010}%{mc68000:-Dmc68010}%{!mc68000:%{!m68000:-Dmc68020}}}" + +#else + +/* -msoft-float is the default */ +#define CPP_SPEC \ +"%{m68881:-D__HAVE_68881__ }\ +%{!ansi:%{m68000:-Dmc68010}%{mc68000:-Dmc68010}%{!mc68000:%{!m68000:-Dmc68020}}}" + +#endif + +/* -m68000 requires special flags to the assembler. */ + +#define ASM_SPEC \ + "%{m68000:-mc68010}%{mc68000:-mc68010}%{!mc68000:%{!m68000:-mc68020}}" + +/* Names to predefine in the preprocessor for this target machine. */ + +#define CPP_PREDEFINES "-Dmc68000 -DPORTAR -Dmc68k32 -Uvax -Dm68k -Dunix" + +/* Every structure or union's size must be a multiple of 2 bytes. */ + +#define STRUCTURE_SIZE_BOUNDARY 16 + +/* Generate calls to memcpy, memcmp and memset. */ +#define TARGET_MEM_FUNCTIONS + +/* We use gnu assembler, linker and gdb, so we want DBX format. */ + +#define DBX_DEBUGGING_INFO + +/* Tell some conditionals we will use GAS. Is this really used? */ + +#define USE_GAS + +/* This is how to output an assembler line defining a `double' constant. */ + +#undef ASM_OUTPUT_DOUBLE +#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \ + fprintf (FILE, "\t.double 0r%.20e\n", (VALUE)) + +/* This is how to output an assembler line defining a `float' constant. */ + +#undef ASM_OUTPUT_FLOAT +#define ASM_OUTPUT_FLOAT(FILE,VALUE) \ + fprintf (FILE, "\t.single 0r%.20e\n", (VALUE)) + +#undef ASM_OUTPUT_FLOAT_OPERAND +#define ASM_OUTPUT_FLOAT_OPERAND(FILE,VALUE) \ + fprintf (FILE, "#0r%.9g", (VALUE)) + +#undef ASM_OUTPUT_DOUBLE_OPERAND +#define ASM_OUTPUT_DOUBLE_OPERAND(FILE,VALUE) \ + fprintf (FILE, "#0r%.20g", (VALUE)) + +/* Return pointer values in both d0 and a0. */ + +#undef FUNCTION_EXTRA_EPILOGUE +#define FUNCTION_EXTRA_EPILOGUE(FILE, SIZE) \ +{ \ + extern int current_function_returns_pointer; \ + if ((current_function_returns_pointer) && \ + ! find_equiv_reg (0, get_last_insn (), 0, 0, 0, 8, Pmode))\ + fprintf (FILE, "\tmovel d0,a0\n"); \ +} diff --git a/gcc-1.40/config/tm-apollo68.h b/gcc-1.40/config/tm-apollo68.h new file mode 100644 index 0000000..cddfd07 --- /dev/null +++ b/gcc-1.40/config/tm-apollo68.h @@ -0,0 +1,177 @@ +/* Definitions of target machine for GNU compiler. Apollo 680X0 version. + Copyright (C) 1989 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 1, 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 "tm-m68k.h" + +/* This symbol may be tested in other files for special Apollo handling */ + +#define TM_APOLLO + +/* See tm-m68k.h. 7 means 68020 with 68881. */ + +#ifndef TARGET_DEFAULT +#define TARGET_DEFAULT 7 +#endif + +/* Target switches for the Apollo is the same as in tm-m68k.h, except + there is no Sun FPA. */ + +#undef TARGET_SWITCHES +#define TARGET_SWITCHES \ + { { "68020", 5}, \ + { "c68020", 5}, \ + { "68881", 2}, \ + { "bitfield", 4}, \ + { "68000", -5}, \ + { "c68000", -5}, \ + { "soft-float", -0102}, \ + { "nobitfield", -4}, \ + { "rtd", 8}, \ + { "nortd", -8}, \ + { "short", 040}, \ + { "noshort", -040}, \ + { "", TARGET_DEFAULT}} + +/* Define __HAVE_68881__ in preprocessor, + according to the -m flags. + This will control the use of inline 68881 insns in certain macros. + Also inform the program which CPU this is for. */ + +#if TARGET_DEFAULT & 02 + +/* -m68881 is the default */ +#define CPP_SPEC \ +"%{!msoft-float:%{mfpa:-D__HAVE_FPA__ }%{!mfpa:-D__HAVE_68881__ }}\ +%{!ansi:%{m68000:-Dmc68010 }%{mc68000:-Dmc68010 }%{!mc68000:%{!m68000:-Dmc68020 }}\ +%{!ansi:-D_APOLLO_SOURCE}}" + +#else + +/* -msoft-float is the default */ +#define CPP_SPEC \ +"%{m68881:-D__HAVE_68881__ }%{mfpa:-D__HAVE_FPA__ }\ +%{!ansi:%{m68000:-Dmc68010 }%{mc68000:-Dmc68010 }%{!mc68000:%{!m68000:-Dmc68020 }}\ +%{!ansi:-D_APOLLO_SOURCE}}" + +#endif + +/* Names to predefine in the preprocessor for this target machine. */ +/* These are the ones defined by Apollo, plus mc68000 for uniformity with + GCC on other 68000 systems. */ + +#define CPP_PREDEFINES "-Dapollo -Daegis -Dunix" + +/* cpp has to support a #sccs directive for the /usr/include files */ + +#define SCCS_DIRECTIVE + +/* Allow #ident but output nothing for it. */ + +#define IDENT_DIRECTIVE +#define ASM_OUTPUT_IDENT(FILE, NAME) + +/* Allow dollarsigns in identifiers */ + +#define DOLLARS_IN_IDENTIFIERS 1 + +/* -m68000 requires special flags to the assembler. + The -C flag is passed to a modified GNU assembler to cause COFF + modules to be produced. Remove it if you're not using this. + (See vasta@apollo.com.) */ + +#define ASM_SPEC \ + "-C %{m68000:-mc68010}%{mc68000:-mc68010}%{!mc68000:%{!m68000:-mc68020}}" + +/* STARTFILE_SPEC + Note that includes knowledge of the default specs for gcc, ie. no + args translates to the same effect as -m68881 */ + +/* To get ANSI-conformant behavior, a special version of crt0.o must be used. + We use the -ansi switch to pick up that version. */ + +#define STARTFILE_SPEC \ + "%{ansi:/usr/apollo/lib/%{pg:gcrt0.o}%{!pg:%{p:mcrt0.o}%{!p:crt0.o}}}\ +%{!ansi:%{pg:gcrt0.o%s}%{!pg:%{p:mcrt0.o%s}%{!p:crt0.o%s}}}" + +/* Make sure ld sets the entry point to _start. + This is in LIB_SPEC rather than LINK_SPEC because it needs to + come after _start is defined, and to eliminate the default LIB_SPEC. */ +#define LIB_SPEC "-e _start" + +/* Debugging is not supported yet */ + +#undef DBX_DEBUGGING_INFO +#undef SDB_DEBUGGING_INFO + +/* Every structure or union's size must be a multiple of 2 bytes. */ + +#define STRUCTURE_SIZE_BOUNDARY 16 + +/* Functions which return large structures get the address + to place the wanted value at offset 8 from the frame. */ + +#undef PCC_STATIC_STRUCT_RETURN +#undef STRUCT_VALUE_REGNUM + +/* Caller treats address of return area like a parm. */ +#define STRUCT_VALUE 0 + +#define STRUCT_VALUE_INCOMING \ + gen_rtx (MEM, Pmode, \ + gen_rtx (PLUS, SImode, frame_pointer_rtx, \ + gen_rtx (CONST_INT, VOIDmode, 8))) + +/* Boundary (in *bits*) on which stack pointer should be aligned. */ +#undef STACK_BOUNDARY +#define STACK_BOUNDARY 32 + +/* Specify how to pad function arguments. + Arguments are not padded at all; the stack is kept aligned on long + boundaries. */ + +#define FUNCTION_ARG_PADDING(mode, size) none + +/* Short integral argument prototype promotion is not done */ + +#undef PROMOTE_PROTOTYPES + +/* The definition of this macro imposes a limit on the size of + an aggregate object which can be treated as if it were a scalar + object. */ + +#define MAX_FIXED_MODE_SIZE BITS_PER_WORD + +/* The definition of this macro implies that there are cases where + a scalar value cannot be returned in registers. + For Apollo, anything larger than one integer register is returned + using the structure-value mechanism, i.e. objects of DFmode are + returned that way. */ + +#define RETURN_IN_MEMORY(type) \ + (GET_MODE_SIZE (TYPE_MODE (type)) > UNITS_PER_WORD) + +/* This is how to output a reference to a user-level label named NAME. + In order to link to Apollo libraries, no underscore is prepended to names. + `assemble_name' uses this. */ + +#undef ASM_OUTPUT_LABELREF +#define ASM_OUTPUT_LABELREF(FILE,NAME) \ + fprintf (FILE, "%s", NAME) + + diff --git a/gcc-1.40/config/tm-att386.h b/gcc-1.40/config/tm-att386.h new file mode 100644 index 0000000..c359166 --- /dev/null +++ b/gcc-1.40/config/tm-att386.h @@ -0,0 +1,244 @@ +/* Definitions for AT&T assembler syntax for the Intel 80386. + Copyright (C) 1988 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 1, 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. */ + + +#define TARGET_VERSION fprintf (stderr, " (80386, ATT syntax)"); + +/* Define the syntax of instructions and addresses. */ + +/* Define some concatenation macros to concatenate an opcode + and one, two or three operands. In other assembler syntaxes + they may alter the order of ther operands. */ + +#ifdef __STDC__ +#define AS2(a,b,c) #a " " #b "," #c +#define AS3(a,b,c,d) #a " " #b "," #c "," #d +#define AS1(a,b) #a " " #b +#else +#define AS1(a,b) "a b" +#define AS2(a,b,c) "a b,c" +#define AS3(a,b,c,d) "a b,c,d" +#endif + +/* Output the size-letter for an opcode. + CODE is the letter used in an operand spec (L, B, W, S or Q). + CH is the corresponding lower case letter + (except if CODE is L then CH is `l'). */ +#define PUT_OP_SIZE(CODE,CH,FILE) putc (CH,(FILE)) + +/* Opcode suffix for fullword insn. */ +#define L_SIZE "l" + +/* Prefix for register names in this syntax. */ +#define RP "%" + +/* Prefix for immediate operands in this syntax. */ +#define IP "$" + +/* Prefix for internally generated assembler labels. */ +#define LPREFIX ".L" + +/* Output the prefix for an immediate operand, or for an offset operand. */ +#define PRINT_IMMED_PREFIX(FILE) fputs ("$", (FILE)) +#define PRINT_OFFSET_PREFIX(FILE) fputs ("$", (FILE)) + +/* Indirect call instructions should use `*'. */ +#define USE_STAR 1 + +/* Prefix for a memory-operand X. */ +#define PRINT_PTR(X, FILE) + +/* Delimiters that surround base reg and index reg. */ +#define ADDR_BEG(FILE) putc('(', (FILE)) +#define ADDR_END(FILE) putc(')', (FILE)) + +/* Print an index register (whose rtx is IREG). */ +#define PRINT_IREG(FILE,IREG) \ + do \ + { fputs (",", (FILE)); PRINT_REG ((IREG), 0, (FILE)); } \ + while (0) + +/* Print an index scale factor SCALE. */ +#define PRINT_SCALE(FILE,SCALE) \ + if ((SCALE) != 1) fprintf ((FILE), ",%d", (SCALE)) + +/* Print a base/index combination. + BREG is the base reg rtx, IREG is the index reg rtx, + and SCALE is the index scale factor (an integer). */ + +#define PRINT_B_I_S(BREG,IREG,SCALE,FILE) \ + { ADDR_BEG (FILE); \ + if (BREG) PRINT_REG ((BREG), 0, (FILE)); \ + if ((IREG) != 0) \ + { PRINT_IREG ((FILE), (IREG)); \ + PRINT_SCALE ((FILE), (SCALE)); } \ + ADDR_END (FILE); } + +/* Define the syntax of pseudo-ops, labels and comments. */ + +/* Assembler pseudos to introduce constants of various size. */ + +#define ASM_BYTE "\t.byte " +#define ASM_SHORT "\t.value " +#define ASM_LONG "\t.long " +#define ASM_DOUBLE "\t.double " + +/* String containing the assembler's comment-starter. */ + +#define COMMENT_BEGIN "/" + +/* Output at beginning of assembler file. */ +/* The .file command should always begin the output. */ + +#undef ASM_FILE_START +#define ASM_FILE_START(FILE) \ + do { sdbout_filename ((FILE), main_input_filename); \ + if (optimize) ASM_FILE_START_1 (FILE); \ + } while (0) + +#define ASM_FILE_START_1(FILE) fprintf (FILE, "\t.optim\n") + +/* Output to assembler file text saying following lines + may contain character constants, extra white space, comments, etc. */ + +#define ASM_APP_ON "/APP\n" + +/* Output to assembler file text saying following lines + no longer contain unusual constructs. */ + +#define ASM_APP_OFF "/NO_APP\n" + +/* 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)) + +/* This is how to output an assembler line + that says to advance the location counter by SIZE bytes. */ + +/* The `space' pseudo in the text segment outputs nop insns rather than 0s, + so we must output 0s explicitly in the text segment. */ +#define ASM_OUTPUT_SKIP(FILE,SIZE) \ + if (in_text_section ()) \ + { \ + int i; \ + for (i = 0; i < (SIZE) - 20; i += 20) \ + fprintf (FILE, "\t.byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\n"); \ + if (i < (SIZE)) \ + { \ + fprintf (FILE, "\t.byte 0"); \ + i++; \ + for (; i < (SIZE); i++) \ + fprintf (FILE, ",0"); \ + fprintf (FILE, "\n"); \ + } \ + } \ + else \ + fprintf ((FILE), "\t.set .,.+%u\n", (SIZE)) + +/* Output before read-only data. */ + +#define TEXT_SECTION_ASM_OP ".text" + +/* Output before writable data. */ + +#define DATA_SECTION_ASM_OP ".data" + +/* Output before uninitialized data. */ + +#define BSS_SECTION_ASM_OP ".bss" + +#define EXTRA_SECTIONS in_bss + +#define EXTRA_SECTION_FUNCTIONS \ +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. */ + +/* This says how to output an assembler line + to define a global common symbol. */ +/* We don't use ROUNDED because the standard compiler doesn't, + and the linker gives error messages if a common symbol + has more than one length value. */ + +#define ASM_OUTPUT_COMMON(FILE, NAME, SIZE, ROUNDED) \ +( fputs (".comm ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%u\n", (SIZE))) + +/* This says how to output an assembler line + to define a local common symbol. */ + +/* Note that using bss_section here caused errors + in building shared libraries on system V.3. */ +#define ASM_OUTPUT_LOCAL(FILE, NAME, SIZE, ROUNDED) \ + do { \ + int align = exact_log2 (ROUNDED); \ + if (align > 2) align = 2; \ + data_section (); \ + ASM_OUTPUT_ALIGN ((FILE), align == -1 ? 2 : align); \ + ASM_OUTPUT_LABEL ((FILE), (NAME)); \ + fprintf ((FILE), "\t.set .,.+%u\n", (ROUNDED)); \ + } while (0) + +/* This is how to store into the string BUF + 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(BUF,PREFIX,NUMBER) \ + sprintf ((BUF), ".%s%d", (PREFIX), (NUMBER)) + +/* This is how to output a reference to a user-level label named NAME. */ + +#define ASM_OUTPUT_LABELREF(FILE,NAME) \ + fprintf (FILE, "%s", NAME) + +/* 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) \ + fprintf (FILE, ".%s%d:\n", PREFIX, NUM) + +/* 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) \ + (fputs (".globl ", FILE), assemble_name (FILE, NAME), fputs ("\n", FILE)) + +/* How to output an ASCII string constant. */ + +#define ASM_OUTPUT_ASCII(FILE, p, size) \ +{ int i=0; \ + while (i < size) \ + { if (i%10 == 0) { if (i!=0) fprintf (FILE, "\n"); \ + fprintf (FILE, ASM_BYTE); } \ + else fprintf (FILE, ","); \ + fprintf (FILE, "0x%x",(p[i++] & 0377)) ;} \ + fprintf (FILE, "\n"); } diff --git a/gcc-1.40/config/tm-bsd386.h b/gcc-1.40/config/tm-bsd386.h new file mode 100644 index 0000000..2bfc61d --- /dev/null +++ b/gcc-1.40/config/tm-bsd386.h @@ -0,0 +1,202 @@ +/* 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. + +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 1, 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. */ + +/* Use the Sequent Symmetry assembler syntax. */ + +#define TARGET_VERSION fprintf (stderr, " (80386, BSD syntax)"); + +/* Define some concatenation macros to concatenate an opcode + and one, two or three operands. In other assembler syntaxes + they may alter the order of ther operands. */ + +#ifdef __STDC__ +#define AS2(a,b,c) #a " " #b "," #c +#define AS3(a,b,c,d) #a " " #b "," #c "," #d +#define AS1(a,b) #a " " #b +#else +#define AS1(a,b) "a b" +#define AS2(a,b,c) "a b,c" +#define AS3(a,b,c,d) "a b,c,d" +#endif + +/* Output the size-letter for an opcode. + CODE is the letter used in an operand spec (L, B, W, S or Q). + CH is the corresponding lower case letter + (except if CODE is L then CH is `l'). */ +#define PUT_OP_SIZE(CODE,CH,FILE) putc (CH,(FILE)) + +/* Opcode suffix for fullword insn. */ +#define L_SIZE "l" + +/* Prefix for register names in this syntax. */ +#define RP "%" + +/* Prefix for immediate operands in this syntax. */ +#define IP "$" + +/* Prefix for internally generated assembler labels. */ +#define LPREFIX "L" + +/* Output the prefix for an immediate operand, or for an offset operand. */ +#define PRINT_IMMED_PREFIX(FILE) fputs ("$", (FILE)) +#define PRINT_OFFSET_PREFIX(FILE) fputs ("$", (FILE)) + +/* Indirect call instructions should use `*'. */ +#define USE_STAR 1 + +/* Prefix for a memory-operand X. */ +#define PRINT_PTR(X, FILE) + +/* Delimiters that surround base reg and index reg. */ +#define ADDR_BEG(FILE) putc('(', (FILE)) +#define ADDR_END(FILE) putc(')', (FILE)) + +/* Print an index register (whose rtx is IREG). */ +#define PRINT_IREG(FILE,IREG) \ + do \ + { fputs (",", (FILE)); PRINT_REG ((IREG), 0, (FILE)); } \ + while (0) + +/* Print an index scale factor SCALE. */ +#define PRINT_SCALE(FILE,SCALE) \ + if ((SCALE) != 1) fprintf ((FILE), ",%d", (SCALE)) + +/* Print a base/index combination. + BREG is the base reg rtx, IREG is the index reg rtx, + and SCALE is the index scale factor (an integer). */ + +#define PRINT_B_I_S(BREG,IREG,SCALE,FILE) \ + { ADDR_BEG (FILE); \ + if (BREG) PRINT_REG ((BREG), 0, (FILE)); \ + if ((IREG) != 0) \ + { PRINT_IREG ((FILE), (IREG)); \ + PRINT_SCALE ((FILE), (SCALE)); } \ + ADDR_END (FILE); } + +/* Define the syntax of pseudo-ops, labels and comments. */ + +/* Assembler pseudos to introduce constants of various size. */ + +#define ASM_BYTE "\t.byte " +#define ASM_SHORT "\t.word " +#define ASM_LONG "\t.long " +#define ASM_DOUBLE "\t.double " + +/* String containing the assembler's comment-starter. */ + +#define COMMENT_BEGIN "/" + +/* Output at beginning of assembler file. + ??? I am skeptical of this -- RMS. */ + +#define ASM_FILE_START(FILE) \ + fprintf (FILE, "\t.file\t\"%s\"\n", dump_base_name); + +/* This was suggested, but it shouldn't be right for DBX output. -- RMS + #define ASM_OUTPUT_SOURCE_FILENAME(FILE, NAME) */ + +/* Output to assembler file text saying following lines + may contain character constants, extra white space, comments, etc. */ + +#define ASM_APP_ON "/APP\n" + +/* Output to assembler file text saying following lines + no longer contain unusual constructs. */ + +#define ASM_APP_OFF "/NO_APP\n" + +/* Define the syntax of labels and symbol definitions/declarations. */ + +/* This is how to output an assembler line + that says to advance the location counter by SIZE bytes. */ + +#define ASM_OUTPUT_SKIP(FILE,SIZE) \ + fprintf (FILE, "\t.space %u\n", (SIZE)) + +/* Output before read-only data. */ + +#define TEXT_SECTION_ASM_OP ".text" + +/* Output before writable data. */ + +#define DATA_SECTION_ASM_OP ".data" + +/* Define the syntax of labels and symbol definitions/declarations. */ + +/* This says how to output an assembler line + to define a global common symbol. */ + +#define ASM_OUTPUT_COMMON(FILE, NAME, SIZE, ROUNDED) \ +( fputs (".comm ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%u\n", (SIZE))) + +/* This says how to output an assembler line + to define a local common symbol. */ + +#define ASM_OUTPUT_LOCAL(FILE, NAME, SIZE, ROUNDED) \ +( fputs (".lcomm ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%u\n", (SIZE))) + +/* 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", (LOG)) + +/* This is how to store into the string BUF + 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(BUF,PREFIX,NUMBER) \ + sprintf ((BUF), "*%s%d", (PREFIX), (NUMBER)) + +/* 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) \ + fprintf (FILE, "%s%d:\n", PREFIX, NUM) + +/* This is how to output a reference to a user-level label named NAME. */ + +#define ASM_OUTPUT_LABELREF(FILE,NAME) \ + fprintf (FILE, "_%s", NAME) + +/* Sequent has some changes in the format of DBX symbols. */ +#define DBX_NO_XREFS 1 + +/* Don't split DBX symbols into continuations. */ +#define DBX_CONTIN_LENGTH 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) \ + (fputs (".globl ", FILE), assemble_name (FILE, NAME), fputs ("\n", FILE)) + +/* This is how to output an assembler line defining a `double' constant. */ + +#undef ASM_OUTPUT_DOUBLE +#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \ + fprintf (FILE, "\t.double 0d%.20e\n", (VALUE)) diff --git a/gcc-1.40/config/tm-compaq.h b/gcc-1.40/config/tm-compaq.h new file mode 100644 index 0000000..6aa7d5f --- /dev/null +++ b/gcc-1.40/config/tm-compaq.h @@ -0,0 +1,39 @@ +/* Definitions for Compaq as target machine. NOT TESTED! + Copyright (C) 1988 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 1, 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 "tm-i386.h" + +/* Use the ATT assembler syntax. */ + +#include "tm-att386.h" + +/* By default, target has a 80387. */ + +#define TARGET_DEFAULT 1 + +#define ASM_SPEC "" + +/* Names to predefine in the preprocessor for this target machine. */ + +#define CPP_PREDEFINES "-Di386 -Di80386 -Dunix" + + +#include "tm-i386.h" +#include "tm-att386.h" diff --git a/gcc-1.40/config/tm-conv1os7.h b/gcc-1.40/config/tm-conv1os7.h new file mode 100644 index 0000000..ec522dd --- /dev/null +++ b/gcc-1.40/config/tm-conv1os7.h @@ -0,0 +1,6 @@ +#include "tm-convex1.h" + +#undef LINK_SPEC +#undef STARTFILE_SPEC +#undef CPP_SPEC +#undef LIB_SPEC diff --git a/gcc-1.40/config/tm-conv2os7.h b/gcc-1.40/config/tm-conv2os7.h new file mode 100644 index 0000000..9735905 --- /dev/null +++ b/gcc-1.40/config/tm-conv2os7.h @@ -0,0 +1,6 @@ +#include "tm-convex2.h" + +#undef LINK_SPEC +#undef STARTFILE_SPEC +#undef CPP_SPEC +#undef LIB_SPEC diff --git a/gcc-1.40/config/tm-convex.h b/gcc-1.40/config/tm-convex.h new file mode 100644 index 0000000..71be483 --- /dev/null +++ b/gcc-1.40/config/tm-convex.h @@ -0,0 +1,1034 @@ +/* Definitions of target machine for GNU compiler. Convex version. + Copyright (C) 1989, 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 1, 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. */ + + +/* Use the proper incantation to search Posix-compliant libraries. */ + +#define LINK_SPEC \ +"%{!traditional:-Eposix}%{traditional:-Enoposix}\ + -A__iob=___ap$iob\ + -A_use_libc_sema=___ap$use_libc_sema\ + -L /usr/lib" + +/* Use the matching startup files. */ + +#define STARTFILE_SPEC \ +"%{pg:/usr/lib/crt/gcrt0.o}\ +%{!pg:%{p:/usr/lib/crt/mcrt0.o}\ +%{!p:/usr/lib/crt/crt0.o}}" + +/* Names to predefine in the preprocessor for this target machine. */ + +#define CPP_PREDEFINES "-Dconvex -Dunix" + +/* Print subsidiary information on the compiler version in use. */ + +#define TARGET_VERSION fprintf (stderr, " (convex)"); + +/* Run-time compilation parameters selecting different hardware subsets. */ + +extern int target_flags; + +/* Macros used in the machine description to test the flags. */ + +/* + -mc1 avoid C2-only instructions; default on C1 host + -mc2 use C2-only instructions; default on C2 host + -margcount use standard calling sequence, with arg count word + -mnoargcount don't push arg count (it's in the symbol table) (usually) +*/ + +#define TARGET_C1 (target_flags & 1) +#define TARGET_C2 (target_flags & 2) +#define TARGET_ARGCOUNT (target_flags & 4) + +/* 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 \ + { { "c1", 1 }, \ + { "c2", 2 }, \ + { "noc1", -1 }, \ + { "noc2", -2 }, \ + { "argcount", 4 }, \ + { "noargcount", -4 }, \ + { "", TARGET_DEFAULT }} + +/* Default target_flags if no switches specified. */ + +#ifndef TARGET_DEFAULT +#define TARGET_DEFAULT 0 +#endif + +/* Allow $ in identifiers */ + +#define DOLLARS_IN_IDENTIFIERS 1 + +/* Definitions for g++. */ + +/* Do not put out GNU stabs for constructors and destructors. + ld does not like them. */ + +#define FASCIST_ASSEMBLER + +/* Convex has negative addresses, so use positive numbers + to mean `vtable index'. */ + +#define VTABLE_USES_MASK +#define VINDEX_MAX ((unsigned) 0x80000000) + +/* Target machine storage layout */ + +/* Define this if most significant bit is lowest numbered + in instructions that operate on numbered bit-fields. */ +#define BITS_BIG_ENDIAN + +/* Define this if most significant byte of a word is the lowest numbered. */ +#define BYTES_BIG_ENDIAN + +/* Define this if most significant word of a multiword number is numbered. */ +/* Lie, so that gcc will take the low part of double reg N in reg N. */ +/* #define WORDS_BIG_ENDIAN */ + +/* Number of bits in an addressible 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 32 + +/* Width of a word, in units (bytes). */ +#define UNITS_PER_WORD 4 + +/* Width in bits of a pointer. + See also the macro `Pmode' defined below. */ +#define POINTER_SIZE 32 + +/* Allocation boundary (in *bits*) for storing pointers in memory. */ +#define POINTER_BOUNDARY 32 + +/* Allocation boundary (in *bits*) for storing arguments in argument list. */ +#define PARM_BOUNDARY 32 + +/* Boundary (in *bits*) on which stack pointer should be aligned. */ +#define STACK_BOUNDARY 32 + +/* Allocation boundary (in *bits*) for the code of a function. */ +#define FUNCTION_BOUNDARY 16 + +/* Alignment of field after `int : 0' in a structure. */ +#define EMPTY_FIELD_BOUNDARY 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. */ +/* beware of doubles in structs -- 64 is incompatible with pcc */ +#define BIGGEST_ALIGNMENT 32 + +/* Define this if move instructions will actually fail to work + when given unaligned data. */ +/* #define STRICT_ALIGNMENT */ + +/* 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. */ +#define FIRST_PSEUDO_REGISTER 16 + +/* 1 for registers that have pervasive standard uses + and are not available for the register allocator. + For Convex, these are AP, FP, and SP. */ +#define FIXED_REGISTERS {0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1} + +/* 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} + +/* 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 Convex, all values fit in one register. */ +#define HARD_REGNO_NREGS(REGNO, MODE) 1 + +/* Value is 1 if hard register REGNO can hold a value of machine-mode MODE. + On Convex, S registers can hold any type, A registers can any nonfloat */ +#define HARD_REGNO_MODE_OK(REGNO, MODE) \ + ((REGNO) < 8 || ((MODE) != SFmode && (MODE) != DFmode && (MODE) != DImode)) + +/* 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) == SFmode || (MODE1) == DFmode || (MODE1) == DImode) \ + == ((MODE2) == SFmode || (MODE2) == DFmode || (MODE2) == DImode)) + +/* Specify the registers used for certain standard purposes. + The values of these macros are register numbers. */ + +/* Register to use for pushing function arguments. */ +#define STACK_POINTER_REGNUM 8 + +/* Base register for access to local variables of the function. */ +#define FRAME_POINTER_REGNUM 15 + +/* 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. */ +#define FRAME_POINTER_REQUIRED 1 + +/* Base register for access to arguments of the function. */ +#define ARG_POINTER_REGNUM 14 + +/* Register in which static-chain is passed to a function. */ +#define STATIC_CHAIN_REGNUM 0 + +/* Register in which address to store a structure value + is passed to a function. */ +#define STRUCT_VALUE_REGNUM 9 + +/* 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. */ + +/* Convex has classes A (address) and S (scalar). Seems to work + better to put S first, here and in the md. */ + +enum reg_class { NO_REGS, S_REGS, A_REGS, ALL_REGS, LIM_REG_CLASSES }; + +#define N_REG_CLASSES (int) LIM_REG_CLASSES + +/* Since GENERAL_REGS is the same class as ALL_REGS, + don't give it a different class number; just make it an alias. */ + +#define GENERAL_REGS ALL_REGS + +/* Give names of register classes as strings for dump file. */ + +#define REG_CLASS_NAMES \ + {"NO_REGS", "S_REGS", "A_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, 0x00ff, 0xff00, 0xffff} + +/* 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. */ + +#define REGNO_REG_CLASS(REGNO) \ + (S_REGNO_P (REGNO) ? S_REGS : A_REGS) + +#define S_REGNO_P(REGNO) ((REGNO) < 8) +#define A_REGNO_P(REGNO) ((REGNO) >= 8) + +#define S_REG_P(X) (REG_P (X) && S_REGNO_P (REGNO (X))) +#define A_REG_P(X) (REG_P (X) && A_REGNO_P (REGNO (X))) + +/* The class value for index registers, and the one for base regs. */ + +#define INDEX_REG_CLASS A_REGS +#define BASE_REG_CLASS A_REGS + +/* Get reg_class from a letter such as appears in the machine description. */ +/* S regs use the letter 'd' because 's' is taken. */ + +#define REG_CLASS_FROM_LETTER(C) \ + ((C) == 'a' ? A_REGS : (C) == 'd' ? S_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. */ + +/* Convex uses only I: + 32-bit value with sign bit off, usable as immediate in DImode logical + instructions and, or, xor */ + +#define CONST_OK_FOR_LETTER_P(VALUE, C) ((VALUE) >= 0) + +/* Similar, but for floating constants, and defining letters G and H. + Here VALUE is the CONST_DOUBLE rtx itself. */ +/* Convex uses only G: + value usable in ld.d (low word 0) or ld.l (high word all sign) */ + +#define CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C) \ + (LD_D_P (VALUE) || LD_L_P (VALUE)) + +#define LD_D_P(X) (const_double_low_int (X) == 0) + +#define LD_L_P(X) (const_double_low_int (X) >= 0 \ + ? const_double_high_int (X) == 0 \ + : const_double_high_int (X) == -1) + +extern int const_double_low_int (); +extern int const_double_high_int (); +extern int const_double_float_int (); + +/* 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. */ + +#define PREFERRED_RELOAD_CLASS(X,CLASS) (CLASS) + +/* Return the maximum number of consecutive registers + needed to represent mode MODE in a register of class CLASS. */ +#define CLASS_MAX_NREGS(CLASS, MODE) 1 + +/* Stack layout; function entry, exit and calling. */ + +/* 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 + +/* Define this if should default to -fcaller-saves. */ + +#define DEFAULT_CALLER_SAVES + +/* 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. */ +#define STARTING_FRAME_OFFSET 0 + +/* If we generate an insn to push BYTES bytes, + this says how many the stack pointer really advances by. */ +#define PUSH_ROUNDING(BYTES) (((BYTES) + 3) & ~3) + +/* Offset of first parameter from the argument pointer register value. */ +#define FIRST_PARM_OFFSET(FNDECL) 0 + +/* Value is 1 if returning from a function call automatically + pops the arguments described by the number-of-args field in the call. + 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. */ +/* The standard Convex call, with arg count word, includes popping the + args as part of the call template. We optionally omit the arg count + word and let gcc combine the arg pops. */ +#define RETURN_POPS_ARGS(FUNTYPE) TARGET_ARGCOUNT + +/* 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 Convex the return value is in S0 regardless. */ + +#define FUNCTION_VALUE(VALTYPE, FUNC) \ + gen_rtx (REG, TYPE_MODE (VALTYPE), 0) + +/* Define how to find the value returned by a library function + assuming the value has mode MODE. */ + +/* On Convex the return value is in S0 regardless. */ + +#define LIBCALL_VALUE(MODE) gen_rtx (REG, MODE, 0) + +/* Define this if PCC uses the nonreentrant convention for returning + structure and union values. */ + +#define PCC_STATIC_STRUCT_RETURN + +/* 1 if N is a possible register number for a function value. + On the Convex, S0 is the only register thus used. */ + +#define FUNCTION_VALUE_REGNO_P(N) ((N) == 0) + +/* 1 if N is a possible register number for function argument passing. */ + +#define FUNCTION_ARG_REGNO_P(N) 0 + +/* 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 the vax, this is a single integer, which is a number of bytes + of arguments scanned so far. */ + +#define CUMULATIVE_ARGS int + +/* 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. + + On Convex, the offset starts at 0. */ + +#define INIT_CUMULATIVE_ARGS(CUM,FNTYPE) \ + ((CUM) = 0) + +/* 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.) */ + +#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \ + ((CUM) += ((MODE) != BLKmode \ + ? (GET_MODE_SIZE (MODE) + 3) & ~3 \ + : (int_size_in_bytes (TYPE) + 3) & ~3)) + +/* Define where to put the arguments 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). */ + +/* On Convex, all args are pushed. */ + +#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) 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. */ + +#define FUNCTION_PROLOGUE(FILE, SIZE) \ +{ if ((SIZE) != 0) fprintf (FILE, "\tsub.w #%d,sp\n", ((SIZE) + 3) & -4);} + +/* Output assembler code to FILE to increment profiler label # LABELNO + for profiling a function entry. */ + +#define FUNCTION_PROFILER(FILE, LABELNO) \ + fprintf (FILE, "\tldea LP%d,a1\n\tcallq mcount\n", (LABELNO)); + +/* 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. */ + +#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. */ + +/* #define FUNCTION_EPILOGUE(FILE, SIZE) */ + +/* If the memory address ADDR is relative to the frame pointer, + correct it to be relative to the stack pointer instead. + This is for when we don't use a frame pointer. + ADDR should be a variable name. */ + +#define FIX_FRAME_POINTER_ADDRESS(ADDR,DEPTH) abort (); + +/* 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) ^ 010) < 8 || ((reg_renumber[regno] ^ 010) & -8) == 0) \ + && regno != 8) + +#define REGNO_OK_FOR_BASE_P(regno) REGNO_OK_FOR_INDEX_P (regno) + +/* Maximum number of registers that can appear in a valid memory address. */ + +#define MAX_REGS_PER_ADDRESS 1 + +/* 1 if X is an rtx for a constant that is a valid address. */ + +#define CONSTANT_ADDRESS_P(X) CONSTANT_P (X) + +/* Nonzero if the constant value X is a legitimate general operand. + It is given that X satisfies CONSTANT_P or is a CONST_DOUBLE. */ + +/* For convex, any single-word constant is ok; the only contexts + allowing general_operand of mode DI or DF are movdi and movdf. */ + +#define LEGITIMATE_CONSTANT_P(X) \ + (GET_CODE (X) != CONST_DOUBLE ? 1 : (LD_D_P (X) || LD_L_P (X))) + +/* 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. */ + +#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) (REGNO (X) > 8) +/* 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) (REGNO (X) > 8) + +#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)) + +#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. + + For Convex, valid addresses are + indirectable or (MEM indirectable) + where indirectable is + const, reg, (PLUS reg const) */ + +/* 1 if X is an address that we could indirect through. */ +#define INDIRECTABLE_ADDRESS_P(X) \ + (CONSTANT_ADDRESS_P (X) \ + || (GET_CODE (X) == REG && REG_OK_FOR_BASE_P (X)) \ + || (GET_CODE (X) == PLUS \ + && GET_CODE (XEXP (X, 0)) == REG \ + && REG_OK_FOR_BASE_P (XEXP (X, 0)) \ + && CONSTANT_ADDRESS_P (XEXP (X, 1))) \ + || (GET_CODE (X) == PLUS \ + && GET_CODE (XEXP (X, 1)) == REG \ + && REG_OK_FOR_BASE_P (XEXP (X, 1)) \ + && CONSTANT_ADDRESS_P (XEXP (X, 0)))) + +/* Go to ADDR if X is a valid address. */ +#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \ +{ register rtx xfoob = (X); \ + if (GET_CODE (xfoob) == REG) goto ADDR; \ + if (INDIRECTABLE_ADDRESS_P (xfoob)) goto ADDR; \ + xfoob = XEXP (X, 0); \ + if (GET_CODE (X) == MEM && INDIRECTABLE_ADDRESS_P (xfoob)) \ + goto ADDR; \ + if (GET_CODE (X) == PRE_DEC && REG_P (xfoob) \ + && REGNO (xfoob) == STACK_POINTER_REGNUM) \ + 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. + + For Convex, nothing needs to be done. */ + +#define LEGITIMIZE_ADDRESS(X,OLDX,MODE,WIN) {} + +/* Go to LABEL if ADDR (a legitimate address expression) + has an effect that depends on the machine mode it is used for. */ + +#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR,LABEL) {} + +/* Specify the machine mode that this machine uses + for the index in the tablejump instruction. */ +#define CASE_VECTOR_MODE SImode + +/* Define this if the case 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 this if the case instruction drops through after the table + when the index is out of range. Don't define it if the case insn + jumps to the default label instead. */ +/* #define CASE_DROPS_THROUGH */ + +/* 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 + +/* This flag, if defined, says the same insns that convert to a signed fixnum + also convert validly to an unsigned one. */ +#define FIXUNS_TRUNC_LIKE_FIX_TRUNC + +/* Max number of bytes we can move from memory to memory + in one reasonably fast instruction. */ +#define MOVE_MAX 8 + +/* Define this if zero-extension is slow (more than one real instruction). */ +/* #define SLOW_ZERO_EXTEND */ + +/* Nonzero if access to memory by bytes is slow and undesirable. */ +#define SLOW_BYTE_ACCESS 0 + +/* Define if shifts truncate the shift count + which implies one can omit a sign-extension or zero-extension + of a shift count. */ +#define SHIFT_COUNT_TRUNCATED + +/* 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 + +/* On Convex, it is as good to call a constant function address as to + call an address kept in a register. */ +#define NO_FUNCTION_CSE + +/* When a prototype says `char' or `short', really pass an `int'. */ +#define PROMOTE_PROTOTYPES + +/* 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 SImode + +/* 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 QImode + +/* 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) \ + case CONST: \ + case LABEL_REF: \ + case SYMBOL_REF: \ + case CONST_INT: \ + return 0; \ + case CONST_DOUBLE: \ + return 2; + +/* Check a `double' value for validity for a particular machine mode. */ + +#define CHECK_FLOAT_VALUE(mode, d) \ + if ((mode) == SFmode) \ + { \ + if ((d) > 1.7014117331926443e+38) \ + { error ("magnitude of constant too large for `float'"); \ + (d) = 1.7014117331926443e+38; } \ + else if ((d) < -1.7014117331926443e+38) \ + { error ("magnitude of constant too large for `float'"); \ + (d) = -1.7014117331926443e+38; } \ + else if (((d) > 0) && ((d) < 2.9387358770557188e-39)) \ + { warning ("`float' constant truncated to zero"); \ + (d) = 0.0; } \ + else if (((d) < 0) && ((d) > -2.9387358770557188e-39)) \ + { warning ("`float' constant truncated to zero"); \ + (d) = 0.0; } \ + } + +/* Tell final.c how to eliminate redundant test instructions. */ + +/* Here we define machine-dependent flags and fields in cc_status + (see `conditions.h'). No extra ones are needed for convex. */ + +/* Store in cc_status the expressions + that the condition codes will describe + after execution of an instruction whose pattern is EXP. + Do not alter them if the instruction would not alter the cc's. */ + +#define NOTICE_UPDATE_CC(EXP,INSN) {CC_STATUS_INIT;} + +/* Control the assembler format that we output. */ + +/* Output at beginning of assembler file. */ + +#define ASM_FILE_START(FILE) fprintf (FILE, ";NO_APP\n") + +/* Output to assembler file text saying following lines + may contain character constants, extra white space, comments, etc. */ + +#define ASM_APP_ON ";APP\n" + +/* Output to assembler file text saying following lines + no longer contain unusual constructs. */ + +#define ASM_APP_OFF ";NO_APP\n" + +/* Alignment with Convex's assembler goes like this: + .text can be .aligned up to a halfword. + .data and .bss can be .aligned up to a longword. + .lcomm is not supported, explicit declarations in .bss must be used instead. + We get alignment for word and longword .text data by conventionally + using .text 2 for word-aligned data and .text 3 for longword-aligned + data. This requires that this data's size be a multiple of its alignment, + which seems to be always true. */ + +/* Boolean to keep track of whether the current section is .text or not. */ + +extern int current_section_is_text; + +/* Output before read-only data. */ + +#define TEXT_SECTION_ASM_OP (current_section_is_text = 1, ".text") + +/* Output before writable data. */ + +#define DATA_SECTION_ASM_OP (current_section_is_text = 0, ".data") + +/* Output before uninitialized data. */ + +#define BSS_SECTION_ASM_OP (current_section_is_text = 0, ".bss") + +#define EXTRA_SECTIONS in_bss + +#define EXTRA_SECTION_FUNCTIONS \ +void \ +bss_section () \ +{ \ + if (in_section != in_bss) \ + { \ + fprintf (asm_out_file, "%s\n", BSS_SECTION_ASM_OP); \ + in_section = in_bss; \ + } \ +} + +/* 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 (current_section_is_text && (LOG) > 1) \ + fprintf (FILE, ".text %d\n", LOG); \ + else if (current_section_is_text) \ + fprintf (FILE, ".text\n.align %d\n", 1 << (LOG)); \ + else \ + fprintf (FILE, ".align %d\n", 1 << (LOG)) + +/* How to refer to registers in assembler output. + This sequence is indexed by compiler's hard-register-number (see above). */ + +#define REGISTER_NAMES \ +{"s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", \ + "sp", "a1", "a2", "a3", "a4", "a5", "ap", "fp"} + +/* This is BSD, so it wants DBX format. */ + +#define DBX_DEBUGGING_INFO + +/* How to renumber registers for dbx and gdb. */ + +#define DBX_REGISTER_NUMBER(REGNO) (REGNO) + +/* Do not break .stabs pseudos into continuations. */ + +#define DBX_CONTIN_LENGTH 0 + +/* This is the char to use for continuation (in case we need to turn + continuation back on). */ + +#define DBX_CONTIN_CHAR '?' + +/* Don't use the `xsfoo;' construct in DBX output; this system + doesn't support it. */ + +#define DBX_NO_XREFS + +/* 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 (".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. */ + +#define ASM_OUTPUT_LABELREF(FILE,NAME) \ + fprintf (FILE, "_%s", NAME) + +/* 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) \ + fprintf (FILE, "%s%d:\n", PREFIX, NUM) + +/* Put case tables in .text 2, where they will be word-aligned */ + +#define ASM_OUTPUT_CASE_LABEL(FILE,PREFIX,NUM,TABLE) \ + ASM_OUTPUT_ALIGN (FILE, 2); \ + ASM_OUTPUT_INTERNAL_LABEL (FILE, PREFIX, NUM) + +#define ASM_OUTPUT_CASE_END(FILE,NUM,TABLE) \ + ASM_OUTPUT_ALIGN (FILE, 1) + +/* 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%d", PREFIX, NUM) + +/* This is how to output an assembler line defining a `double' constant. */ + +#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \ + fprintf (FILE, "\tds.d %.17e\n", (VALUE)) + +/* This is how to output an assembler line defining a `float' constant. */ + +#define ASM_OUTPUT_FLOAT(FILE,VALUE) \ + fprintf (FILE, "\tds.s %.9e\n", (VALUE)) + +/* This is how to output an assembler line defining an `int' constant. */ + +#define ASM_OUTPUT_INT(FILE,VALUE) \ +( fprintf (FILE, "\tds.w "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +/* Likewise for `char' and `short' constants. */ + +#define ASM_OUTPUT_SHORT(FILE,VALUE) \ +( fprintf (FILE, "\tds.h "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +#define ASM_OUTPUT_CHAR(FILE,VALUE) \ +( fprintf (FILE, "\tds.b "), \ + 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, "\tds.b %#x\n", (VALUE)) + +/* This is how to output a string */ + +#define ASM_OUTPUT_ASCII(FILE,STR,SIZE) do { \ + int i; \ + fprintf (FILE, "\tds.b \""); \ + for (i = 0; i < (SIZE); i++) { \ + register int c = (STR)[i] & 0377; \ + if (c >= ' ' && c < 0177 && c != '\\' && c != '"') \ + putc (c, FILE); \ + else \ + fprintf (FILE, "\\%03o", c);} \ + fprintf (FILE, "\"\n");} while (0) + +/* This is how to output an insn to push a register on the stack. + It need not be very fast code. */ + +#define ASM_OUTPUT_REG_PUSH(FILE,REGNO) \ + fprintf (FILE, "\tpsh.%c %s\n", \ + S_REGNO_P (REGNO) ? 'l' : 'w', \ + 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, "\tpop.%c %s\n", \ + S_REGNO_P (REGNO) ? 'l' : 'w', \ + reg_names[REGNO]) + +/* This is how to output an element of a case-vector that is absolute. */ + +#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \ + fprintf (FILE, "\tds.w L%d\n", VALUE) + +/* This is how to output an element of a case-vector that is relative. + (not used on Convex) */ + +#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, VALUE, REL) \ + fprintf (FILE, "\tds.w L%d-L%d\n", VALUE, REL) + +/* This is how to output an assembler line + that says to advance the location counter by SIZE bytes. */ + +#define ASM_OUTPUT_SKIP(FILE,SIZE) \ + fprintf (FILE, "\tds.b %u(0)\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 (".comm ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%u\n", (ROUNDED))) + +/* This says how to output an assembler line + to define a local common symbol. */ + +#define ASM_OUTPUT_LOCAL(FILE, NAME, SIZE, ROUNDED) \ +( bss_section (), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ":\tbs.b %u\n", (ROUNDED))) + +/* 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 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 + +/* Print an instruction operand X on file FILE. + CODE is the code from the %-spec that requested printing this operand; + if `%z3' was used to print operand 3, then CODE is 'z'. */ + +#define PRINT_OPERAND(FILE, X, CODE) \ +{ if (GET_CODE (X) == REG) \ + fprintf (FILE, "%s", reg_names[REGNO (X)]); \ + else if (GET_CODE (X) == MEM) \ + output_address (XEXP (X, 0)); \ + else if (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) != DImode) \ + { union { double d; int i[2]; } u; \ + u.i[0] = CONST_DOUBLE_LOW (X); u.i[1] = CONST_DOUBLE_HIGH (X); \ + fprintf (FILE, "#%.9e", u.d); } \ + else { putc ('#', FILE); output_addr_const (FILE, X); }} + +/* Print a memory operand whose address is X, on file FILE. */ + +#define PRINT_OPERAND_ADDRESS(FILE, ADDR) \ +{ \ + register rtx addr = ADDR; \ + register rtx index = 0; \ + register rtx offset = 0; \ + \ + if (GET_CODE (addr) == MEM) \ + { \ + fprintf (FILE, "@"); \ + addr = XEXP (addr, 0); \ + } \ + \ + switch (GET_CODE (addr)) \ + { \ + case REG: \ + index = addr; \ + break; \ + \ + case PLUS: \ + index = XEXP (addr, 0); \ + if (REG_P (index)) \ + offset = XEXP (addr, 1); \ + else \ + { \ + offset = XEXP (addr, 0); \ + index = XEXP (addr, 1); \ + if (! REG_P (index)) abort (); \ + } \ + break; \ + \ + default: \ + offset = addr; \ + break; \ + } \ + \ + if (offset) \ + output_addr_const (FILE, offset); \ + \ + if (index) \ + fprintf (FILE, "(%s)", reg_names[REGNO (index)]); \ +} + + diff --git a/gcc-1.40/config/tm-convex1.h b/gcc-1.40/config/tm-convex1.h new file mode 100644 index 0000000..573af46 --- /dev/null +++ b/gcc-1.40/config/tm-convex1.h @@ -0,0 +1,24 @@ +/* tm.h file for a Convex C1. */ + +#include "tm-convex.h" + +#undef TARGET_DEFAULT +#define TARGET_DEFAULT 1 + +#define CC1_SPEC "%{mc2:-mnoc1}" + +/* Include Posix prototypes unless -traditional. */ + +#define CPP_SPEC \ +"%{mc2:-D__convex_c2__}%{!mc2:-D__convex_c1__}\ + -D__NO_INLINE_MATH\ + %{!traditional:-D__stdc__ -D_POSIX_SOURCE -D_CONVEX_SOURCE}" + +/* Search Posix or else backward-compatible libraries depending + on -traditional. */ + +#define LIB_SPEC \ +"%{mc2:-lC2}%{!mc2:-lC1}\ + %{!p:%{!pg:%{traditional:-lc_old}%{!traditional:-lc}}}\ +%{p:%{traditional:-lc_old_p}%{!traditional:-lc_p}}\ +%{pg:%{traditional:-lc_old_p}%{!traditional:-lc_p}}" diff --git a/gcc-1.40/config/tm-convex2.h b/gcc-1.40/config/tm-convex2.h new file mode 100644 index 0000000..4e0307b --- /dev/null +++ b/gcc-1.40/config/tm-convex2.h @@ -0,0 +1,24 @@ +/* tm.h file for a Convex C2. */ + +#include "tm-convex.h" + +#undef TARGET_DEFAULT +#define TARGET_DEFAULT 2 + +#define CC1_SPEC "%{mc1:-mnoc2}" + +/* Include Posix prototypes unless -traditional. */ + +#define CPP_SPEC \ +"%{mc1:-D__convex_c1__}%{!mc1:-D__convex_c2__}\ + -D__NO_INLINE_MATH\ + %{!traditional:-D__stdc__ -D_POSIX_SOURCE -D_CONVEX_SOURCE}" + +/* Search Posix or else backward-compatible libraries depending + on -traditional. */ + +#define LIB_SPEC \ +"%{mc1:-lC1}%{!mc1:-lC2}\ + %{!p:%{!pg:%{traditional:-lc_old}%{!traditional:-lc}}}\ +%{p:%{traditional:-lc_old_p}%{!traditional:-lc_p}}\ +%{pg:%{traditional:-lc_old_p}%{!traditional:-lc_p}}" diff --git a/gcc-1.40/config/tm-decstatn.h b/gcc-1.40/config/tm-decstatn.h new file mode 100644 index 0000000..93fb270 --- /dev/null +++ b/gcc-1.40/config/tm-decstatn.h @@ -0,0 +1,27 @@ +/* Definitions of target machine for GNU compiler. DECstation (ultrix) version. + 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 1, 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. */ + +#define DECSTATION + +#include "tm-mips.h" + +#undef CPP_PREDEFINES +#define CPP_PREDEFINES "-D__ANSI_COMPAT \ +-D__LANGUAGE_C -D__MIPSEL -D__R3000 -D__SYSTYPE_BSD -D__bsd4_2 -D__host_mips -D__mips -D__ultrix -D__unix \ +-DLANGUAGE_C -DMIPSEL -DR3000 -DSYSTYPE_BSD -Dbsd4_2 -Dhost_mips -Dmips -Dultrix -Dunix" diff --git a/gcc-1.40/config/tm-delta68k.h b/gcc-1.40/config/tm-delta68k.h new file mode 100644 index 0000000..71c45de --- /dev/null +++ b/gcc-1.40/config/tm-delta68k.h @@ -0,0 +1,486 @@ +/* Definitions of target machine for GNU compiler. + Motorola Delta version of 680x0 for x>1 + copied and modified from 3b1 version by + Daniel R. Bidwell (bidwell@andrews.edu). + + AT&T UNIX PC version (pc7300, 3b1) + + Written by Alex Crain + bug reports to alex@umbc3.umd.edu + + Copyright (C) 1987 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 1, 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. */ + +#define SGS_3B1 + +#include "tm-hp9k320.h" + +/* See tm-m68k.h. 0 means 680[01]0 with no 68881. */ + +#undef TARGET_DEFAULT +#define TARGET_DEFAULT 7 + +/* -m68020 requires special flags to the assembler. */ + +#undef ASM_SPEC +#define ASM_SPEC "%{m68020:-68020}" + +/* we use /lib/libp/lib* when profiling */ + +#undef LIB_SPEC +#define LIB_SPEC "%{!shlib:%{p:-L/lib/libp} %{pg:-L/lib/libp} -lc}" + +/* shared libraries need to use crt0s.o */ + +#undef STARTFILE_SPEC +#define STARTFILE_SPEC \ + "%{!shlib:%{pg:mcrt0.o%s}%{!pg:%{p:mcrt0.o%s}%{!p:crt0.o%s}}}\ + %{shlib:crt0s.o%s shlib.ifile%s} " + +/* cpp has to support a #sccs directive for the /usr/include files */ + +#define SCCS_DIRECTIVE + +/* Make output for SDB. */ + +#define SDB_DEBUGGING_INFO + +/* The .file command should always begin the output. */ + +#undef ASM_FILE_START +#define ASM_FILE_START(FILE) sdbout_filename ((FILE), main_input_filename) + +/* Don't try to define `gcc_compiled.' since the assembler might not + accept symbols with periods and GDB doesn't run on this machine anyway. */ +#define ASM_IDENTIFY_GCC(FILE) + +/* Define __HAVE_68881__ in preprocessor if -m68881 is specified. + This will control the use of inline 68881 insns in certain macros. */ + +#undef CPP_SPEC +#define CPP_SPEC "%{m68881:-D__HAVE_68881__}" + +/* Names to predefine in the preprocessor for this target machine. */ +/* ihnp4!lmayk!lgm@eddie.mit.edu says mc68000 and m68k should not be here. */ + +#undef CPP_PREDEFINES +#define CPP_PREDEFINES "-Dm68k -Dmc68k -Dunix -Dunixpc" + +/* Specify how to pad function arguments. + Value should be `upward', `downward' or `none'. + Same as the default, except no padding for large or variable-size args. */ + +#define FUNCTION_ARG_PADDING(mode, size) \ + (((mode) == BLKmode \ + ? (GET_CODE (size) == CONST_INT \ + && INTVAL (size) < PARM_BOUNDARY / BITS_PER_UNIT) \ + : GET_MODE_BITSIZE (mode) < PARM_BOUNDARY) \ + ? downward : none) + +/* Override part of the obstack macros. */ + +#define __PTR_TO_INT(P) ((int)(P)) +#define __INT_TO_PTR(P) ((char *)(P)) + +/* Override parts of tm-m68k.h to fit the SGS-3b1 assembler. */ + +#undef TARGET_VERSION +#undef ASM_FORMAT_PRIVATE_NAME +#undef ASM_OUTPUT_DOUBLE +#undef ASM_OUTPUT_FLOAT +#undef ASM_OUTPUT_FLOAT_OPERAND +#undef ASM_OUTPUT_ALIGN +#undef ASM_OUTPUT_SOURCE_FILENAME +#undef ASM_OUTPUT_SOURCE_LINE +#undef PRINT_OPERAND_ADDRESS +#undef ASM_GENERATE_INTERNAL_LABEL +#undef FUNCTION_PROFILER +#undef ASM_OUTPUT_ADDR_VEC_ELT +#undef ASM_OUTPUT_ADDR_DIFF_ELT +#undef ASM_OUTPUT_INTERNAL_LABEL +#undef ASM_OUTPUT_OPCODE +#undef ASM_OUTPUT_LOCAL +#undef ASM_OUTPUT_LABELREF +#undef ASM_OUTPUT_ASCII +#undef LEGITIMATE_CONSTANT_P +#undef ASM_RETURN_CASE_JUMP + +#define TARGET_VERSION fprintf (stderr, " (68k, SGS/AT&T unixpc syntax)"); + +/* 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)) + 12), \ + sprintf ((OUTPUT), "%s_%%%d", (NAME), (LABELNO))) + +/* The unixpc doesn't know about double's and float's */ + +#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \ +do { union { double d; long l[2]; } tem; \ + tem.d = (VALUE); \ + fprintf(FILE, "\tlong 0x%x,0x%x\n", tem.l[0], tem.l[1]); \ + } while (0) + +#define ASM_OUTPUT_FLOAT(FILE,VALUE) \ +do { union { float f; long l;} tem; \ + tem.f = (VALUE); \ + fprintf (FILE, "\tlong 0x%x\n", tem.l); \ + } while (0) +/* Output a float value (represented as a C double) as an immediate operand. + This macro is a 68k-specific macro. */ +#define ASM_OUTPUT_FLOAT_OPERAND(FILE,VALUE) \ + fprintf (FILE, "#0x%.8x", (VALUE)) + +#define ASM_OUTPUT_ALIGN(FILE,LOG) \ + if ((LOG) == 1) \ + fprintf (FILE, "\teven\n"); \ + else if ((LOG) != 0) \ + abort (); + +/* The `space' pseudo in the text segment outputs nop insns rather than 0s, + so we must output 0s explicitly in the text segment. */ +#undef ASM_OUTPUT_SKIP +#define ASM_OUTPUT_SKIP(FILE,SIZE) \ + if (in_text_section ()) \ + { \ + int i; \ + for (i = 0; i < (SIZE) - 20; i += 20) \ + fprintf (FILE, "\tbyte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\n"); \ + if (i < (SIZE)) \ + { \ + fprintf (FILE, "\tbyte 0"); \ + i++; \ + for (; i < (SIZE); i++) \ + fprintf (FILE, ",0"); \ + fprintf (FILE, "\n"); \ + } \ + } \ + else \ + fprintf (FILE, "\tspace %d\n", (SIZE)) + +/* The beginnings of sdb support... */ + +#define ASM_OUTPUT_SOURCE_FILENAME(FILE, FILENAME) \ + fprintf (FILE, "\tfile\t\"%s\"\n", FILENAME) + +#define ASM_OUTPUT_SOURCE_LINE(FILE, LINENO) \ + fprintf (FILE, "\tln\t%d\n", \ + (sdb_begin_function_line \ + ? last_linenum - sdb_begin_function_line : 1)) + +/* Yet another null terminated string format. */ + +#define ASM_OUTPUT_ASCII(FILE,PTR,LEN) \ + { register int sp = 0, lp = 0; \ + fprintf (FILE, "\tbyte\t"); \ + loop: \ + if (PTR[sp] > ' ' && ! (PTR[sp] & 0x80) && PTR[sp] != '\\') \ + { lp += 3; \ + fprintf (FILE, "'%c", PTR[sp]); } \ + else \ + { lp += 5; \ + fprintf (FILE, "0x%x", PTR[sp]); } \ + if (++sp < LEN) \ + { if (lp > 60) \ + { lp = 0; \ + fprintf (FILE, "\n%s ", ASCII_DATA_ASM_OP); } \ + else \ + putc (',', FILE); \ + goto loop; } \ + putc ('\n', FILE); } + +/* Note that in the case of the movhi which fetches an element of + an ADDR_DIFF_VEC the offset output is too large by 2. + This is because the 3b1 assembler refuses to subtract 2. + ASM_OUTPUT_CASE_LABEL, below, compensates for this. */ + +#define PRINT_OPERAND_ADDRESS(FILE, ADDR) \ +{ register rtx reg1, reg2, breg, ireg; \ + register rtx addr = ADDR; \ + rtx offset; \ + switch (GET_CODE (addr)) \ + { \ + case REG: \ + fprintf (FILE, "(%s)", reg_names[REGNO (addr)]); \ + break; \ + case PRE_DEC: \ + fprintf (FILE, "-(%s)", reg_names[REGNO (XEXP (addr, 0))]); \ + break; \ + case POST_INC: \ + fprintf (FILE, "(%s)+", reg_names[REGNO (XEXP (addr, 0))]); \ + break; \ + case PLUS: \ + reg1 = 0; reg2 = 0; \ + ireg = 0; breg = 0; \ + offset = 0; \ + if (CONSTANT_ADDRESS_P (XEXP (addr, 0))) \ + { \ + offset = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (CONSTANT_ADDRESS_P (XEXP (addr, 1))) \ + { \ + offset = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + if (GET_CODE (addr) != PLUS) ; \ + else if (GET_CODE (XEXP (addr, 0)) == SIGN_EXTEND) \ + { \ + reg1 = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (GET_CODE (XEXP (addr, 1)) == SIGN_EXTEND) \ + { \ + reg1 = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + else if (GET_CODE (XEXP (addr, 0)) == MULT) \ + { \ + reg1 = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (GET_CODE (XEXP (addr, 1)) == MULT) \ + { \ + reg1 = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + else if (GET_CODE (XEXP (addr, 0)) == REG) \ + { \ + reg1 = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (GET_CODE (XEXP (addr, 1)) == REG) \ + { \ + reg1 = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + if (GET_CODE (addr) == REG || GET_CODE (addr) == MULT \ + || GET_CODE (addr) == SIGN_EXTEND) \ + { if (reg1 == 0) reg1 = addr; else reg2 = addr; addr = 0; } \ +/* for OLD_INDEXING \ + else if (GET_CODE (addr) == PLUS) \ + { \ + if (GET_CODE (XEXP (addr, 0)) == REG) \ + { \ + reg2 = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (GET_CODE (XEXP (addr, 1)) == REG) \ + { \ + reg2 = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + } \ + */ \ + if (offset != 0) { if (addr != 0) abort (); addr = offset; } \ + if ((reg1 && (GET_CODE (reg1) == SIGN_EXTEND \ + || GET_CODE (reg1) == MULT)) \ + || (reg2 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg2)))) \ + { breg = reg2; ireg = reg1; } \ + else if (reg1 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg1))) \ + { breg = reg1; ireg = reg2; } \ + if (ireg != 0 && breg == 0 && GET_CODE (addr) == LABEL_REF) \ + { int scale = 1; \ + if (GET_CODE (ireg) == MULT) \ + { scale = INTVAL (XEXP (ireg, 1)); \ + ireg = XEXP (ireg, 0); } \ + if (GET_CODE (ireg) == SIGN_EXTEND) \ + fprintf (FILE, "(L%%%d,%s.w", \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + reg_names[REGNO (XEXP (ireg, 0))]); \ + else \ + fprintf (FILE, "(L%%%d,%s.l", \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + reg_names[REGNO (ireg)]); \ + if (scale != 1) fprintf (FILE, "*%d", scale); \ + fprintf (FILE, ")"); \ + break; } \ + if (breg != 0 && ireg == 0 && GET_CODE (addr) == LABEL_REF) \ + { fprintf (FILE, "(L%%%d,%s.l", \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + reg_names[REGNO (breg)]); \ + putc (')', FILE); \ + break; } \ + if (ireg != 0 || breg != 0) \ + { int scale = 1; \ + if (breg == 0) \ + abort (); \ + if (addr != 0) \ + output_addr_const (FILE, addr); \ + fprintf (FILE, "(%s", reg_names[REGNO (breg)]); \ + if (ireg != 0) \ + putc (',', FILE); \ + if (ireg != 0 && GET_CODE (ireg) == MULT) \ + { scale = INTVAL (XEXP (ireg, 1)); \ + ireg = XEXP (ireg, 0); } \ + if (ireg != 0 && GET_CODE (ireg) == SIGN_EXTEND) \ + fprintf (FILE, "%s.w", reg_names[REGNO (XEXP (ireg, 0))]); \ + else if (ireg != 0) \ + fprintf (FILE, "%s.l", reg_names[REGNO (ireg)]); \ + if (scale != 1) fprintf (FILE, "*%d", scale); \ + putc (')', FILE); \ + break; \ + } \ + else if (reg1 != 0 && GET_CODE (addr) == LABEL_REF) \ + { fprintf (FILE, "L%%%d(%%pc,%s.w)", \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + reg_names[REGNO (reg1)]); \ + break; } \ + default: \ + if (GET_CODE (addr) == CONST_INT \ + && INTVAL (addr) < 0x8000 \ + && INTVAL (addr) >= -0x8000) \ + fprintf (FILE, "%d", INTVAL (addr)); \ + else \ + output_addr_const (FILE, addr); \ + }} + +#define ASM_GENERATE_INTERNAL_LABEL(LABEL, PREFIX, NUM) \ + sprintf ((LABEL), "%s%%%d", (PREFIX), (NUM)) + +#define ASM_OUTPUT_INTERNAL_LABEL(FILE,PREFIX,NUM) \ + fprintf (FILE, "%s%%%d:\n", PREFIX, NUM) + +/* Must put address in %a0 , not %d0 . -- LGM, 7/15/88 */ +#define FUNCTION_PROFILER(FILE, LABEL_NO) \ + fprintf (FILE, "\tmov.l &LP%%%d,%%a0\n\tjsr mcount\n", (LABEL_NO)) + +#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \ + fprintf (FILE, "\tlong L%%%d\n", (VALUE)) + +#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, VALUE, REL) \ + fprintf (FILE, "\tshort L%%%d-L%%%d\n", (VALUE), (REL)) + +/* ihnp4!lmayk!lgm says that `short 0' triggers assembler bug; + `short L%nn-L%nn' supposedly works. */ +#define ASM_OUTPUT_CASE_LABEL(FILE,PREFIX,NUM,TABLE) \ + fprintf (FILE, "\tswbeg &%d\n%s%%%d:\n", \ + XVECLEN (PATTERN (TABLE), 1), (PREFIX), (NUM)); + +/* At end of a switch table, define LD%n iff the symbol LI%n was defined. */ +#define ASM_OUTPUT_CASE_END(FILE,NUM,TABLE) \ + if (RTX_INTEGRATED_P (TABLE)) \ + fprintf (FILE, "\tset LD%%%d,L%%%d-LI%%%d\n", (NUM), (NUM), (NUM)) + +#define ASM_OUTPUT_OPCODE(FILE, PTR) \ +{ if ((PTR)[0] == 'j' && (PTR)[1] == 'b') \ + { ++(PTR); \ + while (*(PTR) != ' ') \ + { putc (*(PTR), (FILE)); ++(PTR); } \ + fprintf ((FILE), ".w"); } \ + else if ((PTR)[0] == 'f') \ + { \ + if (!strncmp ((PTR), "fmove", 5)) \ + { fprintf ((FILE), "fmov"); (PTR) += 5; } \ + else if (!strncmp ((PTR), "ftst", 4)) \ + { fprintf ((FILE), "ftest"); (PTR) += 4; } \ + else if (!strncmp ((PTR), "fbne", 4)) \ + { fprintf ((FILE), "fbgl"); (PTR) += 4; } \ + else if (!strncmp ((PTR), "fbeq", 4)) \ + { fprintf ((FILE), "fbngl"); (PTR) += 4; } \ + } \ +/* MOVE, MOVEA, MOVEQ, MOVEC ==> MOV */ \ + else if ((PTR)[0] == 'm' && (PTR)[1] == 'o' \ + && (PTR)[2] == 'v' && (PTR)[3] == 'e') \ + { fprintf ((FILE), "mov"); (PTR) += 4; \ + if ((PTR)[0] == 'q' || (PTR)[0] == 'a' || \ + (PTR)[0] == 'c') (PTR)++; } \ +/* SUB, SUBQ, SUBA, SUBI ==> SUB */ \ + else if ((PTR)[0] == 's' && (PTR)[1] == 'u' \ + && (PTR)[2] == 'b') \ + { fprintf ((FILE), "sub"); (PTR) += 3; \ + if ((PTR)[0] == 'q' || (PTR)[0] == 'i' || \ + (PTR)[0] == 'a') (PTR)++; } \ +/* CMP, CMPA, CMPI, CMPM ==> CMP */ \ + else if ((PTR)[0] == 'c' && (PTR)[1] == 'm' \ + && (PTR)[2] == 'p') \ + { fprintf ((FILE), "cmp"); (PTR) += 3; \ + if ((PTR)[0] == 'a' || (PTR)[0] == 'i' || \ + (PTR)[0] == 'm') (PTR)++; } \ +} + +#define ASM_OUTPUT_LOCAL(FILE, NAME, SIZE, ROUNDED) \ +( fputs ("\tlcomm ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%d\n", (ROUNDED))) + +#define ASM_OUTPUT_LABELREF(FILE,NAME) \ + fprintf (FILE, "%s", NAME) + +/* Override usual definitions of SDB output macros. + These definitions differ only in the absence of the period + at the beginning of the name of the directive + and in the use of `~' as the symbol for the current location. */ + +#define PUT_SDB_SCL(a) fprintf(asm_out_file, "\tscl\t%d;", (a)) +#define PUT_SDB_INT_VAL(a) fprintf (asm_out_file, "\tval\t%d;", (a)) +#define PUT_SDB_VAL(a) \ +( fputs ("\tval\t", asm_out_file), \ + output_addr_const (asm_out_file, (a)), \ + fputc (';', asm_out_file)) + +#define PUT_SDB_DEF(a) \ +do { fprintf (asm_out_file, "\tdef\t"); \ + ASM_OUTPUT_LABELREF (asm_out_file, a); \ + fprintf (asm_out_file, ";"); } while (0) + +#define PUT_SDB_PLAIN_DEF(a) fprintf(asm_out_file,"\tdef\t~%s;",a) +#define PUT_SDB_ENDEF fputs("\tendef\n", asm_out_file) +#define PUT_SDB_TYPE(a) fprintf(asm_out_file, "\ttype\t0%o;", a) +#define PUT_SDB_SIZE(a) fprintf(asm_out_file, "\tsize\t%d;", a) +#define PUT_SDB_DIM(a) fprintf(asm_out_file, "\tdim\t%d;", a) + +#define PUT_SDB_TAG(a) \ +do { fprintf (asm_out_file, "\ttag\t"); \ + ASM_OUTPUT_LABELREF (asm_out_file, a); \ + fprintf (asm_out_file, ";"); } while (0) + +#define PUT_SDB_BLOCK_START(LINE) \ + fprintf (asm_out_file, \ + "\tdef\t~bb;\tval\t~;\tscl\t100;\tline\t%d;\tendef\n", \ + (LINE)) + +#define PUT_SDB_BLOCK_END(LINE) \ + fprintf (asm_out_file, \ + "\tdef\t~eb;\tval\t~;\tscl\t100;\tline\t%d;\tendef\n", \ + (LINE)) + +#define PUT_SDB_FUNCTION_START(LINE) \ + fprintf (asm_out_file, \ + "\tdef\t~bf;\tval\t~;\tscl\t101;\tline\t%d;\tendef\n", \ + (LINE)) + +#define PUT_SDB_FUNCTION_END(LINE) \ + fprintf (asm_out_file, \ + "\tdef\t~ef;\tval\t~;\tscl\t101;\tline\t%d;\tendef\n", \ + (LINE)) + +#define PUT_SDB_EPILOGUE_END(NAME) \ + fprintf (asm_out_file, \ + "\tdef\t%s;\tval\t~;\tscl\t-1;\tendef\n", \ + (NAME)) + +#define SDB_GENERATE_FAKE(BUFFER, NUMBER) \ + sprintf ((BUFFER), "~%dfake", (NUMBER)); + +#define LEGITIMATE_CONSTANT_P(X) (GET_CODE(X)==CONST_DOUBLE?0:1) + +#define ASM_RETURN_CASE_JUMP return "jmp (%0.w,%a1)" + diff --git a/gcc-1.40/config/tm-encore.h b/gcc-1.40/config/tm-encore.h new file mode 100644 index 0000000..cdf326c --- /dev/null +++ b/gcc-1.40/config/tm-encore.h @@ -0,0 +1,202 @@ +/* Definitions of target machine for GNU compiler. ENCORE NS32000 version. + Copyright (C) 1988 Free Software Foundation, Inc. + Adapted by Robert Brown (brown@harvard.harvard.edu) from the Sequent + version by Michael Tiemann (tiemann@mcc.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 1, 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. */ + + +/* + * Looks like all multiprocessors have this bug! + */ + +#define SEQUENT_ADDRESS_BUG 1 + +#include "tm-ns32k.h" + +#define SDB_DEBUGGING_INFO +#undef DBX_REGISTER_NUMBER +#define DBX_REGISTER_NUMBER(REGNO) (REGNO) + +/* Cause long-jump assembler to be used, + since otherwise some files fail to be assembled right. */ +#define ASM_SPEC "-j" + +#undef ASM_FILE_START +#undef ASM_GENERATE_INTERNAL_LABEL +#undef ASM_OUTPUT_ADDR_DIFF_ELT +#undef ASM_OUTPUT_ALIGN +#undef ASM_OUTPUT_ASCII +#undef ASM_OUTPUT_DOUBLE +#undef ASM_OUTPUT_INT +#undef ASM_OUTPUT_INTERNAL_LABEL +#undef ASM_OUTPUT_LOCAL +#undef CPP_PREDEFINES +#undef FUNCTION_BOUNDARY +#undef PRINT_OPERAND +#undef PRINT_OPERAND_ADDRESS +#undef TARGET_VERSION +#undef FUNCTION_PROFILER + + +#define TARGET_DEFAULT 1 +#define TARGET_VERSION fprintf (stderr, " (32000, Encore syntax)"); +/* Note Encore does not standardly do -Dencore. */ +/* budd: should have a -ns32332 (or -apc) switch! but no harm for now */ +#define CPP_PREDEFINES "-Dns32000 -Dn16 -Dns16000 -Dns32332 -Dunix" + +/* Ignore certain cpp directives used in header files on sysV. */ +#define SCCS_DIRECTIVE + +/* Output #ident as a .ident. */ +#define ASM_OUTPUT_IDENT(FILE, NAME) fprintf (FILE, "\t.ident \"%s\"\n", NAME); + +/* The .file command should always begin the output. */ +#define ASM_FILE_START(FILE) sdbout_filename ((FILE), main_input_filename) + +#define FUNCTION_BOUNDARY 128 /* speed optimization */ + +/* + * The Encore assembler uses ".align 2" to align on 2-byte boundaries. + */ + +#define ASM_OUTPUT_ALIGN(FILE,LOG) \ + fprintf (FILE, "\t.align %d\n", 1 << (LOG)) + +/* + * Internal labels are prefixed with a period. + */ + +#define ASM_GENERATE_INTERNAL_LABEL(LABEL,PREFIX,NUM) \ + sprintf (LABEL, "*.%s%d", PREFIX, NUM) +#define ASM_OUTPUT_INTERNAL_LABEL(FILE,PREFIX,NUM) \ + fprintf (FILE, ".%s%d:\n", PREFIX, NUM) +#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, VALUE, REL) \ + fprintf (FILE, "\t.word .L%d-.LI%d\n", VALUE, REL) + +/* + * Different syntax for integer constants, double constants, and + * uninitialized locals. + */ + +#define ASM_OUTPUT_INT(FILE,VALUE) \ +( fprintf (FILE, "\t.double "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \ + fprintf (FILE, "\t.long 0f%.20e\n", (VALUE)) + +#define ASM_OUTPUT_LOCAL(FILE, NAME, SIZE, ROUNDED) \ +( fputs ("\t.bss ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%u,%u\n", (SIZE), (ROUNDED))) + + /* + * Encore assembler can't handle huge string constants like the one in + * gcc.c. If the default routine in varasm.c were more conservative, this + * code could be eliminated. It starts a new .ascii directive every 40 + * characters. + */ + +#define ASM_OUTPUT_ASCII(file, p, size) \ +{ \ + for (i = 0; i < size; i++) \ + { \ + register int c = p[i]; \ + if ((i / 40) * 40 == i) \ + if (i == 0) \ + fprintf (file, "\t.ascii \""); \ + else \ + fprintf (file, "\"\n\t.ascii \""); \ + if (c == '\"' || c == '\\') \ + putc ('\\', file); \ + if (c >= ' ' && c < 0177) \ + putc (c, file); \ + else \ + { \ + fprintf (file, "\\%o", c); \ + if (i < size - 1 \ + && p[i + 1] >= '0' && p[i + 1] <= '9') \ + fprintf (file, "\"\n\t.ascii \""); \ + } \ + } \ + fprintf (file, "\"\n"); \ +} + + /* + * Dollar signs are required before immediate operands, double + * floating point constants use $0f syntax, and external addresses + * should be prefixed with a question mark to avoid assembler warnings + * about undefined symbols. + */ + +#define PRINT_OPERAND(FILE, X, CODE) \ +{ if (CODE == '$') putc ('$', FILE); \ + else if (CODE == '?') fputc ('?', FILE); \ + else if (GET_CODE (X) == REG) \ + fprintf (FILE, "%s", reg_names[REGNO (X)]); \ + else if (GET_CODE (X) == MEM) \ + { \ + rtx xfoo; \ + xfoo = XEXP (X, 0); \ + switch (GET_CODE (xfoo)) \ + { \ + case MEM: \ + if (GET_CODE (XEXP (xfoo, 0)) == REG) \ + if (REGNO (XEXP (xfoo, 0)) == STACK_POINTER_REGNUM) \ + fprintf (FILE, "0(0(sp))"); \ + else fprintf (FILE, "0(0(%s))", \ + reg_names[REGNO (XEXP (xfoo, 0))]); \ + else \ + { \ + fprintf (FILE, "0("); \ + output_address (xfoo); \ + putc (')', FILE); \ + } \ + break; \ + case REG: \ + fprintf (FILE, "0(%s)", reg_names[REGNO (xfoo)]); \ + break; \ + case PRE_DEC: \ + case POST_INC: \ + fprintf (FILE, "tos"); \ + break; \ + case CONST_INT: \ + fprintf (FILE, "@%d", INTVAL (xfoo)); \ + break; \ + default: \ + output_address (xfoo); \ + break; \ + } \ + } \ + else if (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) != DImode) \ + if (GET_MODE (X) == DFmode) \ + { union { double d; int i[2]; } u; \ + u.i[0] = CONST_DOUBLE_LOW (X); u.i[1] = CONST_DOUBLE_HIGH (X); \ + fprintf (FILE, "$0f%.20e", u.d); } \ + else { union { double d; int i[2]; } u; \ + u.i[0] = CONST_DOUBLE_LOW (X); u.i[1] = CONST_DOUBLE_HIGH (X); \ + fprintf (FILE, "$0f%.20e", u.d); } \ + else if (GET_CODE (X) == CONST) \ + output_addr_const (FILE, X); \ + else { putc ('$', FILE); output_addr_const (FILE, X); }} + +#define PRINT_OPERAND_ADDRESS(FILE, ADDR) print_operand_address(FILE, ADDR) + +#define FUNCTION_PROFILER(FILE, LABELNO) \ + fprintf (FILE, "\taddr .LP%d,r0\n\tjsr mcount\n", (LABELNO)) diff --git a/gcc-1.40/config/tm-genix.h b/gcc-1.40/config/tm-genix.h new file mode 100644 index 0000000..db4682e --- /dev/null +++ b/gcc-1.40/config/tm-genix.h @@ -0,0 +1,163 @@ +/* Definitions of target machine for GNU compiler. Genix ns32000 version. + Copyright (C) 1987, 1988 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 1, 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 "tm-encore.h" + +/* We don't want the one Encore needs. */ +#undef ASM_SPEC + +/* The following defines override ones in tm-ns32k.h and prevent any attempts + to explicitly or implicitly make references to the SB register in the GCC + generated code. It is necessary to avoid such references under Genix V.3.1 + because this OS doesn't even save/restore the SB on context switches! */ + +#define IS_OK_REG_FOR_BASE_P(X) \ + ( (GET_CODE (X) == REG) && REG_OK_FOR_BASE_P (X) ) + +#undef INDIRECTABLE_1_ADDRESS_P +#define INDIRECTABLE_1_ADDRESS_P(X) \ + (CONSTANT_ADDRESS_NO_LABEL_P (X) \ + || IS_OK_REG_FOR_BASE_P (X) \ + || (GET_CODE (X) == PLUS \ + && IS_OK_REG_FOR_BASE_P (XEXP (X, 0)) \ + && CONSTANT_ADDRESS_P (XEXP (X, 1)) ) ) + +/* Note that for double indirects, only FP, SP, and SB are allowed + as the inner-most base register. But we are avoiding use of SB. */ + +#undef MEM_REG +#define MEM_REG(X) \ + ( (GET_CODE (X) == REG) \ + && ( (REGNO (X) == FRAME_POINTER_REGNUM) \ + || (REGNO (X) == STACK_POINTER_REGNUM) ) ) + +#undef INDIRECTABLE_2_ADDRESS_P +#define INDIRECTABLE_2_ADDRESS_P(X) \ + (GET_CODE (X) == MEM \ + && (((xfoo0 = XEXP (X, 0), MEM_REG (xfoo0)) \ + || (GET_CODE (xfoo0) == PLUS \ + && MEM_REG (XEXP (xfoo0, 0)) \ + && CONSTANT_ADDRESS_NO_LABEL_P (XEXP (xfoo0, 1)))) \ + || CONSTANT_ADDRESS_NO_LABEL_P (xfoo0))) + +/* Go to ADDR if X is a valid address not using indexing. + (This much is the easy part.) */ +#undef GO_IF_NONINDEXED_ADDRESS +#define GO_IF_NONINDEXED_ADDRESS(X, ADDR) \ +{ register rtx xfoob = (X); \ + if (GET_CODE (xfoob) == REG) goto ADDR; \ + if (INDIRECTABLE_1_ADDRESS_P(X)) goto ADDR; \ + if (CONSTANT_P(X)) goto ADDR; \ + if (INDIRECTABLE_2_ADDRESS_P (X)) goto ADDR; \ + if (GET_CODE (X) == PLUS) \ + if (CONSTANT_ADDRESS_NO_LABEL_P (XEXP (X, 1))) \ + if (INDIRECTABLE_2_ADDRESS_P (XEXP (X, 0))) \ + goto ADDR; \ +} + +/* A bug in the GNX 3.X assembler causes references to external symbols to + be mishandled if the symbol is also used as the name of a function-local + variable or as the name of a struct or union field. The problem only + appears when you are also using the -g option so that SDB debugging + directives are also being produced by GCC. In such cases, the assembler + gets the external entity confused with the local entity and addressing + havoc ensues. The solution is to get GCC to produce .global directives + for all external entities which are actually referenced within the current + source file. The following macro does this. */ + +#define ASM_OUTPUT_EXTERNAL(FILE, DECL, NAME) \ + ASM_GLOBALIZE_LABEL(FILE,NAME); + +/* Genix wants 0l instead of 0f. */ + +#undef ASM_OUTPUT_DOUBLE +#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \ + fprintf (FILE, "\t.long 0l%.20e\n", (VALUE)) + +/* A bug in the GNX 3.X linker prevents symbol-table entries with a storage- + class field of C_EFCN (-1) from being accepted. */ + +#ifdef PUT_SDB_EPILOGUE_END +#undef PUT_SDB_EPILOGUE_END +#endif +#define PUT_SDB_EPILOGUE_END(NAME) + +#undef TARGET_VERSION +#define TARGET_VERSION fprintf (stderr, " (32000, National syntax)"); + +/* Same as the tm-encore definition except + * Different syntax for double constants. + * Don't output `?' before external regs. + * Output `(sb)' in certain indirect refs. */ + +#undef PRINT_OPERAND +#define PRINT_OPERAND(FILE, X, CODE) \ +{ if (CODE == '$') putc ('$', FILE); \ + else if (CODE == '?'); \ + else if (GET_CODE (X) == REG) \ + fprintf (FILE, "%s", reg_names[REGNO (X)]); \ + else if (GET_CODE (X) == MEM) \ + { \ + rtx xfoo; \ + xfoo = XEXP (X, 0); \ + switch (GET_CODE (xfoo)) \ + { \ + case MEM: \ + if (GET_CODE (XEXP (xfoo, 0)) == REG) \ + if (REGNO (XEXP (xfoo, 0)) == STACK_POINTER_REGNUM) \ + fprintf (FILE, "0(0(sp))"); \ + else fprintf (FILE, "0(0(%s))", \ + reg_names[REGNO (XEXP (xfoo, 0))]); \ + else \ + { \ + extern int paren_base_reg_printed; \ + fprintf (FILE, "0("); \ + paren_base_reg_printed = 0; \ + output_address (xfoo); \ + if (!paren_base_reg_printed) \ + fprintf (FILE, "(sb)"); \ + putc (')', FILE); \ + } \ + break; \ + case REG: \ + fprintf (FILE, "0(%s)", reg_names[REGNO (xfoo)]); \ + break; \ + case PRE_DEC: \ + case POST_INC: \ + fprintf (FILE, "tos"); \ + break; \ + case CONST_INT: \ + fprintf (FILE, "@%d", INTVAL (xfoo)); \ + break; \ + default: \ + output_address (xfoo); \ + break; \ + } \ + } \ + else if (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) != DImode) \ + if (GET_MODE (X) == DFmode) \ + { union { double d; int i[2]; } u; \ + u.i[0] = CONST_DOUBLE_LOW (X); u.i[1] = CONST_DOUBLE_HIGH (X); \ + fprintf (FILE, "$0l%.20e", u.d); } \ + else { union { double d; int i[2]; } u; \ + u.i[0] = CONST_DOUBLE_LOW (X); u.i[1] = CONST_DOUBLE_HIGH (X); \ + fprintf (FILE, "$0f%.20e", u.d); } \ + else if (GET_CODE (X) == CONST) \ + output_addr_const (FILE, X); \ + else { putc ('$', FILE); output_addr_const (FILE, X); }} diff --git a/gcc-1.40/config/tm-harris.h b/gcc-1.40/config/tm-harris.h new file mode 100644 index 0000000..a06f001 --- /dev/null +++ b/gcc-1.40/config/tm-harris.h @@ -0,0 +1,96 @@ +/* Definitions of target machine for GNU compiler. Harris tahoe version. + Copyright (C) 1989 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 1, 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 "tm-tahoe.h" + +#undef CPP_PREDEFINES +#define CPP_PREDEFINES "-Dtahoe -Dunix -Dhcx" + +#undef DBX_DEBUGGING_INFO +#define SDB_DEBUGGING_INFO + +#undef TARGET_DEFAULT +#define TARGET_DEFAULT 1 + +/* urem and udiv don't exist on this system. */ +#undef UDIVSI3_LIBCALL +#undef UMODSI3_LIBCALL + +/* start the assembly by turning off APP. For the Harris (if not, + apparently, for the Tahoe) we want a .file directive as well. */ + +#undef ASM_FILE_START +#define ASM_FILE_START(FILE) \ + do { \ + int len = strlen (dump_base_name); \ + char *na = dump_base_name + len; \ + /* NA gets DUMP_BASE_NAME sans directory names. */ \ + while (na > dump_base_name) \ + { \ + if (na[-1] == '/') \ + break; \ + na--; \ + } \ + fprintf (FILE, "#NO_APP\n\n"); \ + fprintf (FILE, "\t.file\t\"%s\"\n", na); \ + } while (0) + +/* Operand of .align is not logarithmic. */ +#undef ASM_OUTPUT_ALIGN +#define ASM_OUTPUT_ALIGN(FILE,LOG) \ + LOG ? fprintf (FILE, "\t.align %d\n", 1 << (LOG)) : 0 + +/* For the same reason, we need .align 2 after casesi. */ +#undef PRINT_OPERAND +#define PRINT_OPERAND(FILE, X, CODE) \ +{ if (CODE == '@') \ + putc ('2', FILE); \ + else if (GET_CODE (X) == REG) \ + fprintf (FILE, "%s", reg_names[REGNO (X)]); \ + else if (GET_CODE (X) == MEM) \ + output_address (XEXP (X, 0)); \ + else { putc ('$', FILE); output_addr_const (FILE, X); }} + +#undef ASM_OUTPUT_LOCAL +#define ASM_OUTPUT_LOCAL(FILE, NAME, SIZE, ROUNDED) \ +( fputs (".bss ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%u,4\n", (ROUNDED))) + +#define ASM_OUTPUT_ASCII(FILE, PTR, SIZE) \ +{ \ + unsigned char *_p = (PTR); \ + int _thissize = (SIZE); \ + fprintf ((FILE), "\t.ascii \""); \ + for (i = 0; i < _thissize; i++) \ + { \ + register int c = _p[i]; \ + if (c >= ' ' && c < 0177 && c != '\"' && c != '\\') \ + putc (c, (FILE)); \ + else \ + { \ + fprintf ((FILE), "\\%o", c); \ + if (i < _thissize - 1 \ + && _p[i + 1] >= '0' && _p[i + 1] <= '9') \ + fprintf ((FILE), "\"\n\t.ascii \""); \ + } \ + } \ + fprintf ((FILE), "\"\n"); \ +} diff --git a/gcc-1.40/config/tm-hp9k2bsd.h b/gcc-1.40/config/tm-hp9k2bsd.h new file mode 100644 index 0000000..3793e52 --- /dev/null +++ b/gcc-1.40/config/tm-hp9k2bsd.h @@ -0,0 +1,53 @@ +/* Definitions of target machine for GNU compiler. HP 9000/200 68000 version. + Copyright (C) 1987 - 1991 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 1, 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 "tm-m68k.h" + +/* See tm-m68k.h. 0 means 68000 with no 68881. */ + +#define TARGET_DEFAULT -0102 + +/* Define __HAVE_68881 in preprocessor only if -m68881 is specified. + This will control the use of inline 68881 insns in certain macros. + Also inform the program which CPU this is for. */ + +#define CPP_SPEC "%{m68881:-D__HAVE_68881__} \ +%{!ansi:%{m68020:-Dmc68020}%{mc68020:-Dmc68020}%{!mc68020:%{!m68020:-Dmc68010}}}" + +/* -m68020 requires special flags to the assembler. */ + +#define ASM_SPEC \ + "%{m68020:-mc68020}%{mc68020:-mc68020}%{!mc68020:%{!m68020:-mc68010}}" + +/* Names to predefine in the preprocessor for this target machine. */ + +#define CPP_PREDEFINES "-Dmc68000 -Dmc68010 -Dhp200 -Dunix" + +/* Alignment of field after `int : 0' in a structure. */ + +#undef EMPTY_FIELD_BOUNDARY +#define EMPTY_FIELD_BOUNDARY 16 + +/* Every structure or union's size must be a multiple of 2 bytes. */ + +#define STRUCTURE_SIZE_BOUNDARY 16 + +/* This is BSD, so it wants DBX format. */ + +#define DBX_DEBUGGING_INFO diff --git a/gcc-1.40/config/tm-hp9k310.h b/gcc-1.40/config/tm-hp9k310.h new file mode 100644 index 0000000..806aed5 --- /dev/null +++ b/gcc-1.40/config/tm-hp9k310.h @@ -0,0 +1,32 @@ +/* Definitions of target machine for GNU compiler. HP-UX 68010 version. */ + +/* See tm-m68k.h. 0 means 68000 without 68881 and no bitfields. */ +#define TARGET_DEFAULT 0 + +#include "tm-hp9k320.h" + +#undef CPP_SPEC +#undef ASM_SPEC + +/* HP does not support a 68020 without a 68881 or a 68010 with a 68881. + However, -m68020 does not imply -m68881. You must specify both + if you want both. */ + +#ifdef HPUX_ASM + +#define CPP_SPEC "-D__HPUX_ASM__ %{m68881: -D__HAVE_68881__}\ +%{m68020: -Dmc68020}%{mc68020: -Dmc68020}\ +%{!traditional:-D_INCLUDE__STDC__}" + +#define ASM_SPEC "%{!m68020:%{!mc68020:+X}}" + +#else /* not HPUX_ASM */ + +#define CPP_SPEC "%{m68881: -D__HAVE_68881__}\ +%{m68020: -Dmc68020}%{mc68020: -Dmc68020}\ +%{!traditional:-D_INCLUDE__STDC__}" + +#define ASM_SPEC \ + "%{m68000:-mc68000}%{mc68000:-mc68000}%{!mc68000:%{!m68000:-mc68020}}" + +#endif /* not HPUX_ASM */ diff --git a/gcc-1.40/config/tm-hp9k310g.h b/gcc-1.40/config/tm-hp9k310g.h new file mode 100644 index 0000000..d1e982b --- /dev/null +++ b/gcc-1.40/config/tm-hp9k310g.h @@ -0,0 +1,12 @@ +/* Definitions of target machine for GNU compiler. HP-UX 68000/68020 version. + Use this file if GCC is supposed to work with the GNU assembler, + GNU linker and GNU debugger using DBX debugging information. + (In other words, much of HPUX has been cast aside.) */ + +/* This wants DBX format. */ + +#define DBX_DEBUGGING_INFO + +#define USE_GAS + +#include "tm-hp9k310.h" diff --git a/gcc-1.40/config/tm-hp9k320.h b/gcc-1.40/config/tm-hp9k320.h new file mode 100644 index 0000000..4991007 --- /dev/null +++ b/gcc-1.40/config/tm-hp9k320.h @@ -0,0 +1,598 @@ +/* Definitions of target machine for GNU compiler. HP-UX 68000/68020 version. + Copyright (C) 1987, 1988 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 1, 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. */ + +/* Define USE_GAS if GCC is supposed to work with the GNU assembler, + GNU linker and GNU debugger using DBX debugging information. + (In other words, much of HPUX has been cast aside.) + Undefine USE_GAS if you want GCC to feed the HP assembler. */ + +/* #define USE_GAS */ /* Use tm-hp9k320g.h if you want this. */ + +/* Control assembler-syntax conditionals in m68k.md. */ + +#ifndef USE_GAS +#define MOTOROLA +#define SGS +#define HPUX_ASM +#endif + +#include "tm-m68k.h" + +/* See tm-m68k.h. 7 means 68020 with 68881. */ + +#ifndef TARGET_DEFAULT +#define TARGET_DEFAULT 7 +#endif + +/* Define __HAVE_68881__ in preprocessor, unless -msoft-float is specified. + This will control the use of inline 68881 insns in certain macros. */ + +/* For version 6.2 of HP-UX (or earlier), remove the "-V 3" from + ASM_SPEC below. */ + +#ifdef HPUX_ASM + +/* "-V 3" says that setjmp and longjmp need to save the fpu regs. */ + +#define ASM_SPEC "%{m68000:+X} -V 3" + +#if TARGET_DEFAULT & 02 /* -m68881 is the default */ + +/* These definitions differ from those used for GAS by defining __HPUX_ASM__. + This is needed because some programs, particularly GDB, need to + know which assembler is being used so that the correct `asm' + instructions can be used. */ + +#define CPP_SPEC \ +"%{!msoft-float:-D__HAVE_68881__ }\ +%{!ansi:%{!mc68000:%{!m68000:-Dmc68020}}} -D__HPUX_ASM__\ + -D_HPUX_SOURCE -D__hp9000s300 -D__hp9000s200 -D__PWB -D__hpux -D__unix" + +#else /* default is -msoft-float */ + +#define CPP_SPEC \ +"%{m68881:-D__HAVE_68881__ }\ +%{!ansi:%{!mc68000:%{!m68000:-Dmc68020}}} -D__HPUX_ASM__\ + -D_HPUX_SOURCE -D__hp9000s300 -D__hp9000s200 -D__PWB -D__hpux -D__unix" + +#endif /* default is -msoft-float */ + +#else /* not HPUX_ASM */ + +#if TARGET_DEFAULT & 02 /* -m68881 is the default */ + +#define CPP_SPEC \ +"%{!msoft-float:-D__HAVE_68881__ }\ +%{!ansi:%{!mc68000:%{!m68000:-Dmc68020}}}\ + -D_HPUX_SOURCE -D__hp9000s300 -D__hp9000s200 -D__PWB -D__hpux -D__unix" + +#else /* default is -msoft-float */ + +#define CPP_SPEC \ +"%{m68881:-D__HAVE_68881__ }\ +%{!ansi:%{!mc68000:%{!m68000:-Dmc68020}}}\ + -D_HPUX_SOURCE -D__hp9000s300 -D__hp9000s200 -D__PWB -D__hpux -D__unix" + +#endif /* default is -msoft-float */ + + +/* -m68000 requires special flags to the assembler. */ +#define ASM_SPEC \ + "%{m68000:-mc68000}%{mc68000:-mc68000}%{!mc68000:%{!m68000:-mc68020}}" + +/* special directory for gnu libs on hp-ux system */ +#undef STANDARD_STARTFILE_PREFIX +#define STANDARD_STARTFILE_PREFIX "/usr/local/lib/gnu/" + +#endif /* Not HPUX_ASM */ + +/* Names to predefine in the preprocessor for this target machine + (for non-strict-ANSI programs only). */ +/* These are the ones defined by HPUX cc, plus mc68000 for uniformity with + GCC on other 68000 systems. */ + +#define CPP_PREDEFINES "-Dhp9000s200 -Dhp9000s300 -DPWB -Dhpux -Dunix" + +/* Every structure or union's size must be a multiple of 2 bytes. */ + +#define STRUCTURE_SIZE_BOUNDARY 16 + +/* hpux doesn't use static area for struct returns. */ +#undef PCC_STATIC_STRUCT_RETURN + +/* Generate calls to memcpy, memcmp and memset. */ +#define TARGET_MEM_FUNCTIONS + +/* Function calls do save some fp registers on hpux version 7. */ + +#undef CALL_USED_REGISTERS +#define CALL_USED_REGISTERS \ + {1, 1, 0, 0, 0, 0, 0, 0, \ + 1, 1, 0, 0, 0, 0, 0, 1, \ + 1, 1, 0, 0, 0, 0, 0, 0} + +#ifdef HPUX_ASM + +/* Override parts of tm-m68k.h to fit the HPUX assembler. */ + +#undef TARGET_VERSION +#undef REGISTER_NAMES +#undef FUNCTION_PROLOGUE +#undef FUNCTION_EPILOGUE +#undef ASM_OUTPUT_REG_PUSH +#undef ASM_OUTPUT_REG_POP +#undef ASM_FILE_START +#undef ASM_APP_ON +#undef ASM_APP_OFF +#undef TEXT_SECTION_ASM_OP +#undef DATA_SECTION_ASM_OP +#undef ASM_OUTPUT_DOUBLE +#undef ASM_OUTPUT_FLOAT +#undef ASM_OUTPUT_INT +#undef ASM_OUTPUT_SHORT +#undef ASM_OUTPUT_CHAR +#undef ASM_OUTPUT_BYTE +#undef ASM_OUTPUT_ADDR_VEC_ELT +#undef ASM_OUTPUT_ADDR_DIFF_ELT +#undef ASM_OUTPUT_ALIGN +#undef ASM_OUTPUT_SKIP +#undef ASM_OUTPUT_COMMON +#undef ASM_OUTPUT_LOCAL +#undef ASM_FORMAT_PRIVATE_NAME +#undef PRINT_OPERAND +#undef PRINT_OPERAND_ADDRESS +#undef FUNCTION_PROFILER +#undef ASM_GLOBALIZE_LABEL +#undef ASM_OUTPUT_INTERNAL_LABEL + +#define TARGET_VERSION fprintf (stderr, " (68k, SGS/hpux syntax)"); + +#define REGISTER_NAMES \ +{"%d0", "%d1", "%d2", "%d3", "%d4", "%d5", "%d6", "%d7", \ + "%a0", "%a1", "%a2", "%a3", "%a4", "%a5", "%fp", "%sp", \ + "%fp0", "%fp1", "%fp2", "%fp3", "%fp4", "%fp5", "%fp6", "%fp7"} + +#define FUNCTION_PROLOGUE(FILE, SIZE) \ +{ register int regno; \ + register int mask = 0; \ + extern char call_used_regs[]; \ + int fsize = (SIZE); \ + if (frame_pointer_needed) \ + { if (fsize < 0x8000) \ + fprintf (FILE, "\tlink.w %%a6,&%d\n", -fsize); \ + else if (TARGET_68020) \ + fprintf (FILE, "\tlink.l %%a6,&%d\n", -fsize); \ + else \ + fprintf (FILE, "\tlink.w %%a6,&0\n\tsub.l &%d,%%sp\n", fsize); } \ + for (regno = 16; regno < FIRST_PSEUDO_REGISTER; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + mask |= 1 << (regno - 16); \ + if (mask != 0) \ + fprintf (FILE, "\tfmovem &0x%x,-(%%sp)\n", mask & 0xff); \ + mask = 0; \ + for (regno = 0; regno < 16; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + mask |= 1 << (15 - regno); \ + if (frame_pointer_needed) \ + mask &= ~ (1 << (15-FRAME_POINTER_REGNUM)); \ + if (exact_log2 (mask) >= 0) \ + fprintf (FILE, "\tmov.l %s,-(%%sp)\n", reg_names[15 - exact_log2 (mask)]); \ + else if (mask) fprintf (FILE, "\tmovm.l &0x%x,-(%%sp)\n", mask); } + +#define PROFILE_BEFORE_PROLOGUE + +#define FUNCTION_PROFILER(FILE, LABEL_NO) \ + fprintf (FILE, "\tmov.l &LP%d,%%a0\n\tjsr mcount\n", (LABEL_NO)); + +#define FUNCTION_EPILOGUE(FILE, SIZE) \ +{ register int regno; \ + register int mask, fmask; \ + register int nregs; \ + int offset, foffset; \ + extern char call_used_regs[]; \ + extern int current_function_pops_args; \ + extern int current_function_args_size; \ + int fsize = (SIZE); \ + int big = 0; \ + nregs = 0; fmask = 0; \ + for (regno = 16; regno < FIRST_PSEUDO_REGISTER; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + { nregs++; fmask |= 1 << (23 - regno); } \ + foffset = nregs * 12; \ + nregs = 0; mask = 0; \ + if (frame_pointer_needed) regs_ever_live[FRAME_POINTER_REGNUM] = 0; \ + for (regno = 0; regno < 16; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + { nregs++; mask |= 1 << regno; } \ + offset = foffset + nregs * 4; \ + if (offset + fsize >= 0x8000 && frame_pointer_needed) \ + { fprintf (FILE, "\tmov.l &%d,%%a0\n", -fsize); \ + fsize = 0, big = 1; } \ + if (exact_log2 (mask) >= 0) { \ + if (big) \ + fprintf (FILE, "\tmov.l -%d(%%a6,%%a0.l),%s\n", \ + offset + fsize, reg_names[exact_log2 (mask)]); \ + else if (! frame_pointer_needed) \ + fprintf (FILE, "\tmov.l (%%sp)+,%s\n", \ + reg_names[exact_log2 (mask)]); \ + else \ + fprintf (FILE, "\tmov.l -%d(%%a6),%s\n", \ + offset + fsize, reg_names[exact_log2 (mask)]); } \ + else if (mask) { \ + if (big) \ + fprintf (FILE, "\tmovm.l -%d(%%a6,%%a0.l),&0x%x\n", \ + offset + fsize, mask); \ + else if (! frame_pointer_needed) \ + fprintf (FILE, "\tmovm.l (%%sp)+,&0x%x\n", mask); \ + else \ + fprintf (FILE, "\tmovm.l -%d(%%a6),&0x%x\n", \ + offset + fsize, mask); } \ + if (fmask) { \ + if (big) \ + fprintf (FILE, "\tfmovem -%d(%%a6,%%a0.l),&0x%x\n", \ + foffset + fsize, fmask); \ + else if (! frame_pointer_needed) \ + fprintf (FILE, "\tfmovem (%%sp)+,&0x%x\n", fmask); \ + else \ + fprintf (FILE, "\tfmovem -%d(%%a6),&0x%x\n", \ + foffset + fsize, fmask); } \ + if (frame_pointer_needed) \ + fprintf (FILE, "\tunlk %%a6\n"); \ + if (current_function_pops_args && current_function_args_size) \ + fprintf (FILE, "\trtd &%d\n", current_function_args_size); \ + else fprintf (FILE, "\trts\n"); } + +/* This is how to output an insn to push a register on the stack. + It need not be very fast code. */ + +#define ASM_OUTPUT_REG_PUSH(FILE,REGNO) \ + fprintf (FILE, "\tmov.l %s,-(%%sp)\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, "\tmov.l (%%sp)+,%s\n", reg_names[REGNO]) + +#define ASM_FILE_START(FILE) + +#define ASM_APP_ON "" + +#define ASM_APP_OFF "" + +#define TEXT_SECTION_ASM_OP "text" + +#define DATA_SECTION_ASM_OP "data" + +#define ASCII_DATA_ASM_OP "\tbyte" + +/* This says how to output an assembler line + to define a global common symbol. */ + +#define ASM_OUTPUT_COMMON(FILE, NAME, SIZE, ROUNDED) \ +( fputs ("\tcomm ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%u\n", (ROUNDED))) + +/* This says how to output an assembler line + to define a local common symbol. */ + +#define ASM_OUTPUT_LOCAL(FILE, NAME, SIZE, ROUNDED) \ +( fputs ("\tlcomm ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%u,2\n", (ROUNDED))) + +/* 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)) + 12), \ + sprintf ((OUTPUT), "%s___%d", (NAME), (LABELNO))) + +/* 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 ("\tglobal ", FILE); assemble_name (FILE, NAME); fputs ("\n", FILE);} while (0) + +#define ASM_OUTPUT_INTERNAL_LABEL(FILE,PREFIX,NUM) \ +do{ if (PREFIX[0] == 'L' && PREFIX[1] == 'I') \ + fprintf(FILE, "\tset %s%d,.+2\n", PREFIX, NUM); \ + else \ + fprintf (FILE, "%s%d:\n", PREFIX, NUM); \ +} while(0) + +#define ASM_OUTPUT_DOUBLE(FILE, VALUE) \ + fprintf (FILE, "\tdouble 0f%.20g\n", (VALUE)) + +#define ASM_OUTPUT_FLOAT(FILE, VALUE) \ + fprintf (FILE, "\tfloat 0f%.9g\n", (VALUE)) + +/* This is how to output an assembler line defining an `int' constant. */ + +#define ASM_OUTPUT_INT(FILE,VALUE) \ +( fprintf (FILE, "\tlong "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +/* Likewise for `char' and `short' constants. */ + +#define ASM_OUTPUT_SHORT(FILE,VALUE) \ +( fprintf (FILE, "\tshort "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +#define ASM_OUTPUT_CHAR(FILE,VALUE) \ +( fprintf (FILE, "\tbyte "), \ + 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, "\tbyte 0x%x\n", (VALUE)) + +#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \ + fprintf (FILE, "\tlong L%d\n", VALUE) + +#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, VALUE, REL) \ + fprintf (FILE, "\tshort L%d-L%d\n", VALUE, REL) + +#define ASM_OUTPUT_ALIGN(FILE,LOG) \ + if ((LOG) == 1) \ + fprintf (FILE, "\tlalign 2\n"); \ + else if ((LOG) != 0) \ + abort (); + +#define ASM_OUTPUT_SKIP(FILE,SIZE) \ + fprintf (FILE, "\tspace %u\n", (SIZE)) + +#define ASM_OUTPUT_SOURCE_FILENAME(FILE, FILENAME) +#define ASM_OUTPUT_SOURCE_LINE(FILE, LINENO) + +#define PRINT_OPERAND(FILE, X, CODE) \ +{ if (CODE == '.') fprintf (FILE, "."); \ + else if (CODE == '#') fprintf (FILE, "&"); \ + else if (CODE == '-') fprintf (FILE, "-(%%sp)"); \ + else if (CODE == '+') fprintf (FILE, "(%%sp)+"); \ + else if (CODE == '@') fprintf (FILE, "(%%sp)"); \ + else if (CODE == '!') fprintf (FILE, "%%cc"); \ + else if (GET_CODE (X) == REG) \ + fprintf (FILE, "%s", reg_names[REGNO (X)]); \ + else if (GET_CODE (X) == MEM) \ + output_address (XEXP (X, 0)); \ + else if (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) == SFmode) \ + { union { double d; int i[2]; } u; \ + union { float f; int i; } u1; \ + u.i[0] = CONST_DOUBLE_LOW (X); u.i[1] = CONST_DOUBLE_HIGH (X); \ + u1.f = u.d; \ + if (CODE == 'f') \ + fprintf (FILE, "&0f%.9g", u1.f); \ + else \ + fprintf (FILE, "&0x%x", u1.i); } \ + else if (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) == DFmode) \ + { union { double d; int i[2]; } u; \ + u.i[0] = CONST_DOUBLE_LOW (X); u.i[1] = CONST_DOUBLE_HIGH (X); \ + fprintf (FILE, "&0f%.20g", u.d); } \ + else { putc ('&', FILE); output_addr_const (FILE, X); }} + +#define PRINT_OPERAND_ADDRESS(FILE, ADDR) \ +{ register rtx reg1, reg2, breg, ireg; \ + register rtx addr = ADDR; \ + rtx offset; \ + switch (GET_CODE (addr)) \ + { \ + case REG: \ + fprintf (FILE, "(%s)", reg_names[REGNO (addr)]); \ + break; \ + case PRE_DEC: \ + fprintf (FILE, "-(%s)", reg_names[REGNO (XEXP (addr, 0))]); \ + break; \ + case POST_INC: \ + fprintf (FILE, "(%s)+", reg_names[REGNO (XEXP (addr, 0))]); \ + break; \ + case PLUS: \ + reg1 = 0; reg2 = 0; \ + ireg = 0; breg = 0; \ + offset = 0; \ + if (CONSTANT_ADDRESS_P (XEXP (addr, 0))) \ + { \ + offset = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (CONSTANT_ADDRESS_P (XEXP (addr, 1))) \ + { \ + offset = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + if (GET_CODE (addr) != PLUS) ; \ + else if (GET_CODE (XEXP (addr, 0)) == SIGN_EXTEND) \ + { \ + reg1 = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (GET_CODE (XEXP (addr, 1)) == SIGN_EXTEND) \ + { \ + reg1 = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + else if (GET_CODE (XEXP (addr, 0)) == MULT) \ + { \ + reg1 = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (GET_CODE (XEXP (addr, 1)) == MULT) \ + { \ + reg1 = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + else if (GET_CODE (XEXP (addr, 0)) == REG) \ + { \ + reg1 = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (GET_CODE (XEXP (addr, 1)) == REG) \ + { \ + reg1 = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + if (GET_CODE (addr) == REG || GET_CODE (addr) == MULT \ + || GET_CODE (addr) == SIGN_EXTEND) \ + { if (reg1 == 0) reg1 = addr; else reg2 = addr; addr = 0; } \ +/* for OLD_INDEXING \ + else if (GET_CODE (addr) == PLUS) \ + { \ + if (GET_CODE (XEXP (addr, 0)) == REG) \ + { \ + reg2 = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (GET_CODE (XEXP (addr, 1)) == REG) \ + { \ + reg2 = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + } \ + */ \ + if (offset != 0) { if (addr != 0) abort (); addr = offset; } \ + if ((reg1 && (GET_CODE (reg1) == SIGN_EXTEND \ + || GET_CODE (reg1) == MULT)) \ + || (reg2 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg2)))) \ + { breg = reg2; ireg = reg1; } \ + else if (reg1 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg1))) \ + { breg = reg1; ireg = reg2; } \ + if (ireg != 0 && breg == 0 && GET_CODE (addr) == LABEL_REF) \ + { int scale = 1; \ + if (GET_CODE (ireg) == MULT) \ + { scale = INTVAL (XEXP (ireg, 1)); \ + ireg = XEXP (ireg, 0); } \ + if (GET_CODE (ireg) == SIGN_EXTEND) \ + fprintf (FILE, "L%d-LI%d(%%pc,%s.w", \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + reg_names[REGNO (XEXP (ireg, 0))]); \ + else \ + fprintf (FILE, "L%d-LI%d(%%pc,%s.l", \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + reg_names[REGNO (ireg)]); \ + if (scale != 1) fprintf (FILE, "*%d", scale); \ + putc (')', FILE); \ + break; } \ + if (ireg != 0 || breg != 0) \ + { int scale = 1; \ + if (breg == 0) \ + abort (); \ + if (addr != 0) \ + output_addr_const (FILE, addr); \ + fprintf (FILE, "(%s", reg_names[REGNO (breg)]); \ + if (ireg != 0) \ + putc (',', FILE); \ + if (ireg != 0 && GET_CODE (ireg) == MULT) \ + { scale = INTVAL (XEXP (ireg, 1)); \ + ireg = XEXP (ireg, 0); } \ + if (ireg != 0 && GET_CODE (ireg) == SIGN_EXTEND) \ + fprintf (FILE, "%s.w", reg_names[REGNO (XEXP (ireg, 0))]); \ + else if (ireg != 0) \ + fprintf (FILE, "%s.l", reg_names[REGNO (ireg)]); \ + if (scale != 1) fprintf (FILE, "*%d", scale); \ + putc (')', FILE); \ + break; \ + } \ + else if (reg1 != 0 && GET_CODE (addr) == LABEL_REF) \ + { fprintf (FILE, "L%d-LI%d(%%pc,%s.w)", \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + reg_names[REGNO (reg1)]); \ + break; } \ + default: \ + if (GET_CODE (addr) == CONST_INT \ + && INTVAL (addr) < 0x8000 \ + && INTVAL (addr) >= -0x8000) \ + fprintf (FILE, "%d.w", INTVAL (addr)); \ + else \ + output_addr_const (FILE, addr); \ + }} + +#define ASM_OUTPUT_ASCII(f, p, size) \ +{ register int i; \ + int inside; \ + inside = FALSE; \ + for (i = 0; i < size; i++) { \ + if (i % 8 == 0) { \ + if (i != 0) { \ + if (inside) \ + putc('"', f); \ + putc('\n', f); \ + inside = FALSE; \ + } \ + fprintf(f, "%s ", ASCII_DATA_ASM_OP); \ + } \ + if (p[i] < 32 || p[i] == '\\' || p[i] == '"' || p[i] == 127) { \ + if (inside) { \ + putc('"', f); \ + inside = FALSE; \ + } \ + if (i % 8 != 0) \ + putc(',', f); \ + fprintf(f, "%d", p[i]); \ + } else { \ + if (!inside) { \ + if (i % 8 != 0) \ + putc(',', f); \ + putc('"', f); \ + inside = TRUE; \ + } \ + putc(p[i], f); \ + } \ + } \ + if (inside) \ + putc('"', f); \ + putc('\n', f); \ +} + +/* Translate Motorola opcodes such as `jbeq' + into SGS opcodes such as `beq.w'. + Delete the `e' in `move...' and `fmove'. + Change `ftst' to `ftest'. */ + +#define ASM_OUTPUT_OPCODE(FILE, PTR) \ +{ if ((PTR)[0] == 'j' && (PTR)[1] == 'b') \ + { ++(PTR); \ + while (*(PTR) != ' ') \ + { putc (*(PTR), (FILE)); ++(PTR); } \ + fprintf ((FILE), ".w"); } \ + else if ((PTR)[0] == 'f') \ + { \ + if (!strncmp ((PTR), "fmove", 5)) \ + { fprintf ((FILE), "fmov"); (PTR) += 5; } \ + else if (!strncmp ((PTR), "ftst", 4)) \ + { fprintf ((FILE), "ftest"); (PTR) += 4; } \ + } \ + else if ((PTR)[0] == 'm' && (PTR)[1] == 'o' \ + && (PTR)[2] == 'v' && (PTR)[3] == 'e') \ + { fprintf ((FILE), "mov"); (PTR) += 4; } \ +} + +/* Prevent output of `gcc_compiled.:'. */ + +#define ASM_IDENTIFY_GCC(FILE) + +#endif /* HPUX_ASM */ diff --git a/gcc-1.40/config/tm-hp9k320g.h b/gcc-1.40/config/tm-hp9k320g.h new file mode 100644 index 0000000..32ac30a --- /dev/null +++ b/gcc-1.40/config/tm-hp9k320g.h @@ -0,0 +1,12 @@ +/* Definitions of target machine for GNU compiler. HP-UX 68000/68020 version. + Use this file if GCC is supposed to work with the GNU assembler, + GNU linker and GNU debugger using DBX debugging information. + (In other words, much of HPUX has been cast aside.) */ + +/* This wants DBX format. */ + +#define DBX_DEBUGGING_INFO + +#define USE_GAS + +#include "tm-hp9k320.h" diff --git a/gcc-1.40/config/tm-hp9k3bsd.h b/gcc-1.40/config/tm-hp9k3bsd.h new file mode 100644 index 0000000..b4e5442 --- /dev/null +++ b/gcc-1.40/config/tm-hp9k3bsd.h @@ -0,0 +1,36 @@ +#include "tm-m68k.h" + +/* See tm-m68k.h. 7 means 68020 with 68881. */ + +#define TARGET_DEFAULT 7 + +/* Define __HAVE_68881__ in preprocessor, unless -msoft-float is specified. + This will control the use of inline 68881 insns in certain macros. */ + +#define CPP_SPEC "%{!msoft-float:-D__HAVE_FPU__ -D__HAVE_68881__}" + +/* Names to predefine in the preprocessor for this target machine. */ + +#define CPP_PREDEFINES "-Dmc68000 -Dmc68020 -Dhp300 -Dhp9000 -Dunix" + +/* Every structure or union's size must be a multiple of 2 bytes. */ + +#define STRUCTURE_SIZE_BOUNDARY 16 + +/* This is BSD, so it wants DBX format. */ + +#define DBX_DEBUGGING_INFO + +/* Do not break .stabs pseudos into continuations. */ + +#define DBX_CONTIN_LENGTH 0 + +/* This is the char to use for continuation (in case we need to turn + continuation back on). */ + +#define DBX_CONTIN_CHAR '?' + +/* Don't use the `xsfoo;' construct in DBX output; this system + doesn't support it. */ + +#define DBX_NO_XREFS diff --git a/gcc-1.40/config/tm-i386.h b/gcc-1.40/config/tm-i386.h new file mode 100644 index 0000000..34d6c2c --- /dev/null +++ b/gcc-1.40/config/tm-i386.h @@ -0,0 +1,1088 @@ +/* Definitions of target machine for GNU compiler for Intel 80386. + Copyright (C) 1988 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 1, 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. */ + + +/* Note that some other tm- files include this one and then override + many of the definitions that relate to assembler syntax. */ + +/* Names to predefine in the preprocessor for this target machine. */ + +/* the file tm-compaq.h includes this file */ + + +#define I386 1 + +/* Run-time compilation parameters selecting different hardware subsets. */ + +extern int target_flags; + +/* Macros used in the machine description to test the flags. */ + +/* Compile 80387 insns for floating point (not library calls). */ +#define TARGET_80387 (target_flags & 1) +/* Compile using ret insn that pops args. + This will not work unless you use prototypes at least + for all functions that can take varying numbers of args. */ +#define TARGET_RTD (target_flags & 8) +/* Compile passing first two args in regs 0 and 1. + This exists only to test compiler features that will + be needed for RISC chips. It is not usable + and is not intended to be usable on this cpu. */ +#define TARGET_REGPARM (target_flags & 020) + +/* 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 \ + { { "80387", 1}, \ + { "soft-float", -1}, \ + { "rtd", 8}, \ + { "nortd", -8}, \ + { "regparm", 020}, \ + { "noregparm", -020}, \ + { "", TARGET_DEFAULT}} + +/* TARGET_DEFAULT is defined in tm-compaq.h, etc. */ + +/* target machine storage layout */ + +/* Define this if most significant byte of a word is the lowest numbered. */ +/* That is true on the 80386. */ + +/* #define BITS_BIG_ENDIAN */ + +/* Define this if most significant byte of a word is the lowest numbered. */ +/* That is not true on the 80386. */ +/* #define BYTES_BIG_ENDIAN */ + +/* Define this if most significant word of a multiword number is numbered. */ +/* Not true for 80386 */ +/* #define WORDS_BIG_ENDIAN */ + +/* number of bits in an addressible 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 80386, this would still be 32. + But on a machine with 16-bit registers, this would be 16. */ +#define BITS_PER_WORD 32 + +/* Width of a word, in units (bytes). */ +#define UNITS_PER_WORD 4 + +/* Width in bits of a pointer. + See also the macro `Pmode' defined below. */ +#define POINTER_SIZE 32 + +/* Allocation boundary (in *bits*) for storing pointers in memory. */ +#define POINTER_BOUNDARY 32 + +/* Allocation boundary (in *bits*) for storing arguments in argument list. */ +#define PARM_BOUNDARY 32 + +/* Boundary (in *bits*) on which stack pointer should be aligned. */ +#define STACK_BOUNDARY 32 + +/* Allocation boundary (in *bits*) for the code of a function. */ +#define FUNCTION_BOUNDARY 32 + +/* Alignment of field after `int : 0' in a structure. */ + +#define EMPTY_FIELD_BOUNDARY 32 + +/* There is no point aligning anything to a rounder boundary than this. */ +/* Some structures in the ATT libraries are assumed to round up from 16 to 18 + bytes, for example the _io_buf */ +#define BIGGEST_ALIGNMENT 32 + +/* Define this if move instructions will actually fail to work + when given unaligned data. */ +/* #define STRICT_ALIGNMENT */ + +/* 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. + In the 80387 we give the 8 general purpose registers the numbers 0-7, + we assign 6 numbers for floating point registers 8-13, + Note that registers 0-7 can be accessed as a short or int, + while only 0-3 may be used with mov byte instructions. +*/ +#define FIRST_PSEUDO_REGISTER 10 + +/* 1 for registers that have pervasive standard uses + and are not available for the register allocator. + On the 80386, only the stack pointer is such. */ +#define FIXED_REGISTERS \ +/*ax,ad,ac,ab,si,di,bp,sp,fval,fp0*/ \ +{ 0, 0, 0, 0, 0, 0, 0, 1, 1, 0} + +/* ;;change-wfs */ + +/* 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 \ +/*ax,ad,ac,ab,si,di,bp,sp,*/ \ +{ 1, 1, 1, 0, 0, 0, 0, 1, \ + 1, 1} + +/* 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. + + Actually there are no two word move instructions for consecutive + registers. And only registers 0-3 may have mov byte instructions + applied to them. + */ + +#define HARD_REGNO_NREGS(REGNO, MODE) \ + ((REGNO) >= 8 ? 1 \ + : ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)) + +/* Value is 1 if hard register REGNO can hold a value of machine-mode MODE. + On the 80386, the first 4 cpu registers can hold any mode. + While the floating point registers may hold SFmode or DFmode only. + */ + +#define HARD_REGNO_MODE_OK(REGNO, MODE) \ + hard_regno_mode_ok(REGNO,MODE) + +/* 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)) + +/* Specify the registers used for certain standard purposes. + The values of these macros are register numbers. */ + +/* on the 386 the pc register is %eip, and is not usable as a general + register. The ordinary mov instructions won't work */ +/* #define PC_REGNUM */ + +/* Register to use for pushing function arguments. */ +#define STACK_POINTER_REGNUM 7 + +/* Base register for access to local variables of the function. */ +#define FRAME_POINTER_REGNUM 6 + +/* First floating point reg */ +#define FIRST_FLOAT_REG 8 +/* 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. */ +#define FRAME_POINTER_REQUIRED 0 + +/* Base register for access to arguments of the function. */ +#define ARG_POINTER_REGNUM 6 + +/* Register in which static-chain is passed to a function. */ +#define STATIC_CHAIN_REGNUM 2 + +/* Register in which address to store a structure value + arrives in the function. On the 386, the prologue + copies this from the stack to register %eax. */ +#define STRUCT_VALUE_INCOMING \ + gen_rtx (MEM, Pmode, gen_rtx (PLUS, Pmode, frame_pointer_rtx, \ + gen_rtx (CONST_INT, VOIDmode, 8))) + +/* Place in which caller passes the structure value address. + Actually, all that matters about this value is it its rtx_code: + MEM means push the value on the stack like an argument. */ +#define STRUCT_VALUE \ + gen_rtx (MEM, Pmode, gen_rtx (PRE_DEC, Pmode, stack_pointer_rtx)) + +/* 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. */ + + +enum reg_class { + NO_REGS, AREG, DREG, ADREG, CREG, BREG, Q_REGS, SIREG, DIREG, + INDEX_REGS, GENERAL_REGS, FLOAT_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", "AREG", "DREG", "ADREG", "CREG", "BREG","Q_REGS", \ + "SIREG", "DIREG", \ + "INDEX_REGS", "GENERAL_REGS", "FLOAT_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, 0x1, 0x2, 0x3, 0x4, 0x8, 0xf,\ + 0x10, 0x20, 0x7f, 0xff, 0x300, 0x3ff} + +/* 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. */ + +#define REGNO_REG_CLASS(REGNO) \ + ((REGNO) == 0 ? AREG : \ + (REGNO) == 1 ? DREG : \ + (REGNO) == 2 ? CREG : \ + (REGNO) == 3 ? BREG : \ + (REGNO) == 4 ? SIREG : \ + (REGNO) == 5 ? DIREG : \ + (REGNO) == 7 ? GENERAL_REGS : \ + (REGNO) < 8 ? INDEX_REGS : \ + FLOAT_REGS) + +#define NON_QI_REG_P(X) \ + (REG_P (X) && REGNO (X) >= 4 && REGNO (X) < FIRST_PSEUDO_REGISTER) + +#define FP_REG_P(X) (REG_P (X) && FP_REGNO_P (REGNO (X))) +#define FP_REGNO_P(n) ((n) >= FIRST_FLOAT_REG && (n) < FIRST_PSEUDO_REGISTER) + +/* This definition indicates that some register classes are very small, + which requires extra care in certain optimizations. */ + +#define SMALL_REGISTER_CLASSES + +/* Try to maintain the accuracy of the death notes for regs satisfying the + following. Important for stack like regs, to know when to pop. */ + +#define PRESERVE_DEATH_INFO_REGNO_P(x) FP_REGNO_P(x) + +/* 1 if register REGNO can magically overlap other regs. + Note that nonzero values work only in very special circumstances. + We return 1 for an FP reg because "both" our FP regs + are really the same reg. */ + +#define OVERLAPPING_REGNO_P(REGNO) FP_REGNO_P (REGNO) + +/* The class value for index registers, and the one for base regs. */ + +#define INDEX_REG_CLASS INDEX_REGS +#define BASE_REG_CLASS GENERAL_REGS + +/* Get reg_class from a letter such as appears in the machine description. */ + +#define REG_CLASS_FROM_LETTER(C) \ + ((C) == 'r' ? GENERAL_REGS : \ + (C) == 'q' ? Q_REGS : \ + (C) == 'f' ? FLOAT_REGS : \ + (C) == 'a' ? AREG : (C) == 'b' ? BREG : \ + (C) == 'c' ? CREG : (C) == 'd' ? DREG : \ + (C) == 'A' ? ADREG : \ + (C) == 'S' ? SIREG : \ + (C) == 'D' ? DIREG : 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 for the maximum shifts. + */ + +#define CONST_OK_FOR_LETTER_P(VALUE, C) \ + ((C) == 'I' ? (VALUE) >= 0 && (VALUE) <= 31 :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' ? ! (TARGET_80387 && standard_80387_constant_p (VALUE)) : 1) + +/* 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. + On the 80386 series, we prevent floating constants from being + reloaded into floating registers (since no move-insn can do that) + and we ensure that QImodes aren't reloaded into the esi or edi reg. */ + +#define PREFERRED_RELOAD_CLASS(X,CLASS) \ + (GET_CODE (X) == CONST_DOUBLE \ + ? ((CLASS) == GENERAL_REGS || (CLASS) == ALL_REGS \ + ? GENERAL_REGS : NO_REGS) \ + : GET_MODE (X) == QImode \ + ? ((CLASS) == GENERAL_REGS || (CLASS) == ALL_REGS \ + ? Q_REGS \ + : (CLASS) == INDEX_REGS ? (abort (), INDEX_REGS) \ + : (CLASS)) \ + : (CLASS)) + +/* Return the maximum number of consecutive registers + needed to represent mode MODE in a register of class CLASS. */ +/* On the 80386, this is the size of MODE in words, + except in the FP regs, where a single reg is always enough. */ +#define CLASS_MAX_NREGS(CLASS, MODE) \ + ((CLASS) == FLOAT_REGS ? 1 : \ + ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)) + +/* Stack layout; function entry, exit and calling. */ + +/* 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. */ +#define STARTING_FRAME_OFFSET 0 + +/* If we generate an insn to push BYTES bytes, + this says how many the stack pointer really advances by. + On 386 pushw decrements by exactly 2 no matter what the position was. + On the 386 there is no pushb; we use pushw instead, and this + has the effect of rounding up to 2. */ + +#define PUSH_ROUNDING(BYTES) (((BYTES) + 1) & (-2)) + +/* Offset of first parameter from the argument pointer register value. */ +#define FIRST_PARM_OFFSET(FNDECL) 8 + +/* Value is 1 if returning from a function call automatically + pops the arguments described by the number-of-args field in the call. + 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. + + On the 80386, the RTD insn may be used to pop them if the number + of args is fixed, but if the number is variable then the caller + must pop them all. RTD can't be used for library calls now + because the library is compiled with the Unix compiler. + Use of RTD is a selectable option, since it is incompatible with + standard Unix calling sequences. If the option is not selected, + the caller must always pop the args. */ + +#define RETURN_POPS_ARGS(FUNTYPE) \ + (TARGET_RTD && TREE_CODE (FUNTYPE) != IDENTIFIER_NODE \ + && (TYPE_ARG_TYPES (FUNTYPE) == 0 \ + || TREE_VALUE (tree_last (TYPE_ARG_TYPES (FUNTYPE))) == void_type_node)) + +#define FUNCTION_VALUE(VALTYPE, FUNC) \ + 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)) + +/* 1 if N is a possible register number for function argument passing. + On the 80386, no registers are used in this way. + *NOTE* -mregparm does not work. + It exists only to test register calling conventions. */ + +#define FUNCTION_ARG_REGNO_P(N) 0 +/* 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 the 80386, this is a single integer, which is a number of bytes + of arguments scanned so far. */ + +#define CUMULATIVE_ARGS int + +/* 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. + + On the 80386, the offset starts at 0. */ + +#define INIT_CUMULATIVE_ARGS(CUM,FNTYPE) \ + ((CUM) = 0) + +/* 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.) */ + +#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \ + ((CUM) += ((MODE) != BLKmode \ + ? (GET_MODE_SIZE (MODE) + 3) & ~3 \ + : (int_size_in_bytes (TYPE) + 3) & ~3)) + +/* Define where to put the arguments 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). */ + + +/* On the 80386 all args are pushed, except if -mregparm is specified + then the first two words of arguments are passed in EAX, EDX. + *NOTE* -mregparm does not work. + It exists only to test register calling conventions. */ + +#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \ +((TARGET_REGPARM && (CUM) < 8) ? gen_rtx (REG, (MODE), (CUM) / 4) : 0) + +/* 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. */ + + +#define FUNCTION_ARG_PARTIAL_NREGS(CUM, MODE, TYPE, NAMED) \ +((TARGET_REGPARM && (CUM) < 8 \ + && 8 < ((CUM) + ((MODE) == BLKmode \ + ? int_size_in_bytes (TYPE) \ + : GET_MODE_SIZE (MODE)))) \ + ? 2 - (CUM) / 4 : 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. */ + +#define FUNCTION_PROLOGUE(FILE, SIZE) \ + function_prologue (FILE, SIZE) + +/* Output assembler code to FILE to increment profiler label # LABELNO + for profiling a function entry. */ + +#define FUNCTION_PROFILER(FILE, LABELNO) \ + fprintf (FILE, "\tmovl $%sP%d,%%edx\n\tcall _mcount\n", LPREFIX, (LABELNO)); + +/* 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. */ +/* Note on the 386 it might be more efficient not to define this since + we have to restore it ourselves from the frame pointer, in order to + use pop */ + +#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) \ + function_epilogue (FILE, SIZE) + +/* If the memory address ADDR is relative to the frame pointer, + correct it to be relative to the stack pointer instead. + This is for when we don't use a frame pointer. + ADDR should be a variable name. */ + + +#define FIX_FRAME_POINTER_ADDRESS(ADDR,DEPTH) \ +{ int offset = -1; \ + rtx regs = stack_pointer_rtx; \ + if (ADDR == frame_pointer_rtx) \ + offset = 0; \ + else if (GET_CODE (ADDR) == PLUS && XEXP (ADDR, 0) == frame_pointer_rtx \ + && GET_CODE (XEXP (ADDR, 1)) == CONST_INT) \ + offset = INTVAL (XEXP (ADDR, 1)); \ + else if (GET_CODE (ADDR) == PLUS && XEXP (ADDR, 0) == frame_pointer_rtx) \ + { rtx other_reg = XEXP (ADDR, 1); \ + offset = 0; \ + regs = gen_rtx (PLUS, Pmode, stack_pointer_rtx, other_reg); } \ + else if (GET_CODE (ADDR) == PLUS && XEXP (ADDR, 1) == frame_pointer_rtx) \ + { rtx other_reg = XEXP (ADDR, 0); \ + offset = 0; \ + regs = gen_rtx (PLUS, Pmode, stack_pointer_rtx, other_reg); } \ + else if (GET_CODE (ADDR) == PLUS \ + && GET_CODE (XEXP (ADDR, 0)) == PLUS \ + && XEXP (XEXP (ADDR, 0), 0) == frame_pointer_rtx \ + && GET_CODE (XEXP (ADDR, 1)) == CONST_INT) \ + { rtx other_reg = XEXP (XEXP (ADDR, 0), 1); \ + offset = INTVAL (XEXP (ADDR, 1)); \ + regs = gen_rtx (PLUS, Pmode, stack_pointer_rtx, other_reg); } \ + else if (GET_CODE (ADDR) == PLUS \ + && GET_CODE (XEXP (ADDR, 0)) == PLUS \ + && XEXP (XEXP (ADDR, 0), 1) == frame_pointer_rtx \ + && GET_CODE (XEXP (ADDR, 1)) == CONST_INT) \ + { rtx other_reg = XEXP (XEXP (ADDR, 0), 0); \ + offset = INTVAL (XEXP (ADDR, 1)); \ + regs = gen_rtx (PLUS, Pmode, stack_pointer_rtx, other_reg); } \ + if (offset >= 0) \ + { int regno; \ + extern char call_used_regs[]; \ + for (regno = FIRST_FLOAT_REG; regno < FIRST_PSEUDO_REGISTER; regno++)\ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + offset += 8; \ + for (regno=0 ; regno = FIRST_PSEUDO_REGISTER) +/* Nonzero if X is a hard reg that can be used as a base reg + of if it is a pseudo reg. */ + /* ?wfs */ +#define REG_OK_FOR_BASE_P(X) (REGNO (X) <= STACK_POINTER_REGNUM || REGNO(X) >= FIRST_PSEUDO_REGISTER) +#define REG_OK_FOR_STRREG_P(X) \ + (REGNO (X) == 4 || REGNO (X) == 5 || REGNO (X) >= FIRST_PSEUDO_REGISTER) + +#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 REG_OK_FOR_STRREG_P(X) \ + (REGNO_OK_FOR_DIREG_P (REGNO (X)) || REGNO_OK_FOR_SIREG_P (REGNO (X))) + +#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. + + The other macros defined here are used only in GO_IF_LEGITIMATE_ADDRESS, + except for CONSTANT_ADDRESS_P which is usually machine-independent. */ + +#define MAX_REGS_PER_ADDRESS 2 + +#define CONSTANT_ADDRESS_P(X) CONSTANT_P (X) + +/* Nonzero if the constant value X is a legitimate general operand. + It is given that X satisfies CONSTANT_P or is a CONST_DOUBLE. */ + +#define LEGITIMATE_CONSTANT_P(X) 1 + +#define GO_IF_INDEXABLE_BASE(X, ADDR) \ + if (GET_CODE (X) == REG && REG_OK_FOR_BASE_P (X)) goto ADDR + +#define LEGITIMATE_INDEX_REG_P(X) \ + (GET_CODE (X) == REG && REG_OK_FOR_INDEX_P (X)) + +/* Return 1 if X is an index or an index times a scale. */ + +#define LEGITIMATE_INDEX_P(X) \ + (LEGITIMATE_INDEX_REG_P (X) \ + || (GET_CODE (X) == MULT \ + && LEGITIMATE_INDEX_REG_P (XEXP (X, 0)) \ + && GET_CODE (XEXP (X, 1)) == CONST_INT \ + && (INTVAL (XEXP (X, 1)) == 2 \ + || INTVAL (XEXP (X, 1)) == 4 \ + || INTVAL (XEXP (X, 1)) == 8))) + +/* Go to ADDR if X is an index term, a base reg, or a sum of those. */ + +#define GO_IF_INDEXING(X, ADDR) \ +{ if (LEGITIMATE_INDEX_P (X)) goto ADDR; \ + GO_IF_INDEXABLE_BASE (X, ADDR); \ + if (GET_CODE (X) == PLUS && LEGITIMATE_INDEX_P (XEXP (X, 0))) \ + { GO_IF_INDEXABLE_BASE (XEXP (X, 1), ADDR); } \ + if (GET_CODE (X) == PLUS && LEGITIMATE_INDEX_P (XEXP (X, 1))) \ + { GO_IF_INDEXABLE_BASE (XEXP (X, 0), ADDR); } } + +/* We used to allow this, but it isn't ever used. + || ((GET_CODE (X) == POST_DEC || GET_CODE (X) == POST_INC) \ + && REG_P (XEXP (X, 0)) \ + && REG_OK_FOR_STRREG_P (XEXP (X, 0))) \ +*/ + +#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \ +{ if (CONSTANT_ADDRESS_P (X)) goto ADDR; \ + GO_IF_INDEXING (X, ADDR); \ + if (GET_CODE (X) == PLUS) \ + { if (CONSTANT_ADDRESS_P (XEXP (X, 1))) \ + GO_IF_INDEXING (XEXP (X, 0), ADDR); \ + if (CONSTANT_ADDRESS_P (XEXP (X, 0))) \ + GO_IF_INDEXING (XEXP (X, 1), 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. + + For the 80386, we handle X+REG by loading X into a register R and + using R+REG. R will go in a general reg and indexing will be used. + However, if REG is a broken-out memory address or multiplication, + nothing needs to be done because REG can certainly go in a general reg. */ + +#define LEGITIMIZE_ADDRESS(X,OLDX,MODE,WIN) \ +{ register int ch = (X) != (OLDX); \ + if (GET_CODE (X) == PLUS) \ + { if (GET_CODE (XEXP (X, 0)) == MULT) \ + ch = 1, XEXP (X, 0) = force_operand (XEXP (X, 0), 0); \ + if (GET_CODE (XEXP (X, 1)) == MULT) \ + ch = 1, XEXP (X, 1) = force_operand (XEXP (X, 1), 0); \ + if (ch && GET_CODE (XEXP (X, 1)) == REG \ + && GET_CODE (XEXP (X, 0)) == REG) \ + return X; \ + if (ch) { GO_IF_LEGITIMATE_ADDRESS (MODE, X, WIN); } \ + if (GET_CODE (XEXP (X, 0)) == REG \ + || (GET_CODE (XEXP (X, 0)) == SIGN_EXTEND \ + && GET_CODE (XEXP (XEXP (X, 0), 0)) == REG \ + && GET_MODE (XEXP (XEXP (X, 0), 0)) == HImode)) \ + { register rtx temp = gen_reg_rtx (Pmode); \ + register rtx val = force_operand (XEXP (X, 1), temp); \ + if (val != temp) emit_move_insn (temp, val, 0); \ + XEXP (X, 1) = temp; \ + return X; } \ + else if (GET_CODE (XEXP (X, 1)) == REG \ + || (GET_CODE (XEXP (X, 1)) == SIGN_EXTEND \ + && GET_CODE (XEXP (XEXP (X, 1), 0)) == REG \ + && GET_MODE (XEXP (XEXP (X, 1), 0)) == HImode)) \ + { register rtx temp = gen_reg_rtx (Pmode); \ + register rtx val = force_operand (XEXP (X, 0), temp); \ + if (val != temp) emit_move_insn (temp, val, 0); \ + XEXP (X, 0) = temp; \ + return X; }}} + +/* Go to LABEL if ADDR (a legitimate address expression) + has an effect that depends on the machine mode it is used for. + On the 80386, only postdecrement and postincrement address depend thus + (the amount of decrement or increment being the length of the operand). */ +#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR,LABEL) \ + if (GET_CODE (ADDR) == POST_INC || GET_CODE (ADDR) == POST_DEC) goto LABEL + +/* Specify the machine mode that this machine uses + 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 */ + +/* Specify the tree operation to be used to convert reals to integers. + This should be changed to take advantage of fist --wfs ?? + */ +#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 4 + +/* Define this if zero-extension is slow (more than one real instruction). */ +/* #define SLOW_ZERO_EXTEND */ + +/* Nonzero if access to memory by bytes is slow and undesirable. */ +#define SLOW_BYTE_ACCESS 0 + +/* Define if shifts truncate the shift count + which implies one can omit a sign-extension or zero-extension + of a shift count. */ +#define SHIFT_COUNT_TRUNCATED + +/* 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 + +/* 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'. + (The 386 can't easily push less than an int.) */ + +#define PROMOTE_PROTOTYPES + +/* 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 SImode + +/* 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 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. */ +#define NO_FUNCTION_CSE + +/* 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) \ + case CONST_INT: \ + if (RTX == const0_rtx) return 0; \ + if ((unsigned) INTVAL (RTX) < 077) return 1; \ + case CONST: \ + case LABEL_REF: \ + case SYMBOL_REF: \ + return 3; \ + case CONST_DOUBLE: \ + return 5; \ + case PLUS: \ + if (GET_CODE (XEXP (RTX, 0)) == REG \ + && GET_CODE (XEXP (RTX, 1)) == CONST_INT) \ + return 2; + +/* Tell final.c how to eliminate redundant test instructions. */ + +/* ??? Find a better place to put this. */ +#if 0 +#define FINAL_PRESCAN_INSN(INSN, OPERANDS, NOPERANDS) \ + fp_hook (INSN, OPERANDS, NOPERANDS) +#endif + +/* Here we define machine-dependent flags and fields in cc_status + (see `conditions.h'). */ + +/* Set if the cc value is actually in the 80387, so a floating point + conditional branch must be output. */ +#define CC_IN_80387 04000 + +/* Store in cc_status the expressions + that the condition codes will describe + after execution of an instruction whose pattern is EXP. + Do not alter them if the instruction would not alter the cc's. */ + +#define NOTICE_UPDATE_CC(EXP, INSN) \ + notice_update_cc((EXP)) + +/* Output a signed jump insn. Use template NORMAL ordinarily, or + FLOAT following a floating point comparison. + Use NO_OV following an arithmetic insn that set the cc's + before a test insn that was deleted. + NO_OV may be zero, meaning final should reinsert the test insn + because the jump cannot be handled properly without it. */ + +#define OUTPUT_JUMP(NORMAL, FLOAT, NO_OV) \ +{ \ + if (cc_status.flags & CC_IN_80387) \ + return FLOAT; \ + if (cc_status.flags & CC_NO_OVERFLOW) \ + return NO_OV; \ + return NORMAL; \ +} + +/* Control the assembler format that we output. */ + +#ifdef ATT +#include +#else +#define FILNMLEN 14 +#endif + +/* How to refer to registers in assembler output. + This sequence is indexed by compiler's hard-register-number (see above). */ + +/* In order to refer to the first 8 regs as 32 bit regs prefix an "e" + For non floating point regs, the following are the HImode names. + */ + + +#define HI_REGISTER_NAMES \ +{"ax","dx","cx","bx","si","di","bp","sp", \ + "st","st(1)"} +/* ,"st(2)","st(3)","st(4)","st(5)" } */ +#define REGISTER_NAMES HI_REGISTER_NAMES + +/* 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 +number as al, and ax. +*/ + +/* note the last four are not really qi_registsers, but + the md will have to never output movb into one of them + only a movw . There is no movb into the hardware reg + esi that I can find */ + +#define QI_REGISTER_NAMES \ +{"al", "dl", "cl", "bl", "si", "di", "bp", "sp",} + +/* + Don't know how to use these, yet. They overlap with ax,dx,cx,bx + and so would clobber al,dl,cl,bl +#define QI_REGISTER_NAMES_TOP \ +{"ah", \ + "dh", \ + "ch", \ + "bh", } +*/ + +/* How to renumber registers for dbxand gdb. */ + +/* {0,2,1,3,6,7,4,5,12,13,14,15,16,17} */ +#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?4 :(n)==7?5 :(n)==8?12 :(n)==9?12 :(n)) + +/* 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) \ + (assemble_name (FILE, NAME), fputs (":\n", FILE)) + +/* This is how to output an assembler line defining a `double' constant. */ + +#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \ + fprintf (FILE, "%s%.22e\n",ASM_DOUBLE, (VALUE)) + + +/* This is how to output an assembler line defining a `float' constant. */ + +#define ASM_OUTPUT_FLOAT(FILE,VALUE) \ +do { union { float f; long l;} tem; \ + tem.f = (VALUE); \ + fputs(ASM_LONG,FILE); \ + fprintf((FILE), "0x%x\n", tem.l); \ + } 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))) + + + +/* This is how to output an assembler line defining an `int' constant. */ + +#define ASM_OUTPUT_INT(FILE,VALUE) \ +( fprintf (FILE,ASM_LONG), \ + output_addr_const (FILE,(VALUE)), \ + putc('\n',FILE)) + +/* Likewise for `char' and `short' constants. */ +/* is this supposed to do align too?? */ + +#define ASM_OUTPUT_SHORT(FILE,VALUE) \ +( fprintf (FILE,ASM_SHORT), \ + output_addr_const (FILE,(VALUE)), \ + putc('\n',FILE)) + +/* +#define ASM_OUTPUT_SHORT(FILE,VALUE) \ +( fputs (ASM_BYTE,FILE), \ + output_addr_const (FILE,(VALUE)), \ + fputs ( ",",FILE), \ + output_addr_const (FILE,(VALUE)), \ + fputs (" >> 8\n",FILE)) +*/ + + +#define ASM_OUTPUT_CHAR(FILE,VALUE) \ +( fprintf (FILE, ASM_BYTE), \ + output_addr_const (FILE,(VALUE)), \ + putc('\n',FILE)) + +/* This is how to output an assembler line for a numeric constant byte. */ + +#define ASM_OUTPUT_BYTE(FILE,VALUE) \ + fprintf ((FILE), "%s0x%x\n", ASM_BYTE, (VALUE)) + +/* This is how to output an insn to push a register on the stack. + It need not be very fast code. */ + +#define ASM_OUTPUT_REG_PUSH(FILE,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]) + +/* This is how to output an element of a case-vector that is absolute. + */ + +#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \ + fprintf (FILE, "%s%s%d\n",ASM_LONG,LPREFIX, VALUE) + +/* This is how to output an element of a case-vector that is relative. + We don't use these on the 386 yet, because the ATT assembler can't do + forward reference the differences. + */ + +#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, VALUE, REL) abort(); \ + fprintf (FILE, "\t.word %s%d-%s%d\n",LPREFIX, VALUE,LPREFIX, REL) + +/* 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 + +/* 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. + The CODE z takes the size of operand from the following digit, and + outputs b,w,or l respectively. + + On the 80386, we use several such letters: + f -- float insn (print a CONST_DOUBLE as a float rather than in hex). + L,W,B,Q,S -- print the opcode suffix for specified size of operand. + 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. + w -- print the operand as if it's a byte (QImode) even if it isn't. + c -- don't print special prefixes before constant operands. */ + +#define PRINT_OPERAND_PUNCT_VALID_P(CODE) \ + ((CODE) == '*') + +#define PRINT_OPERAND(FILE, X, CODE) \ + print_operand (FILE, X, CODE) + + +#define PRINT_OPERAND_ADDRESS(FILE, ADDR) \ + print_operand_address (FILE, ADDR) + +/* Routines in gnulib that return floats must return them in an fp reg, + just as other functions do which return such values. + These macros make that happen. */ + +#define SFVALUE float +#define INTIFY(FLOATVAL) FLOATVAL + +/* Nonzero if INSN magically clobbers register REGNO. */ + +#define INSN_CLOBBERS_REGNO_P(INSN, REGNO) \ + (FP_REGNO_P (REGNO) \ + && (GET_CODE (INSN) == JUMP_INSN || GET_CODE (INSN) == BARRIER)) + +/* a letter which is not needed by the normal asm syntax, which + we can use for operand syntax in the extended asm */ + +#define ASM_OPERAND_LETTER '#' + + +/* +Local variables: +version-control: t +End: +*/ diff --git a/gcc-1.40/config/tm-i386esix.h b/gcc-1.40/config/tm-i386esix.h new file mode 100644 index 0000000..33b349f --- /dev/null +++ b/gcc-1.40/config/tm-i386esix.h @@ -0,0 +1,36 @@ +/* Definitions for Intel 386 running ESIX Unix System V. */ +/* Just like SCO support except don't use their special library and + predefined symbol. */ + +/* Mostly it's like AT&T Unix System V. */ + +#include "tm-i386v.h" + +/* Use crt1.o as a startup file and crtn.o as a closing file. */ + +#undef STARTFILE_SPEC +#define STARTFILE_SPEC "%{pg:gcrt1.o%s}%{!pg:%{p:mcrt1.o%s}%{!p:crt1.o%s}}" + +#define ENDFILE_SPEC "crtn.o%s" + +/* Library spec. */ + +#undef LIB_SPEC +#define LIB_SPEC \ + "%{p:-L/usr/lib/libp}%{pg:-L/usr/lib/libp} -lc" + +/* Specify predefined symbols in preprocessor. */ + +#undef CPP_PREDEFINES +#define CPP_PREDEFINES \ +"-Dunix -Di386 -DM_UNIX -DM_I386 -DM_COFF -DM_WORDSWAP" + +#undef CPP_SPEC +#define CPP_SPEC "%{posix:-D_POSIX_SOURCE}" + +/* SCO's assember doesn't grok '$' in labels (for g++) */ + +#define NO_DOLLAR_IN_LABEL + +/* Unlike SCO, ESIX expects the called function to pop the structure + value address. So don't define STRUCT_RETURN_CALLER_POP. */ diff --git a/gcc-1.40/config/tm-i386gas.h b/gcc-1.40/config/tm-i386gas.h new file mode 100644 index 0000000..fdb3c59 --- /dev/null +++ b/gcc-1.40/config/tm-i386gas.h @@ -0,0 +1,106 @@ +/* Definitions for Intel 386 running system V with gnu tools + Copyright (C) 1988 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 1, 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 "tm-i386.h" +/* Use the bsd assembler syntax. */ +/* we need to do this because gas is really a bsd style assembler, + * and so doesn't work well this these att-isms: + * + * ASM_OUTPUT_SKIP is .set .,.+N, which isn't implemented in gas + * ASM_OUTPUT_LOCAL is done with .set .,.+N, but that can't be + * used to define bss static space + * + * Next is the question of whether to uses underscores. RMS didn't + * like this idea at first, but since it is now obvious that we + * need this separate tm file for use with gas, at least to get + * dbx debugging info, I think we should also switch to underscores. + * We can keep tm-i386v for real att style output, and the few + * people who want both form will have to compile twice. + */ + +#include "tm-bsd386.h" + +/* these come from tm-bsd386.h, but are specific to sequent */ +#undef DBX_NO_XREFS +#undef DBX_CONTIN_LENGTH + +/* By default, target has a 80387. */ + +#define TARGET_DEFAULT 1 + +/* Specify predefined symbols in preprocessor. */ + +#define CPP_PREDEFINES "-Dunix -Di386" + +/* Allow #sccs in preprocessor. */ + +#define SCCS_DIRECTIVE + +/* Output #ident as a .ident. */ + +#define ASM_OUTPUT_IDENT(FILE, NAME) fprintf (FILE, "\t.ident \"%s\"\n", NAME); + +/* We do not want to output SDB debugging information. */ + +#undef SDB_DEBUGGING_INFO + +/* We want to output DBX debugging information. */ + +#define DBX_DEBUGGING_INFO + +/* Implicit library calls should use memcpy, not bcopy, etc. */ + +#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. */ + +#undef ASM_OUTPUT_ALIGN +#define ASM_OUTPUT_ALIGN(FILE,LOG) \ + if ((LOG)!=0) fprintf ((FILE), "\t.align %d\n", 1<<(LOG)) +#endif + +/* Align labels, etc. at 4-byte boundaries. */ + +#define ASM_OUTPUT_ALIGN_CODE(FILE) \ + fprintf ((FILE), "\t.align 2\n"); /* Use log of 4 as arg. */ + +#if 0 +#define ASM_OUTPUT_ALIGN_CODE(FILE) \ + fprintf ((FILE), "\t.align 4\n"); +#endif + +/* Machines that use the AT&T assembler syntax + also return floating point values in an FP register. */ +/* 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. */ + +#define VALUE_REGNO(MODE) \ + (((MODE)==SFmode || (MODE)==DFmode) ? FIRST_FLOAT_REG : 0) + +/* 1 if N is a possible register number for a function value. */ + +#define FUNCTION_VALUE_REGNO_P(N) ((N) == 0 || (N)== FIRST_FLOAT_REG) + +#undef ASM_FILE_START +#define ASM_FILE_START(FILE) \ + fprintf (FILE, "\t.file\t\"%s\"\n", dump_base_name); diff --git a/gcc-1.40/config/tm-i386isc.h b/gcc-1.40/config/tm-i386isc.h new file mode 100644 index 0000000..6204193 --- /dev/null +++ b/gcc-1.40/config/tm-i386isc.h @@ -0,0 +1,24 @@ +/* Definitions for Intel 386 running Interactive Unix System V. */ + +/* Mostly it's like AT&T Unix System V. */ + +#include "tm-i386v.h" + +/* Use crt0.o or crt1.o as a startup file and crtn.o as a closing file. */ +#undef STARTFILE_SPEC +#define STARTFILE_SPEC \ + "%{!shlib:%{posix:%{pg:mcrtp1.o%s}%{!pg:%{p:mcrtp1.o%s}%{!p:crtp0.o%s}}}\ + %{!posix:%{pg:mcrt0.o%s}%{!pg:%{p:mcrt0.o%s}%{!p:crt0.o%s}}\ + %{p:-L/lib/libp} %{pg:-L/lib/libp}}}\ + %{shlib:%{posix:crtp1.o%s}%{!posix:crt1.o%s}} " + +#define ENDFILE_SPEC "crtn.o%s" + +/* Library spec */ +#undef LIB_SPEC +#define LIB_SPEC "%{posix:-lcposix} %{shlib:-lc_s} -lc" + +/* caller has to pop the extra argument passed to functions that return + structures. */ + +#define STRUCT_RETURN_CALLER_POP diff --git a/gcc-1.40/config/tm-i386sco.h b/gcc-1.40/config/tm-i386sco.h new file mode 100644 index 0000000..f9ca635 --- /dev/null +++ b/gcc-1.40/config/tm-i386sco.h @@ -0,0 +1,39 @@ +/* Definitions for Intel 386 running SCO Unix System V. */ + + +/* Mostly it's like AT&T Unix System V. */ + +#include "tm-i386v.h" + +/* Use crt1.o as a startup file and crtn.o as a closing file. */ + +#undef STARTFILE_SPEC +#define STARTFILE_SPEC "%{pg:gcrt1.o%s}%{!pg:%{p:mcrt1.o%s}%{!p:crt1.o%s}}" + +#define ENDFILE_SPEC "crtn.o%s" + +/* Library spec, including SCO international language support. */ + +#undef LIB_SPEC +#define LIB_SPEC \ + "%{p:-L/usr/lib/libp}%{pg:-L/usr/lib/libp} libintl.a%s -lc" + +/* Specify predefined symbols in preprocessor. */ + +#undef CPP_PREDEFINES +#define CPP_PREDEFINES \ +"-Dunix -Di386 -DM_UNIX -DM_I386 -DM_COFF -DM_WORDSWAP" + +#undef CPP_SPEC +#define CPP_SPEC "%{posix:-D_POSIX_SOURCE} -DM_INTERNAT" + +/* SCO's assember doesn't grok '$' in labels (for g++) */ + +#define NO_DOLLAR_IN_LABEL + +/* SCO's libraries are compiled with Microsoft C, which requires the + caller to pop the extra argument passed to functions that return + structures. */ + +#define STRUCT_RETURN_CALLER_POP + diff --git a/gcc-1.40/config/tm-i386v.h b/gcc-1.40/config/tm-i386v.h new file mode 100644 index 0000000..573804b --- /dev/null +++ b/gcc-1.40/config/tm-i386v.h @@ -0,0 +1,86 @@ +/* Definitions for Intel 386 running system V. + Copyright (C) 1988 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 1, 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 "tm-i386.h" + +/* Use the ATT assembler syntax. */ + +#include "tm-att386.h" + +/* By default, target has a 80387. */ + +#define TARGET_DEFAULT 1 + +/* Use crt1.o as a startup file and crtn.o as a closing file. */ + +#define STARTFILE_SPEC \ + "%{pg:gcrt1.o%s}%{!pg:%{posix:%{p:mcrtp1.o%s}%{!p:crtp1.o%s}}%{!posix:%{p:mcrt1.o%s}%{!p:crt1.o%s}}}\ + %{p:-L/usr/lib/libp}%{pg:-L/usr/lib/libp}" + +#define LIB_SPEC "%{posix:-lcposix} %{shlib:-lc_s} -lc crtn.o%s" + +/* Specify predefined symbols in preprocessor. */ + +#define CPP_PREDEFINES "-Dunix -Di386" + +#define CPP_SPEC "%{posix:-D_POSIX_SOURCE}" + +/* Allow #sccs in preprocessor. */ + +#define SCCS_DIRECTIVE + +/* Output #ident as a .ident. */ + +#define ASM_OUTPUT_IDENT(FILE, NAME) fprintf (FILE, "\t.ident \"%s\"\n", NAME); + +/* We want to output SDB debugging information. */ + +#define SDB_DEBUGGING_INFO + +/* We don't want to output DBX debugging information. */ + +#undef DBX_DEBUGGING_INFO + +/* Implicit library calls should use memcpy, not bcopy, etc. */ + +#define TARGET_MEM_FUNCTIONS + +/* Writing `int' for a bitfield forces int alignment for the structure. */ + +#define PCC_BITFIELD_TYPE_MATTERS 1 + +/* Don't write a `.optim' pseudo; this assembler doesn't handle them. */ + +#undef ASM_FILE_START_1 +#define ASM_FILE_START_1(FILE) + +/* Machines that use the AT&T assembler syntax + also return floating point values in an FP register. */ +/* 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. */ + +#define VALUE_REGNO(MODE) \ + (((MODE)==SFmode || (MODE)==DFmode) ? FIRST_FLOAT_REG : 0) + +/* 1 if N is a possible register number for a function value. */ + +#define FUNCTION_VALUE_REGNO_P(N) ((N) == 0 || (N)== FIRST_FLOAT_REG) diff --git a/gcc-1.40/config/tm-i386v4.h b/gcc-1.40/config/tm-i386v4.h new file mode 100644 index 0000000..e128b66 --- /dev/null +++ b/gcc-1.40/config/tm-i386v4.h @@ -0,0 +1,62 @@ +/* Definitions for Intel 386 running system Vr4. + Copyright (C) 1988 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 1, 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. */ + +/* Written by James Van Artsdalen, Dell Computer Corporation. + james@bigtex.cactus.org */ + +#include "tm-i386v.h" + +#undef STANDARD_STARTFILE_PREFIX +#define STANDARD_STARTFILE_PREFIX "/usr/ccs/lib/" + +/* Use crt1.o as a startup file and crtn.o as a closing file. */ + +#undef STARTFILE_SPEC +#define STARTFILE_SPEC \ + "%{pg:gcrt1.o%s}%{!pg:%{p:mcrt1.o%s}%{!p:crt1.o%s}} %{pg:gcrti.o%s}%{!pg:%{p:mcrti.o%s}%{!p:crti.o%s}} values-Xt.o%s" + +#undef LIB_SPEC +#define LIB_SPEC "%{p:-L/usr/lib/libp}%{pg:-L/usr/lib/libp} -Y P,/usr/ccs/lib:/usr/lib -Qy -lc crtn.o%s" + +/* Brain-damaged v4 include files won't work right if __STDC__ != 0 */ + +#define STDC_VALUE 0 + +/* We do not want to output SDB debugging information. */ + +#undef SDB_DEBUGGING_INFO + +#undef ASM_FILE_START +#define ASM_FILE_START(FILE) \ + do { \ + char *p = (char *) strrchr(main_input_filename, '/'); \ + if (!p++) \ + p = main_input_filename; \ + fprintf ((FILE), "\t.file\t\"%s\"\n", p); \ + } while (0) + +/* SysVr4 has a third "alignment" argument to .comm. It matters when + linking with PCC generated code when the object is less than word + length. */ + +#undef ASM_OUTPUT_COMMON +#define ASM_OUTPUT_COMMON(FILE, NAME, SIZE, ROUNDED) \ +( fputs (".comm ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%u,%u\n", (SIZE), (SIZE) < 3 ? (SIZE) : 4)) diff --git a/gcc-1.40/config/tm-i386vgas.h b/gcc-1.40/config/tm-i386vgas.h new file mode 100644 index 0000000..d8e69ff --- /dev/null +++ b/gcc-1.40/config/tm-i386vgas.h @@ -0,0 +1,121 @@ +/* Definitions for Intel 386 running system V with gnu tools + Copyright (C) 1988 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 1, 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 "tm-i386.h" +/* Use the bsd assembler syntax. */ +/* we need to do this because gas is really a bsd style assembler, + * and so doesn't work well this these att-isms: + * + * ASM_OUTPUT_SKIP is .set .,.+N, which isn't implemented in gas + * ASM_OUTPUT_LOCAL is done with .set .,.+N, but that can't be + * used to define bss static space + * + * Next is the question of whether to uses underscores. RMS didn't + * like this idea at first, but since it is now obvious that we + * need this separate tm file for use with gas, at least to get + * dbx debugging info. */ + +#include "tm-bsd386.h" + +/* these come from tm-bsd386.h, but are specific to sequent */ +#undef DBX_NO_XREFS +#undef DBX_CONTIN_LENGTH + +/* By default, target has a 80387. */ + +#define TARGET_DEFAULT 1 + +#if 0 /* These aren't right for GNU ld. */ +/* Use crt1.o as a startup file and crtn.o as a closing file. */ + +#define STARTFILE_SPEC \ + "%{pg:gcrt1.o%s}%{!pg:%{p:mcrt1.o%s}%{!p:crt1.o%s}}" + +#define LIB_SPEC "%{p:-L/usr/lib/libp}%{pg:-L/usr/lib/libp} -lc crtn.o%s" +#endif + +/* Specify predefined symbols in preprocessor. */ + +#define CPP_PREDEFINES "-Dunix -Di386" + +/* Allow #sccs in preprocessor. */ + +#define SCCS_DIRECTIVE + +/* Output #ident as a .ident. */ + +#define ASM_OUTPUT_IDENT(FILE, NAME) fprintf (FILE, "\t.ident \"%s\"\n", NAME); + +/* We do not want to output SDB debugging information. */ + +#undef SDB_DEBUGGING_INFO + +/* We want to output DBX debugging information. */ + +#define DBX_DEBUGGING_INFO + +/* Implicit library calls should use memcpy, not bcopy, etc. */ + +#define TARGET_MEM_FUNCTIONS + +/* Writing `int' for a bitfield forces int alignment for the structure. */ + +#define PCC_BITFIELD_TYPE_MATTERS 1 + +#undef ASM_FILE_START +#define ASM_FILE_START(FILE) \ + fprintf (FILE, "\t.file\t\"%s\"\n", dump_base_name); + +/* This is how to output a reference to a user-level label named NAME. */ +#undef ASM_OUTPUT_LABELREF +#define ASM_OUTPUT_LABELREF(FILE,NAME) \ + fprintf (FILE, "_%s", NAME) + +#if 0 /* People say gas uses the log as the arg to .align. */ +/* When using gas, .align N aligns to an N-byte boundary. */ + +#undef ASM_OUTPUT_ALIGN +#define ASM_OUTPUT_ALIGN(FILE,LOG) \ + if ((LOG)!=0) fprintf ((FILE), "\t.align %d\n", 1<<(LOG)) +#endif + +/* Align labels, etc. at 4-byte boundaries. */ + +#define ASM_OUTPUT_ALIGN_CODE(FILE) \ + fprintf ((FILE), "\t.align 2\n"); /* Use log of 4 as arg. */ + +#if 0 +#define ASM_OUTPUT_ALIGN_CODE(FILE) \ + fprintf ((FILE), "\t.align 4\n"); +#endif + +/* Machines that use the AT&T assembler syntax + also return floating point values in an FP register. */ +/* 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. */ + +#define VALUE_REGNO(MODE) \ + (((MODE)==SFmode || (MODE)==DFmode) ? FIRST_FLOAT_REG : 0) + +/* 1 if N is a possible register number for a function value. */ + +#define FUNCTION_VALUE_REGNO_P(N) ((N) == 0 || (N)== FIRST_FLOAT_REG) diff --git a/gcc-1.40/config/tm-i860.h b/gcc-1.40/config/tm-i860.h new file mode 100644 index 0000000..ee0bacb --- /dev/null +++ b/gcc-1.40/config/tm-i860.h @@ -0,0 +1,1228 @@ +/* Definitions of target machine for GNU compiler, for Intel 860. + Copyright (C) 1989 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 1, 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. */ + + +/* Note that some other tm- files include this one and then override + many of the definitions that relate to assembler syntax. */ + + +/* Names to predefine in the preprocessor for this target machine. */ + +#define CPP_PREDEFINES "-Di860 -Dunix" + +/* Print subsidiary information on the compiler version in use. */ +#define TARGET_VERSION fprintf (stderr, " (i860)"); + +/* Run-time compilation parameters selecting different hardware subsets. + + On the i860, we have one: TARGET_FPU. */ + +extern int target_flags; + +/* Nonzero if we should generate code to use the fpu. */ +#define TARGET_FPU (target_flags & 1) + +/* 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", 1}, \ + {"soft-float", -1}, \ + { "", TARGET_DEFAULT}} + +#define TARGET_DEFAULT 1 + +/* target machine storage layout */ + +/* Define this if most significant bit is lowest numbered + in instructions that operate on numbered bit-fields. + This is a moot question on the i860 due to the lack of bit-field insns. */ +/* #define BITS_BIG_ENDIAN */ + +/* Define this if most significant byte of a word is the lowest numbered. */ +/* That is not true on i860 in the mode we will use. */ +/* #define BYTES_BIG_ENDIAN */ + +/* Define this if most significant word of a multiword number is numbered. */ +/* For the i860 this goes with BYTES_BIG_ENDIAN. */ +/* #define WORDS_BIG_ENDIAN */ + +/* number of bits in an addressible 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 32 + +/* Width of a word, in units (bytes). */ +#define UNITS_PER_WORD 4 + +/* Width in bits of a pointer. + See also the macro `Pmode' defined below. */ +#define POINTER_SIZE 32 + +/* Allocation boundary (in *bits*) for storing pointers in memory. */ +#define POINTER_BOUNDARY 32 + +/* Allocation boundary (in *bits*) for storing arguments in argument list. */ +#define PARM_BOUNDARY 32 + +/* Boundary (in *bits*) on which stack pointer should be aligned. */ +#define STACK_BOUNDARY 128 + +/* Allocation boundary (in *bits*) for the code of a function. */ +#define FUNCTION_BOUNDARY 32 + +/* Alignment of field after `int : 0' in a structure. */ +#define EMPTY_FIELD_BOUNDARY 32 + +/* Every structure's size must be a multiple of this. */ +#define STRUCTURE_SIZE_BOUNDARY 8 + +/* No data type wants to be aligned rounder than this. */ +#define BIGGEST_ALIGNMENT 64 + +/* Define this if move instructions will actually fail to work + when given unaligned data. */ +#define STRICT_ALIGNMENT + +/* If bit field type is int, dont let it cross an int, + and give entire struct the alignment of an int. */ +#define PCC_BITFIELD_TYPE_MATTERS 1 + +/* 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. + + i860 has 32 fullword registers and 32 floating point registers. */ + +#define FIRST_PSEUDO_REGISTER 64 + +/* 1 for registers that have pervasive standard uses + and are not available for the register allocator. + On the i860, this includes the always-0 registers + and fp, sp, and the return address. + Also r31, used for special purposes for constant addresses. */ +#define FIXED_REGISTERS \ + {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, 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} + +/* 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. + On the i860, these are r0-r3, r16-r31, f0, f1, and f16-f31. */ +#define CALL_USED_REGISTERS \ + {1, 1, 1, 1, 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, \ + 1, 1, 1, 1, 1, 1, 1, 1, \ + 1, 1, 1, 1, 1, 1, 1, 1, \ + 1, 1, 1, 1, 1, 1, 1, 1} + +#define REG_ALLOC_ORDER \ + {16, 17, 18, 19, 20, 21, 22, 23, \ + 24, 25, 26, 27, 28, 29, 30, 31, \ + 0, 1, 2, 3, 4, 5, 6, 7, \ + 8, 9, 10, 11, 12, 13, 14, 15, \ + 40, 41, 42, 43, 44, 45, 46, 47, \ + 48, 49, 50, 51, 52, 53, 54, 55, \ + 56, 57, 58, 59, 60, 61, 62, 63, \ + 32, 33, 34, 35, 36, 37, 38, 39} + +/* 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 the i860, all registers hold 32 bits worth. */ +#define HARD_REGNO_NREGS(REGNO, MODE) \ + (((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)) + +/* Value is 1 if hard register REGNO can hold a value of machine-mode MODE. + On the i860, any register can hold anything, provided it is properly + aligned. */ +#define HARD_REGNO_MODE_OK(REGNO, MODE) \ + (((GET_MODE_SIZE ((MODE)) <= 4) || ((REGNO) & 1) == 0) \ + && ((REGNO) < 32 || TARGET_FPU)) + +/* 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. */ +/* I think that is not always true; alignment restrictions for doubles + should not prevent tying them with singles. So try allowing that. + On the other hand, don't let fixed and floating be tied; + this restriction is not necessary, but may make better code. */ +#define MODES_TIEABLE_P(MODE1, MODE2) \ + ((GET_MODE_CLASS ((MODE1)) == MODE_FLOAT) \ + == (GET_MODE_CLASS ((MODE2)) == MODE_FLOAT)) + +/* Specify the registers used for certain standard purposes. + The values of these macros are register numbers. */ + +/* i860 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 2 + +/* Base register for access to local variables of the function. */ +#define FRAME_POINTER_REGNUM 3 + +/* 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. */ +#define FRAME_POINTER_REQUIRED 1 + +/* Base register for access to arguments of the function. */ +#define ARG_POINTER_REGNUM 28 + +/* Register in which static-chain is passed to a function. */ +#define STATIC_CHAIN_REGNUM 29 + +/* Register in which address to store a structure value + is passed to a function. */ +#define STRUCT_VALUE_REGNUM 16 + +/* 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 i860 has two kinds of registers, hence four classes. */ + +enum reg_class { NO_REGS, GENERAL_REGS, 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", "GENERAL_REGS", "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}, {0xffffffff, 0}, \ + {0, 0xffffffff}, {0xffffffff, 0xffffffff}} + +/* 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. */ + +#define REGNO_REG_CLASS(REGNO) \ + ((REGNO) >= 32 ? FP_REGS : GENERAL_REGS) + +/* The class value for index registers, and the one for base regs. */ +#define INDEX_REG_CLASS GENERAL_REGS +#define BASE_REG_CLASS GENERAL_REGS + +/* Get reg_class from a letter such as appears in the machine description. */ + +#define REG_CLASS_FROM_LETTER(C) \ + ((C) == 'f' ? FP_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. + + For the i860, `I' is used for the range of constants + an add/subtract insn can actually contain. + But not including -0x8000, since we need + to negate the constant sometimes. + `J' is used for the range which is just zero (since that is R0). + `K' is used for the range allowed in bte. + `L' is used for the range allowed in logical insns. */ + +#define SMALL_INT(X) ((unsigned) (INTVAL (X) + 0x7fff) < 0xffff) + +#define LOGIC_INT(X) ((unsigned) INTVAL (X) < 0x10000) + +#define SMALL_INTVAL(X) ((unsigned) ((X) + 0x7fff) < 0xffff) + +#define LOGIC_INTVAL(X) ((unsigned) (X) < 0x10000) + +#define CONST_OK_FOR_LETTER_P(VALUE, C) \ + ((C) == 'I' ? ((unsigned) (VALUE) + 0x7fff) < 0xffff \ + : (C) == 'J' ? (VALUE) == 0 \ + : (C) == 'K' ? (unsigned) (VALUE) < 0x20 \ + : (C) == 'L' ? (unsigned) (VALUE) < 0x10000 \ + : 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' && CONST_DOUBLE_LOW ((VALUE)) == 0 \ + && CONST_DOUBLE_HIGH ((VALUE)) == 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. */ +#define PREFERRED_RELOAD_CLASS(X,CLASS) (CLASS) + +/* Return the maximum number of consecutive registers + needed to represent mode MODE in a register of class CLASS. */ +/* On the i860, this is the size of MODE in words. */ +#define CLASS_MAX_NREGS(CLASS, MODE) \ + ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD) + +/* Stack layout; function entry, exit and calling. */ + +/* 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. */ +#define STARTING_FRAME_OFFSET 0 + +/* If we generate an insn to push BYTES bytes, + this says how many the stack pointer really advances by. + On the i860, don't define this because there are no push insns. */ +/* #define PUSH_ROUNDING(BYTES) */ + +/* Offset of first parameter from the argument pointer register value. */ +#define FIRST_PARM_OFFSET(FNDECL) 0 + +/* Value is 1 if returning from a function call automatically + pops the arguments described by the number-of-args field in the call. + 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. */ + +#define RETURN_POPS_ARGS(FUNTYPE) 0 + +/* 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 the i860, the value register depends on the mode. */ + +#define FUNCTION_VALUE(VALTYPE, FUNC) \ + gen_rtx (REG, TYPE_MODE (VALTYPE), \ + (GET_MODE_CLASS (TYPE_MODE (VALTYPE)) == MODE_FLOAT \ + ? 40 : 16)) + +/* 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, \ + (GET_MODE_CLASS ((MODE)) == MODE_FLOAT \ + ? 40 : 16)) + +/* 1 if N is a possible register number for a function value + as seen by the caller. */ + +#define FUNCTION_VALUE_REGNO_P(N) ((N) == 40 || (N) == 16) + +/* 1 if N is a possible register number for function argument passing. + On the i860, these are r16-r27 and f8-f15. */ + +#define FUNCTION_ARG_REGNO_P(N) \ + (((N) < 28 && (N) > 15) || ((N) < 48 && (N) >= 40)) + +/* 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 the i860, we must count separately the number of general registers used + and the number of float registers used. */ + +#define CUMULATIVE_ARGS struct { int ints, floats; } + +/* 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. + + On the i860, the general-reg offset normally starts at 0, + but starts at 4 bytes + when the function gets a structure-value-address as an + invisible first argument. */ + +#define INIT_CUMULATIVE_ARGS(CUM,FNTYPE) \ + ((CUM).ints = ((FNTYPE) != 0 && aggregate_value_p ((FNTYPE)) \ + ? 4 : 0), \ + (CUM).floats = 0) + +/* Machine-specific subroutines of the following macros. */ +#define CEILING(X,Y) (((X) + (Y) - 1) / (Y)) +#define ROUNDUP(X,Y) (CEILING ((X), (Y)) * (Y)) + +/* 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.) + Floats, and doubleword ints, are returned in f regs; + other ints, in r regs. + Aggregates, even short ones, are passed in memory. */ + +#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \ + ((TYPE) != 0 && (TREE_CODE ((TYPE)) == RECORD_TYPE \ + || TREE_CODE ((TYPE)) == UNION_TYPE) \ + ? 0 \ + : GET_MODE_CLASS ((MODE)) == MODE_FLOAT || (MODE) == DImode \ + ? ((CUM).floats = (ROUNDUP ((CUM).floats, GET_MODE_SIZE ((MODE))) \ + + ROUNDUP (GET_MODE_SIZE (MODE), 4))) \ + : GET_MODE_CLASS ((MODE)) == MODE_INT \ + ? ((CUM).ints = (ROUNDUP ((CUM).ints, GET_MODE_SIZE ((MODE))) \ + + ROUNDUP (GET_MODE_SIZE (MODE), 4))) \ + : 0) + +/* 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). */ + +/* On the i860, the first 12 words of integer arguments go in r16-r27, + and the first 8 words of floating arguments go in f8-f15. + DImode values are treated as floats. */ + +#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \ + ((TYPE) != 0 && (TREE_CODE ((TYPE)) == RECORD_TYPE \ + || TREE_CODE ((TYPE)) == UNION_TYPE) \ + ? 0 \ + : GET_MODE_CLASS ((MODE)) == MODE_FLOAT || (MODE) == DImode \ + ? (ROUNDUP ((CUM).floats, GET_MODE_SIZE ((MODE))) < 32 \ + ? gen_rtx (REG, (MODE), \ + 40+(ROUNDUP ((CUM).floats, \ + GET_MODE_SIZE ((MODE))) \ + / 4)) \ + : 0) \ + : GET_MODE_CLASS ((MODE)) == MODE_INT \ + ? (ROUNDUP ((CUM).ints, GET_MODE_SIZE ((MODE))) < 48 \ + ? gen_rtx (REG, (MODE), \ + 16+(ROUNDUP ((CUM).ints, \ + GET_MODE_SIZE ((MODE))) \ + / 4)) \ + : 0) \ + : 0) + +/* 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. */ + +#define FUNCTION_ARG_PARTIAL_NREGS(CUM, MODE, TYPE, NAMED) 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. */ + +#define FUNCTION_PROLOGUE(FILE, SIZE) \ +{ \ + extern char call_used_regs[]; \ + int fsize = (SIZE); \ + int nregs, i; \ + for (i = 0, nregs = 0; i < FIRST_PSEUDO_REGISTER; i++) \ + { \ + if (regs_ever_live[i] && ! call_used_regs[i]) \ + nregs++; \ + } \ + fsize += nregs * 4 + 8; \ + fsize = (fsize + 15) & -16; \ + if (fsize > 0x7fff) \ + { \ + fprintf (FILE, "\tadds -16,sp,sp\n"); \ + fprintf (FILE, "\tst.l fp,8(sp)\n"); \ + fprintf (FILE, "\tst.l r1,12(sp)\n"); \ + fprintf (FILE, "\tadds 8,sp,fp\n"); \ + fprintf (FILE, "\torh %d,r0,r31\n", (fsize - 16) >> 16); \ + fprintf (FILE, "\tor %d,r31,r31\n", (fsize - 16) & 0xffff); \ + fprintf (FILE, "\tsubs sp,r31,sp\n"); \ + } \ + else \ + { \ + fprintf (FILE, "\tadds -%d,sp,sp\n", fsize); \ + fprintf (FILE, "\tst.l fp,%d(sp)\n", fsize - 8); \ + fprintf (FILE, "\tst.l r1,%d(sp)\n", fsize - 4); \ + fprintf (FILE, "\tadds %d,sp,fp\n", fsize - 8); \ + } \ + for (i = 0, nregs = 0; i < 32; i++) \ + if (regs_ever_live[i] && ! call_used_regs[i]) \ + fprintf (FILE, "\tst.l %s,%d(sp)\n", \ + reg_names[i], 4 * nregs++); \ + for (i = 32; i < 64; i++) \ + if (regs_ever_live[i] && ! call_used_regs[i]) \ + fprintf (FILE, "\tfst.l %s,%d(sp)\n", \ + reg_names[i], 4 * nregs++); \ +} +/* ??? maybe save pairs or quads of fp registers. */ + +/* Output assembler code to FILE to increment profiler label # LABELNO + for profiling a function entry. */ + +#define FUNCTION_PROFILER(FILE, LABELNO) \ + abort (); + +/* 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. */ + +/* #define EXIT_IGNORE_STACK 0 */ + +/* 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) \ +{ \ + extern char call_used_regs[]; \ + int fsize = (SIZE); \ + int nregs, i; \ + for (i = 0, nregs = 0; i < FIRST_PSEUDO_REGISTER; i++) \ + { \ + if (regs_ever_live[i] && ! call_used_regs[i]) \ + nregs++; \ + } \ + fsize += nregs * 4 + 8; \ + fsize = (fsize + 15) & -16; \ + if (fsize < 0x7fff) \ + { \ + for (i = 0, nregs = 0; i < 32; i++) \ + if (regs_ever_live[i] && ! call_used_regs[i]) \ + fprintf (FILE, "\tld.l %d(fp),%s\n", \ + 4 * nregs++ - (fsize - 8), reg_names[i]); \ + for (i = 32; i < 64; i++) \ + if (regs_ever_live[i] && ! call_used_regs[i]) \ + fprintf (FILE, "\tfld.l %d(fp),%s\n", \ + 4 * nregs++ - (fsize - 8), reg_names[i]); \ + } \ + else \ + { \ + fprintf (FILE, "\torh %d,r0,r31\n", (fsize - 8) >> 16); \ + fprintf (FILE, "\tor %d,r31,r31\n", (fsize - 8) & 0xffff); \ + fprintf (FILE, "\tsubs fp,r31,sp\n"); \ + for (i = 0, nregs = 0; i < 32; i++) \ + if (regs_ever_live[i] && ! call_used_regs[i]) \ + fprintf (FILE, "\tld.l %d(sp),%s\n", \ + 4 * nregs++, reg_names[i]); \ + for (i = 32; i < 64; i++) \ + if (regs_ever_live[i] && ! call_used_regs[i]) \ + fprintf (FILE, "\tfld.l %d(sp),%s\n", \ + 4 * nregs++, reg_names[i]); \ + } \ + if (fsize < 0x7fff) \ + { \ + fprintf (FILE, "\tld.l 4(fp),r1\n"); \ + fprintf (FILE, "\tld.l 0(fp),fp\n"); \ + fprintf (FILE, "\tbri r1\n\taddu %d,sp,sp\n", fsize); \ + } \ + else \ + { \ + fprintf (FILE, "\tld.l 4(fp),r1\n"); \ + fprintf (FILE, "\tadds 8,fp,r31\n"); \ + fprintf (FILE, "\tld.l 0(fp),fp\n"); \ + fprintf (FILE, "\tbri r1\n\tmov r31,sp\n"); \ + } \ +} + +/* If the memory address ADDR is relative to the frame pointer, + correct it to be relative to the stack pointer instead. + This is for when we don't use a frame pointer. + ADDR should be a variable name. */ + +#define FIX_FRAME_POINTER_ADDRESS(ADDR,DEPTH) abort (); + +/* 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] < 32) +#define REGNO_OK_FOR_BASE_P(REGNO) \ +((REGNO) < 32 || (unsigned) reg_renumber[REGNO] < 32) +#define REGNO_OK_FOR_FP_P(REGNO) \ +(((REGNO) ^ 0x20) < 32 || (unsigned) (reg_renumber[REGNO] ^ 0x20) < 32) + +/* 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 i860, 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))) + +/* 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. */ + +#define CONSTANT_ADDRESS_P(X) CONSTANT_P (X) + +/* Nonzero if the constant value X is a legitimate general operand. + It is given that X satisfies CONSTANT_P or is a CONST_DOUBLE. + + On the Sparc, this is anything but a CONST_DOUBLE. + Let's try permitting CONST_DOUBLEs and see what happens. */ + +#define LEGITIMATE_CONSTANT_P(X) 1 + +/* 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. */ + +#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 >= 14) +/* 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 >= 14) + +#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)) + +#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 the i860, the actual addresses must be REG+REG or REG+SMALLINT. + But we can treat a SYMBOL_REF as legitimate if it is part of this + function's constant-pool, because such addresses can actually + be output as REG+SMALLINT. + + The displacement in an address must be a multiple of the alignment. + + Try making SYMBOL_REF (and other things which are CONSTANT_ADDRESS_P) + a legitimate address, regardless. Because the only insns which can use + memory are load or store insns, the added hair in the machine description + is not that bad. It should also speed up the compiler by halving the number + of insns it must manage for each (MEM (SYMBOL_REF ...)) involved. */ + +#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \ +{ if (GET_CODE (X) == REG) \ + { if (REG_OK_FOR_BASE_P (X)) goto ADDR; } \ + else if (GET_CODE (X) == PLUS) \ + { \ + if (GET_CODE (XEXP (X, 0)) == REG \ + && REG_OK_FOR_BASE_P (XEXP (X, 0))) \ + { \ + if (GET_CODE (XEXP (X, 1)) == CONST_INT \ + && INTVAL (XEXP (X, 1)) >= -0x8000 \ + && INTVAL (XEXP (X, 1)) < 0x8000 \ + && INTVAL (XEXP (X, 1)) & (GET_MODE_SIZE (MODE) - 1) == 0) \ + goto ADDR; \ + } \ + else if (GET_CODE (XEXP (X, 1)) == REG \ + && REG_OK_FOR_BASE_P (XEXP (X, 1))) \ + { \ + if (GET_CODE (XEXP (X, 0)) == CONST_INT \ + && INTVAL (XEXP (X, 0)) >= -0x8000 \ + && INTVAL (XEXP (X, 0)) < 0x8000 \ + && INTVAL (XEXP (X, 0)) & (GET_MODE_SIZE (MODE) - 1) == 0) \ + goto ADDR; \ + } \ + } \ + else if (CONSTANT_ADDRESS_P (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 the i860, change COMPLICATED + CONSTANT to REG+CONSTANT. + Also change a symbolic constant to a REG, + though that may not be necessary. */ + +#define LEGITIMIZE_ADDRESS(X,OLDX,MODE,WIN) \ +{ if (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 0)) == MULT) \ + (X) = gen_rtx (PLUS, SImode, XEXP (X, 1), \ + force_operand (XEXP (X, 0), 0)); \ + if (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 1)) == MULT) \ + (X) = gen_rtx (PLUS, SImode, XEXP (X, 0), \ + force_operand (XEXP (X, 1), 0)); \ + if (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 0)) == PLUS) \ + (X) = gen_rtx (PLUS, SImode, XEXP (X, 1), \ + force_operand (XEXP (X, 0), 0)); \ + if (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 1)) == PLUS) \ + (X) = gen_rtx (PLUS, SImode, XEXP (X, 0), \ + force_operand (XEXP (X, 1), 0)); \ + if (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 0)) != REG \ + && GET_CODE (XEXP (X, 0)) != CONST_INT) \ + (X) = gen_rtx (PLUS, SImode, XEXP (X, 1), \ + copy_to_mode_reg (SImode, XEXP (X, 0))); \ + if (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 1)) != REG \ + && GET_CODE (XEXP (X, 1)) != CONST_INT) \ + (X) = gen_rtx (PLUS, SImode, XEXP (X, 0), \ + copy_to_mode_reg (SImode, XEXP (X, 1))); \ + if (GET_CODE (x) == SYMBOL_REF) \ + (X) = copy_to_reg (X); \ + if (GET_CODE (x) == CONST) \ + (X) = copy_to_reg (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 i860 this is never true. + There are some addresses that are invalid in wide modes + but valid for narrower modes, but they shouldn't cause trouble. */ + +#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR,LABEL) + +/* On the 860, every legit address is offsettable, + but GCC would have trouble figuring this out. */ + +#define OFFSETTABLE_ADDRESS_P(MODE, ADDR) (memory_address_p ((MODE), (ADDR))) + +/* 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. + Do not define this if the table should contain absolute addresses. */ +/* #define CASE_VECTOR_PC_RELATIVE */ + +/* 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 + +/* Must pass floats to gnulib functions as doubles. */ +#define GNULIB_NEEDS_DOUBLE 1 + +#define DIVSI3_LIBCALL "*.div" +#define UDIVSI3_LIBCALL "*.udiv" +#define REMSI3_LIBCALL "*.rem" +#define UREMSI3_LIBCALL "*.urem" + +/* 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 16 + +/* Nonzero if access to memory by bytes is slow and undesirable. */ +#define SLOW_BYTE_ACCESS 0 + +/* This is System V, so it wants sdb format. */ +#define DBX_DEBUGGING_INFO + +/* 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 SImode + +/* 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 + +/* 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) \ + case CONST_INT: \ + if (INTVAL (RTX) == 0) \ + return 0; \ + if (INTVAL (RTX) < 0x2000 && INTVAL (RTX) >= -0x2000) return 1; \ + case CONST: \ + case LABEL_REF: \ + case SYMBOL_REF: \ + return 2; \ + case CONST_DOUBLE: \ + return 2 * GET_MODE_SIZE (GET_MODE (RTX)) / UNITS_PER_WORD; + +/* Tell final.c how to eliminate redundant test instructions. */ + +/* Here we define machine-dependent flags and fields in cc_status + (see `conditions.h'). */ + +/* This holds the value sourcing h%r31. We keep this info + around so that mem/mem ops, such as increment and decrement, + etc, can be performed reasonably. */ +#define CC_STATUS_MDEP rtx + +#define CC_STATUS_MDEP_INIT (cc_status.mdep = 0) + +/* On the i860, each comparison tests just one condition, + so only that condition can be remembered. + We don't need GT, GE, GTU and GEU because CC_REVERSED can handle them. */ +#define CC_ONLY_EQ 0100 +#define CC_ONLY_LE 0200 +#define CC_ONLY_LT 0400 +#define CC_ONLY_LEU 02000 +#define CC_ONLY_LTU 04000 +#define CC_CONDITION_MASK 07700 + +/* Non-zero to invert the sense of the condition code. */ +#define CC_NEGATED 010000 + +/* Nonzero if we know the value of h%r31. */ +#define CC_KNOW_HI_R31 0100000 + +/* Nonzero if h%r31 is actually ha%something, rather than h%something. */ +#define CC_HI_R31_ADJ 0200000 + +/* Store in cc_status the expressions + that the condition codes will describe + after execution of an instruction whose pattern is EXP. + Do not alter them if the instruction would not alter the cc's. */ + +/* On the i860, only compare insns set a useful condition code. */ + +#define NOTICE_UPDATE_CC(EXP, INSN) \ +{ cc_status.flags &= (CC_KNOW_HI_R31 | CC_HI_R31_ADJ); \ + cc_status.value1 = 0; cc_status.value2 = 0; } + +/* Control the assembler format that we output. */ + +/* Output at beginning of assembler file. */ +/* The .file command should always begin the output. */ + +#define ASM_FILE_START(FILE) +#if 0 +#define ASM_FILE_START(FILE) \ + do { sdbout_filename ((FILE), main_input_filename); \ + if (optimize) ASM_FILE_START_1 (FILE); \ + } while (0) +#endif + +#define ASM_FILE_START_1(FILE) + +/* 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 "" + +/* 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 \ +{"r0", "r1", "sp", "fp", "r4", "r5", "r6", "r7", "r8", "r9", \ + "r10", "r11", "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19", \ + "r20", "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", \ + "r30", "r31", \ + "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" } + +/* How to renumber registers for dbx and gdb. */ + +#define DBX_REGISTER_NUMBER(REGNO) (REGNO) + +/* 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) + +/* Likewise, for function names. The difference is that we output a no-op + just before the beginning of the function, to ensure that there does not + appear to be a delayed branch there. + Such a thing would confuse interrupt recovery. */ +#define ASM_DECLARE_FUNCTION_NAME(FILE,NAME,DECL) \ + do { fprintf (FILE, "\tnop\n"); ASM_OUTPUT_LABEL (FILE,NAME); } 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 (".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. */ + +#define ASM_OUTPUT_LABELREF(FILE,NAME) \ + fprintf (FILE, "_%s", NAME) + +/* 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) \ + fprintf (FILE, ".%s%d:\n", PREFIX, NUM) + +/* This is how to output an internal numbered label which + labels a jump table. */ + +#define ASM_OUTPUT_CASE_LABEL(FILE,PREFIX,NUM,JUMPTABLE) \ + fprintf (FILE, ".data\n\t.align 4\n.%s%d:\n", PREFIX, NUM) + +/* Output at the end of a jump table. */ + +#define ASM_OUTPUT_CASE_END(FILE,NUM,INSN) \ + fprintf (FILE, ".text\n") + +/* 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%d", PREFIX, NUM) + +#define ASCII_DATA_ASM_OP ".byte" +#define ASM_OUTPUT_ASCII(f, p, size) \ +{ register int i; \ + int inside; \ + inside = FALSE; \ + for (i = 0; i < size; i++) { \ + if (i % 64 == 0) { \ + if (i != 0) { \ + if (inside) \ + putc('"', f); \ + putc('\n', f); \ + inside = FALSE; \ + } \ + fprintf(f, "%s ", ASCII_DATA_ASM_OP); \ + } \ + if (p[i] < 32 || p[i] == '\\' || p[i] == '"' || p[i] == 127) { \ + if (inside) { \ + putc('"', f); \ + inside = FALSE; \ + } \ + if (i % 64 != 0) \ + putc(',', f); \ + fprintf(f, "%d", p[i]); \ + } else { \ + if (!inside) { \ + if (i % 64 != 0) \ + putc(',', f); \ + putc('"', f); \ + inside = TRUE; \ + } \ + putc(p[i], f); \ + } \ + } \ + if (inside) \ + putc('"', f); \ + putc('\n', f); \ +} + +/* This is how to output an assembler line defining a `double' constant. */ + +#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \ + fprintf (FILE, "\t.double %.20e\n", (VALUE)) + +/* This is how to output an assembler line defining a `float' constant. */ + +#define ASM_OUTPUT_FLOAT(FILE,VALUE) \ + fprintf (FILE, "\t.float %.12e\n", (VALUE)) + +/* This is how to output an assembler line defining an `int' constant. */ + +#define ASM_OUTPUT_INT(FILE,VALUE) \ +( fprintf (FILE, "\t.long "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +/* Likewise for `char' and `short' constants. */ + +#define ASM_OUTPUT_SHORT(FILE,VALUE) \ +( fprintf (FILE, "\t.short "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +#define ASM_OUTPUT_CHAR(FILE,VALUE) \ +( fprintf (FILE, "\t.byte "), \ + 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.byte 0x%x\n", (VALUE)) + +/* This is how to output code to push a register on the stack. + It need not be very fast code. */ + +#define ASM_OUTPUT_REG_PUSH(FILE,REGNO) \ + fprintf (FILE, "\taddu -16,r3,r3\n\t%sst.l %s,0(r3)\n", \ + ((REGNO) < 32 ? "" : "f"), 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, "\t%sld.l 0(r3),%s\n\taddu 16,r3,r3\n", \ + ((REGNO) < 32 ? "" : "f"), reg_names[REGNO]) + +/* This is how to output an element of a case-vector that is absolute. */ + +#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \ + fprintf (FILE, "\t.long .L%d\n", VALUE) + +/* This is how to output an element of a case-vector that is relative. + (The i860 does not use such vectors, + but we must define this macro anyway.) */ + +#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, VALUE, REL) \ + fprintf (FILE, "\t.word .L%d-.L%d\n", VALUE, REL) + +/* 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 ASM_OUTPUT_SKIP(FILE,SIZE) \ + fprintf (FILE, "\t.blkb %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 (".comm ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%u\n", (ROUNDED))) + +/* This says how to output an assembler line + to define a local common symbol. */ + +#define ASM_OUTPUT_LOCAL(FILE, NAME, SIZE, ROUNDED) \ +( fputs (".lcomm ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%u\n", (ROUNDED))) + +/* 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 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 + +/* This assumes the compiler is running on a little-endian machine. + The support for the other case is left for version 2, + since there is nothing in version 1 to indicate the sex of the host. */ + +#define PRINT_OPERAND_EXTRACT_FLOAT(X) \ + u.i[0] = CONST_DOUBLE_LOW (X); u.i[1] = CONST_DOUBLE_HIGH (X); + +/* 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. + + On the i860, the CODE can be `r', meaning this is a register-only operand + and an immediate zero should be represented as `r0'. + It can also be `m', meaning this is a memory ref, + but print its address as a constant. */ + +#define PRINT_OPERAND(FILE, X, CODE) \ +{ if (GET_CODE (X) == REG) \ + fprintf (FILE, "%s", reg_names[REGNO (X)]); \ + else if ((CODE) == 'm') \ + output_address (XEXP (X, 0)); \ + else if (GET_CODE (X) == MEM) \ + output_address (XEXP (X, 0)); \ + else if ((CODE) == 'r' && (X) == const0_rtx) \ + fprintf (FILE, "r0"); \ + else if ((CODE) == 'r' && (X) == CONST0_RTX (GET_MODE (X))) \ + fprintf (FILE, "f0"); \ + else if (GET_CODE (X) == CONST_DOUBLE) \ + { \ + if (GET_MODE (X) == SFmode) \ + { union { double d; int i[2]; } u; \ + union { float f; int i; } u1; \ + PRINT_OPERAND_EXTRACT_FLOAT (X); \ + u1.f = u.d; \ + fprintf (FILE, "0x%x", u1.i); } \ + else \ + abort (); \ + } \ + else \ + output_addr_const (FILE, X); } + +/* 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) \ + { \ + fprintf (FILE, "0(%s)", reg_names[REGNO (addr)]); \ + } \ + 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); \ + if (index != 0) \ + fprintf (FILE, "%s", reg_names[REGNO (index)]); \ + else \ + fprintf (FILE, "%d", offset); \ + fprintf (FILE, "(%s)", reg_names[REGNO (base)]); \ + } \ + else \ + { \ +/* ??? this may be wrong. */ \ + output_addr_const (FILE, addr); \ + } \ +} diff --git a/gcc-1.40/config/tm-i860bsdg.h b/gcc-1.40/config/tm-i860bsdg.h new file mode 100644 index 0000000..84c5ce5 --- /dev/null +++ b/gcc-1.40/config/tm-i860bsdg.h @@ -0,0 +1,4 @@ +#include "tm-i860bsd.h" + +#undef ASCII_DATA_ASM_OP +#define ASCII_DATA_ASM_OP ".ascii" diff --git a/gcc-1.40/config/tm-i860g.h b/gcc-1.40/config/tm-i860g.h new file mode 100644 index 0000000..9bf8295 --- /dev/null +++ b/gcc-1.40/config/tm-i860g.h @@ -0,0 +1,4 @@ +#include "tm-i860.h" + +#undef ASCII_DATA_ASM_OP +#define ASCII_DATA_ASM_OP ".ascii" diff --git a/gcc-1.40/config/tm-iris.h b/gcc-1.40/config/tm-iris.h new file mode 100644 index 0000000..66c7606 --- /dev/null +++ b/gcc-1.40/config/tm-iris.h @@ -0,0 +1,48 @@ +/* Definitions of target machine for GNU compiler. Iris version. + 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 1, 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. */ + +/* Names to predefine in the preprocessor for this target machine. */ + +#define CPP_PREDEFINES "-Dunix -Dmips -Dsgi -DSVR3 -Dhost_mips -DMIPSEB -DSYSTYPE_SYSV -DLANGUAGE_C" + +#define STARTFILE_SPEC \ + "%{pg:gcrt1.o%s}%{!pg:%{p:mcrt1.o%s}%{!p:crt1.o%s}}" + +#define LIB_SPEC "%{!p:%{!pg:-lc}}%{p:-lc_p}%{pg:-lc_p} crtn.o%s" + +#define SGI_TARGET 1 /* inform other mips files this is SGI */ + +/* Always use 1 for .file number. I [meissner@osf.org] wonder why + IRIS needs this. */ + +#define SET_FILE_NUMBER() num_source_filenames = 1 + +/* Put out a label after a .loc. I [meissner@osf.org] wonder why + IRIS needs this. */ + +#define LABEL_AFTER_LOC(STREAM) fprintf (STREAM, "LM%d:\n", ++sym_lineno) + +#define STACK_ARGS_ADJUST(SIZE) \ +{ \ + SIZE.constant += 4; \ + if (SIZE.constant < 32) \ + SIZE.constant = 32; \ +} + +#include "tm-mips.h" diff --git a/gcc-1.40/config/tm-isi68-nfp.h b/gcc-1.40/config/tm-isi68-nfp.h new file mode 100644 index 0000000..c51d5a8 --- /dev/null +++ b/gcc-1.40/config/tm-isi68-nfp.h @@ -0,0 +1,5 @@ +/* Define target machine as an ISI 68000/68020 with no 68881. */ + +#define TARGET_DEFAULT 5 + +#include "tm-isi68.h" diff --git a/gcc-1.40/config/tm-isi68.h b/gcc-1.40/config/tm-isi68.h new file mode 100644 index 0000000..5900e2b --- /dev/null +++ b/gcc-1.40/config/tm-isi68.h @@ -0,0 +1,79 @@ +/* Definitions of target machine for GNU compiler. ISI 68000/68020 version. + Intended only for use with GAS, and not ISI's assembler, which is buggy + Copyright (C) 1988 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 1, 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 "tm-m68k.h" + +/* See tm-m68k.h. 7 means 68020 with 68881. */ + +#ifndef TARGET_DEFAULT +#define TARGET_DEFAULT 7 +#endif + +#if TARGET_DEFAULT & 2 +/* Define __HAVE_68881__ in preprocessor, unless -msoft-float is specified. + This will control the use of inline 68881 insns in certain macros. */ + +#define CPP_SPEC "%{!msoft-float:-D__HAVE_68881__}" + +/* If the 68881 is used, link must load libmc.a instead of libc.a */ + +#define LIB_SPEC "%{msoft-float:%{!p:%{!pg:-lc}}%{p:-lc_p}%{pg:-lc_p}}%{!msoft-float:%{!p:%{!pg:-lmc}}%{p:-lmc_p}%{pg:-lmc_p}}" + +#else +/* Define __HAVE_68881__ in preprocessor if -m68881 is specified. + This will control the use of inline 68881 insns in certain macros. */ + +#define CPP_SPEC "%{m68881:-D__HAVE_68881__}" + +/* If the 68881 is used, link must load libmc.a instead of libc.a */ + +#define LIB_SPEC "%{!m68881:%{!p:%{!pg:-lc}}%{p:-lc_p}%{pg:-lc_p}}%{m68881:%{!p:%{!pg:-lmc}}%{p:-lmc_p}%{pg:-lmc_p}}" +#endif + +/* Names to predefine in the preprocessor for this target machine. */ + +#define CPP_PREDEFINES "-Dunix -Dmc68000 -Dis68k" + +/* This is BSD, so it wants DBX format. */ + +#define DBX_DEBUGGING_INFO + +/* Override parts of tm-m68000.h to fit the ISI 68k machine. */ + +#undef FUNCTION_VALUE +#undef LIBCALL_VALUE +#undef FUNCTION_VALUE_REGNO_P +#undef ASM_FILE_START + +/* If TARGET_68881, return SF and DF values in f0 instead of d0. */ + +#define FUNCTION_VALUE(VALTYPE,FUNC) LIBCALL_VALUE (TYPE_MODE (VALTYPE)) + +#define LIBCALL_VALUE(MODE) \ + gen_rtx (REG, (MODE), ((TARGET_68881 && ((MODE) == SFmode || (MODE) == DFmode)) ? 16 : 0)) + +/* 1 if N is a possible register number for a function value. + D0 may be used, and F0 as well if -m68881 is specified. */ + +#define FUNCTION_VALUE_REGNO_P(N) \ + ((N) == 0 || (TARGET_68881 && (N) == 16)) + +/* Also output something to cause the correct _doprnt to be loaded. */ +#define ASM_FILE_START(FILE) fprintf (FILE, "#NO_APP\n%s\n", TARGET_68881 ? ".globl fltused" : "") diff --git a/gcc-1.40/config/tm-m68k.h b/gcc-1.40/config/tm-m68k.h new file mode 100644 index 0000000..256b06e --- /dev/null +++ b/gcc-1.40/config/tm-m68k.h @@ -0,0 +1,1643 @@ +/* Definitions of target machine for GNU compiler. Sun 68000/68020 version. + Copyright (C) 1987, 1988 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 1, 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. */ + + +/* Note that some other tm- files include this one and then override + many of the definitions that relate to assembler syntax. */ + + +/* Names to predefine in the preprocessor for this target machine. */ + +/* See tm-sun3.h, tm-sun2.h, tm-isi68.h for different CPP_PREDEFINES. */ + +/* Print subsidiary information on the compiler version in use. */ +#ifdef MOTOROLA +#define TARGET_VERSION fprintf (stderr, " (68k, Motorola syntax)"); +#else +#define TARGET_VERSION fprintf (stderr, " (68k, MIT syntax)"); +#endif + +/* Run-time compilation parameters selecting different hardware subsets. */ + +extern int target_flags; + +/* Macros used in the machine description to test the flags. */ + +/* Compile for a 68020 (not a 68000 or 68010). */ +#define TARGET_68020 (target_flags & 1) +/* Compile 68881 insns for floating point (not library calls). */ +#define TARGET_68881 (target_flags & 2) +/* Compile using 68020 bitfield insns. */ +#define TARGET_BITFIELD (target_flags & 4) +/* Compile using rtd insn calling sequence. + This will not work unless you use prototypes at least + for all functions that can take varying numbers of args. */ +#define TARGET_RTD (target_flags & 8) +/* Compile passing first two args in regs 0 and 1. + This exists only to test compiler features that will + be needed for RISC chips. It is not usable + and is not intended to be usable on this cpu. */ +#define TARGET_REGPARM (target_flags & 020) +/* Compile with 16-bit `int'. */ +#define TARGET_SHORT (target_flags & 040) + +/* Compile with special insns for Sun FPA. */ +#define TARGET_FPA (target_flags & 0100) + +/* 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 \ + { { "68020", 5}, \ + { "c68020", 5}, \ + { "68881", 2}, \ + { "bitfield", 4}, \ + { "68000", -5}, \ + { "c68000", -5}, \ + { "soft-float", -0102}, \ + { "nobitfield", -4}, \ + { "rtd", 8}, \ + { "nortd", -8}, \ + { "short", 040}, \ + { "noshort", -040}, \ + { "fpa", 0100}, \ + { "nofpa", -0100}, \ + { "", TARGET_DEFAULT}} +/* TARGET_DEFAULT is defined in tm-sun*.h and tm-isi68.h, etc. */ + +/* Blow away 68881 flag silently on TARGET_FPA (since we can't clear + any bits in TARGET_SWITCHES above) */ +#define OVERRIDE_OPTIONS \ +{ \ + if (TARGET_FPA) target_flags &= ~2; \ +} + +/* target machine storage layout */ + +/* Define this if most significant bit is lowest numbered + in instructions that operate on numbered bit-fields. + This is true for 68020 insns such as bfins and bfexts. + We make it true always by avoiding using the single-bit insns + except in special cases with constant bit numbers. */ +#define BITS_BIG_ENDIAN + +/* Define this if most significant byte of a word is the lowest numbered. */ +/* That is true on the 68000. */ +#define BYTES_BIG_ENDIAN + +/* Define this if most significant word of a multiword number is numbered. */ +/* For 68000 we can decide arbitrarily + since there are no machine instructions for them. */ +/* #define WORDS_BIG_ENDIAN */ + +/* number of bits in an addressible 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 32 + +/* Width of a word, in units (bytes). */ +#define UNITS_PER_WORD 4 + +/* Width in bits of a pointer. + See also the macro `Pmode' defined below. */ +#define POINTER_SIZE 32 + +/* Allocation boundary (in *bits*) for storing pointers in memory. */ +#define POINTER_BOUNDARY 16 + +/* Allocation boundary (in *bits*) for storing arguments in argument list. */ +#define PARM_BOUNDARY (TARGET_SHORT ? 16 : 32) + +/* Boundary (in *bits*) on which stack pointer should be aligned. */ +#define STACK_BOUNDARY 16 + +/* Allocation boundary (in *bits*) for the code of a function. */ +#define FUNCTION_BOUNDARY 16 + +/* Alignment of field after `int : 0' in a structure. */ +#define EMPTY_FIELD_BOUNDARY 16 + +/* No data type wants to be aligned rounder than this. */ +#define BIGGEST_ALIGNMENT 16 + +/* Define this if move instructions will actually fail to work + when given unaligned data. */ +#define STRICT_ALIGNMENT + +/* Define number of bits in most basic integer type. + (If undefined, default is BITS_PER_WORD). */ + +#define INT_TYPE_SIZE (TARGET_SHORT ? 16 : 32) + +/* 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. + For the 68000, we give the data registers numbers 0-7, + the address registers numbers 010-017, + and the 68881 floating point registers numbers 020-027. */ +#define FIRST_PSEUDO_REGISTER 56 /* 24 */ + +/* 1 for registers that have pervasive standard uses + and are not available for the register allocator. + On the 68000, only the stack pointer is such. */ +/* fpa0 is also reserved so that it can be used to move shit back and + forth between high fpa regs and everything else. */ +#define FIXED_REGISTERS \ + {0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 1, \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + /* FPA registers. */ \ + 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 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, 0, 0, 0, 0, 0, 0, \ + 1, 1, 0, 0, 0, 0, 0, 1, \ + 1, 1, 0, 0, 0, 0, 0, 0, \ + /* FPA registers. */ \ + 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, } + +/* Make sure everything's fine if we *don't* have a given processor. + This assumes that putting a register in fixed_regs will keep the + compilers mitt's completely off it. We don't bother to zero it out + of register classes. If neither TARGET_FPA or TARGET_68881 is set, + the compiler won't touch since no instructions that use these + registers will be valid. */ +#define CONDITIONAL_REGISTER_USAGE \ +{ \ + int i; \ + HARD_REG_SET x; \ + if (!TARGET_FPA) \ + { \ + COPY_HARD_REG_SET (x, reg_class_contents[(int)FPA_REGS]); \ + for (i = 0; i < FIRST_PSEUDO_REGISTER; i++ ) \ + if (TEST_HARD_REG_BIT (x, i)) \ + fixed_regs[i] = call_used_regs[i] = 1; \ + } \ + if (TARGET_FPA) \ + { \ + COPY_HARD_REG_SET (x, reg_class_contents[(int)FP_REGS]); \ + for (i = 0; i < FIRST_PSEUDO_REGISTER; i++ ) \ + if (TEST_HARD_REG_BIT (x, i)) \ + fixed_regs[i] = call_used_regs[i] = 1; \ + } \ +} + +/* 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 the 68000, ordinary registers hold 32 bits worth; + for the 68881 registers, a single register is always enough for + anything that can be stored in them at all. */ +#define HARD_REGNO_NREGS(REGNO, MODE) \ + ((REGNO) >= 16 ? 1 \ + : ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)) + +/* Value is 1 if hard register REGNO can hold a value of machine-mode MODE. + On the 68000, the cpu registers can hold any mode but the 68881 registers + can hold only SFmode or DFmode. And the 68881 registers can't hold anything + if 68881 use is disabled. However, the Sun FPA register can + (apparently) hold whatever you feel like putting in them. */ +#define HARD_REGNO_MODE_OK(REGNO, MODE) \ + (((REGNO) < 16 && \ + (!TARGET_FPA || (MODE) != DFmode || (REGNO) != 7)) \ + || ((REGNO) < 24 \ + ? TARGET_68881 && ((MODE) == SFmode || (MODE) == DFmode) \ + : ((REGNO) < 56 \ + ? TARGET_FPA : 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. */ +#define MODES_TIEABLE_P(MODE1, MODE2) \ + (! TARGET_68881 \ + || (((MODE1) == SFmode || (MODE1) == DFmode) \ + == ((MODE2) == SFmode || (MODE2) == DFmode))) + +/* Specify the registers used for certain standard purposes. + The values of these macros are register numbers. */ + +/* m68000 pc isn't overloaded on a register. */ +/* #define PC_REGNUM */ + +/* Register to use for pushing function arguments. */ +#define STACK_POINTER_REGNUM 15 + +/* Base register for access to local variables of the function. */ +#define FRAME_POINTER_REGNUM 14 + +/* 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. */ +#define FRAME_POINTER_REQUIRED 0 + +/* Base register for access to arguments of the function. */ +#define ARG_POINTER_REGNUM 14 + +/* Register in which static-chain is passed to a function. */ +#define STATIC_CHAIN_REGNUM 8 + +/* Register in which address to store a structure value + is passed to a function. */ +#define STRUCT_VALUE_REGNUM 9 + +/* 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 68000 has three kinds of registers, so eight classes would be + a complete set. One of them is not needed. */ + +/* + * Notes on final choices: + * + * 1) Didn't feel any need to union-ize LOW_FPA_REGS with anything + * else. + * 2) Removed all unions that involve address registers with + * floating point registers (left in unions of address and data with + * floating point). + * 3) Defined GENERAL_REGS as ADDR_OR_DATA_REGS. + * 4) Defined ALL_REGS as FPA_OR_FP_OR_GENERAL_REGS. + * 4) Left in everything else. + */ +enum reg_class { NO_REGS, LO_FPA_REGS, FPA_REGS, FP_REGS, + FP_OR_FPA_REGS, DATA_REGS, DATA_OR_FPA_REGS, DATA_OR_FP_REGS, + DATA_OR_FP_OR_FPA_REGS, ADDR_REGS, GENERAL_REGS, + GENERAL_OR_FPA_REGS, GENERAL_OR_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", "LO_FPA_REGS", "FPA_REGS", "FP_REGS", \ + "FP_OR_FPA_REGS", "DATA_REGS", "DATA_OR_FPA_REGS", "DATA_OR_FP_REGS", \ + "DATA_OR_FP_OR_FPA_REGS", "ADDR_REGS", "GENERAL_REGS", \ + "GENERAL_OR_FPA_REGS", "GENERAL_OR_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}, /* NO_REGS */ \ + {0xff000000, 0x000000ff}, /* LO_FPA_REGS */ \ + {0xff000000, 0x00ffffff}, /* FPA_REGS */ \ + {0x00ff0000, 0x00000000}, /* FP_REGS */ \ + {0xffff0000, 0x00ffffff}, /* FP_OR_FPA_REGS */ \ + {0x000000ff, 0x00000000}, /* DATA_REGS */ \ + {0xff0000ff, 0x00ffffff}, /* DATA_OR_FPA_REGS */ \ + {0x00ff00ff, 0x00000000}, /* DATA_OR_FP_REGS */ \ + {0xffff00ff, 0x00ffffff}, /* DATA_OR_FP_OR_FPA_REGS */\ + {0x0000ff00, 0x00000000}, /* ADDR_REGS */ \ + {0x0000ffff, 0x00000000}, /* GENERAL_REGS */ \ + {0xff00ffff, 0x00ffffff}, /* GENERAL_OR_FPA_REGS */\ + {0x00ffffff, 0x00000000}, /* GENERAL_OR_FP_REGS */\ + {0xffffffff, 0x00ffffff}, /* ALL_REGS */ \ +} + +/* 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 regno_reg_class[]; +#define REGNO_REG_CLASS(REGNO) (regno_reg_class[(REGNO)>>3]) + +/* The class value for index registers, and the one for base regs. */ + +#define INDEX_REG_CLASS GENERAL_REGS +#define BASE_REG_CLASS ADDR_REGS + +/* Get reg_class from a letter such as appears in the machine description. + We do a trick here to modify the effective constraints on the + machine description; we zorch the constraint letters that aren't + appropriate for a specific target. This allows us to guarantee + that a specific kind of register will not be used for a given target + without fiddling with the register classes above. */ + +#define REG_CLASS_FROM_LETTER(C) \ + ((C) == 'a' ? ADDR_REGS : \ + ((C) == 'd' ? DATA_REGS : \ + ((C) == 'f' ? (TARGET_68881 ? FP_REGS : \ + NO_REGS) : \ + ((C) == 'x' ? (TARGET_FPA ? FPA_REGS : \ + NO_REGS) : \ + ((C) == 'y' ? (TARGET_FPA ? LO_FPA_REGS : \ + NO_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. + + For the 68000, `I' is used for the range 1 to 8 + allowed as immediate shift counts and in addq. + `J' is used for the range of signed numbers that fit in 16 bits. + `K' is for numbers that moveq can't handle. + `L' is for range -8 to -1, range of values that can be added with subq. */ + +#define CONST_OK_FOR_LETTER_P(VALUE, C) \ + ((C) == 'I' ? (VALUE) > 0 && (VALUE) <= 8 : \ + (C) == 'J' ? (VALUE) >= -0x8000 && (VALUE) <= 0x7FFF : \ + (C) == 'K' ? (VALUE) < -0x80 || (VALUE) >= 0x80 : \ + (C) == 'L' ? (VALUE) < 0 && (VALUE) >= -8 : 0) + +/* + * A small bit of explanation: + * "G" defines all of the floating constants that are *NOT* 68881 + * constants. this is so 68881 constants get reloaded and the + * fpmovecr is used. "H" defines *only* the class of constants that + * the fpa can use, because these can be gotten at in any fpa + * instruction and there is no need to force reloads. + */ + +#define CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C) \ + ((C) == 'G' ? ! (TARGET_68881 && standard_68881_constant_p (VALUE)) : \ + (C) == 'H' ? (TARGET_FPA && standard_sun_fpa_constant_p (VALUE)) : 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. + On the 68000 series, use a data reg if possible when the + value is a constant in the range where moveq could be used + and we ensure that QImodes are reloaded into data regs. */ + +#define PREFERRED_RELOAD_CLASS(X,CLASS) \ + ((GET_CODE (X) == CONST_INT \ + && (unsigned) (INTVAL (X) + 0x80) < 0x100 \ + && (CLASS) != ADDR_REGS) \ + ? DATA_REGS \ + : GET_MODE (X) == QImode \ + ? DATA_REGS \ + : (CLASS)) + +/* Return the maximum number of consecutive registers + needed to represent mode MODE in a register of class CLASS. */ +/* On the 68000, this is the size of MODE in words, + except in the FP regs, where a single reg is always enough. */ +#define CLASS_MAX_NREGS(CLASS, MODE) \ + ((CLASS) == FP_REGS || (CLASS) == FPA_REGS || (CLASS) == LO_FPA_REGS ? 1 \ + : ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)) + +/* Stack layout; function entry, exit and calling. */ + +/* 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. */ +#define STARTING_FRAME_OFFSET 0 + +/* If we generate an insn to push BYTES bytes, + this says how many the stack pointer really advances by. + On the 68000, sp@- in a byte insn really pushes a word. */ +#define PUSH_ROUNDING(BYTES) (((BYTES) + 1) & ~1) + +/* Offset of first parameter from the argument pointer register value. */ +#define FIRST_PARM_OFFSET(FNDECL) 8 + +/* Value is 1 if returning from a function call automatically + pops the arguments described by the number-of-args field in the call. + 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. + + On the 68000, the RTS insn cannot pop anything. + On the 68010, the RTD insn may be used to pop them if the number + of args is fixed, but if the number is variable then the caller + must pop them all. RTD can't be used for library calls now + because the library is compiled with the Unix compiler. + Use of RTD is a selectable option, since it is incompatible with + standard Unix calling sequences. If the option is not selected, + the caller must always pop the args. */ + +#define RETURN_POPS_ARGS(FUNTYPE) \ + (TARGET_RTD && TREE_CODE (FUNTYPE) != IDENTIFIER_NODE \ + && (TYPE_ARG_TYPES (FUNTYPE) == 0 \ + || TREE_VALUE (tree_last (TYPE_ARG_TYPES (FUNTYPE))) == void_type_node)) + +/* 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 the 68000 the return value is in D0 regardless. */ + +#define FUNCTION_VALUE(VALTYPE, FUNC) \ + gen_rtx (REG, TYPE_MODE (VALTYPE), 0) + +/* Define how to find the value returned by a library function + assuming the value has mode MODE. */ + +/* On the 68000 the return value is in D0 regardless. */ + +#define LIBCALL_VALUE(MODE) gen_rtx (REG, MODE, 0) + +/* 1 if N is a possible register number for a function value. + On the 68000, d0 is the only register thus used. */ + +#define FUNCTION_VALUE_REGNO_P(N) ((N) == 0) + +/* Define this if PCC uses the nonreentrant convention for returning + structure and union values. */ + +#define PCC_STATIC_STRUCT_RETURN + +/* 1 if N is a possible register number for function argument passing. + On the 68000, no registers are used in this way. */ + +#define FUNCTION_ARG_REGNO_P(N) 0 + +/* 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 the m68k, this is a single integer, which is a number of bytes + of arguments scanned so far. */ + +#define CUMULATIVE_ARGS int + +/* 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. + + On the m68k, the offset starts at 0. */ + +#define INIT_CUMULATIVE_ARGS(CUM,FNTYPE) \ + ((CUM) = 0) + +/* 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.) */ + +#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \ + ((CUM) += ((MODE) != BLKmode \ + ? (GET_MODE_SIZE (MODE) + 3) & ~3 \ + : (int_size_in_bytes (TYPE) + 3) & ~3)) + +/* Define where to put the arguments 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). */ + +/* On the 68000 all args are pushed, except if -mregparm is specified + then the first two words of arguments are passed in d0, d1. + *NOTE* -mregparm does not work. + It exists only to test register calling conventions. */ + +#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \ +((TARGET_REGPARM && (CUM) < 8) ? gen_rtx (REG, (MODE), (CUM) / 4) : 0) + +/* 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. */ + +#define FUNCTION_ARG_PARTIAL_NREGS(CUM, MODE, TYPE, NAMED) \ +((TARGET_REGPARM && (CUM) < 8 \ + && 8 < ((CUM) + ((MODE) == BLKmode \ + ? int_size_in_bytes (TYPE) \ + : GET_MODE_SIZE (MODE)))) \ + ? 2 - (CUM) / 4 : 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. */ + +/* Note that the order of the bit mask for fmovem is the opposite + of the order for movem! */ + +#define FUNCTION_PROLOGUE(FILE, SIZE) \ +{ register int regno; \ + register int mask = 0; \ + extern char call_used_regs[]; \ + int fsize = ((SIZE) + 3) & -4; \ + if (frame_pointer_needed) \ + { if (TARGET_68020 || fsize < 0x8000) \ + fprintf (FILE, "\tlink a6,#%d\n", -fsize); \ + else \ + fprintf (FILE, "\tlink a6,#0\n\tsubl #%d,sp\n", fsize); } \ + for (regno = 24; regno < 56; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + fprintf(FILE, "\tfpmoved %s, sp@-\n", \ + reg_names[regno]); \ + for (regno = 16; regno < 24; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + mask |= 1 << (regno - 16); \ + if ((mask & 0xff) != 0) \ + fprintf (FILE, "\tfmovem #0x%x,sp@-\n", mask & 0xff); \ + mask = 0; \ + for (regno = 0; regno < 16; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + mask |= 1 << (15 - regno); \ + if (frame_pointer_needed) \ + mask &= ~ (1 << (15-FRAME_POINTER_REGNUM)); \ + if (exact_log2 (mask) >= 0) \ + fprintf (FILE, "\tmovel %s,sp@-\n", reg_names[15 - exact_log2 (mask)]); \ + else if (mask) fprintf (FILE, "\tmoveml #0x%x,sp@-\n", mask); } + +/* Output assembler code to FILE to increment profiler label # LABELNO + for profiling a function entry. */ + +#define FUNCTION_PROFILER(FILE, LABELNO) \ + fprintf (FILE, "\tlea LP%d,a0\n\tjsr mcount\n", (LABELNO)) + +/* Output assembler code to FILE to initialize this source file's + basic block profiling info, if that has not already been done. */ + +#define FUNCTION_BLOCK_PROFILER(FILE, LABELNO) \ + fprintf (FILE, "\ttstl LPBX0\n\tbne LPI%d\n\tpea LPBX0\n\tjsr ___bb_init_func\n\taddql #4,sp\nLPI%d:\n", \ + LABELNO, LABELNO); + +/* Output assembler code to FILE to increment the entry-count for + the BLOCKNO'th basic block in this source file. */ + +#define BLOCK_PROFILER(FILE, BLOCKNO) \ + fprintf (FILE, "\taddql #1,LPBX2+%d\n", 4 * BLOCKNO) + +/* 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. */ + +#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) \ +{ register int regno; \ + register int mask, fmask; \ + register int nregs; \ + int offset, foffset, fpoffset; \ + extern char call_used_regs[]; \ + extern int current_function_pops_args; \ + extern int current_function_args_size; \ + int fsize = ((SIZE) + 3) & -4; \ + int big = 0; \ + FUNCTION_EXTRA_EPILOGUE (FILE, SIZE); \ + nregs = 0; fmask = 0; fpoffset = 0; \ + for (regno = 24 ; regno < 56 ; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + nregs++; \ + fpoffset = nregs*8; \ + nregs = 0; \ + for (regno = 16; regno < 24; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + { nregs++; fmask |= 1 << (23 - regno); } \ + foffset = fpoffset + nregs * 12; \ + nregs = 0; mask = 0; \ + if (frame_pointer_needed) regs_ever_live[FRAME_POINTER_REGNUM] = 0; \ + for (regno = 0; regno < 16; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + { nregs++; mask |= 1 << regno; } \ + offset = foffset + nregs * 4; \ + if (offset + fsize >= 0x8000 \ + && frame_pointer_needed \ + && (mask || fmask || fpoffset)) \ + { fprintf (FILE, "\tmovel #%d,a0\n", -fsize); \ + fsize = 0, big = 1; } \ + if (exact_log2 (mask) >= 0) { \ + if (big) \ + fprintf (FILE, "\tmovel a6@(-%d,a0:l),%s\n", \ + offset + fsize, reg_names[exact_log2 (mask)]); \ + else if (! frame_pointer_needed) \ + fprintf (FILE, "\tmovel sp@+,%s\n", \ + reg_names[exact_log2 (mask)]); \ + else \ + fprintf (FILE, "\tmovel a6@(-%d),%s\n", \ + offset + fsize, reg_names[exact_log2 (mask)]); } \ + else if (mask) { \ + if (big) \ + fprintf (FILE, "\tmoveml a6@(-%d,a0:l),#0x%x\n", \ + offset + fsize, mask); \ + else if (! frame_pointer_needed) \ + fprintf (FILE, "\tmoveml sp@+,#0x%x\n", mask); \ + else \ + fprintf (FILE, "\tmoveml a6@(-%d),#0x%x\n", \ + offset + fsize, mask); } \ + if (fmask) { \ + if (big) \ + fprintf (FILE, "\tfmovem a6@(-%d,a0:l),#0x%x\n", \ + foffset + fsize, fmask); \ + else if (! frame_pointer_needed) \ + fprintf (FILE, "\tfmovem sp@+,#0x%x\n", fmask); \ + else \ + fprintf (FILE, "\tfmovem a6@(-%d),#0x%x\n", \ + foffset + fsize, fmask); } \ + if (fpoffset != 0) \ + for (regno = 55; regno >= 24; regno--) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) { \ + if (big) \ + fprintf(FILE, "\tfpmoved a6@(-%d,a0:l), %s\n", \ + fpoffset + fsize, reg_names[regno]); \ + else if (! frame_pointer_needed) \ + fprintf(FILE, "\tfpmoved sp@+, %s\n", \ + reg_names[regno]); \ + else \ + fprintf(FILE, "\tfpmoved a6@(-%d), %s\n", \ + fpoffset + fsize, reg_names[regno]); \ + fpoffset -= 8; \ + } \ + if (frame_pointer_needed) \ + fprintf (FILE, "\tunlk a6\n"); \ + if (current_function_pops_args && current_function_args_size) \ + fprintf (FILE, "\trtd #%d\n", current_function_args_size); \ + else fprintf (FILE, "\trts\n"); } + +/* This is a hook for other tm files to change. */ +#define FUNCTION_EXTRA_EPILOGUE(FILE, SIZE) + +/* If the memory address ADDR is relative to the frame pointer, + correct it to be relative to the stack pointer instead. + This is for when we don't use a frame pointer. + ADDR should be a variable name. */ + +#define FIX_FRAME_POINTER_ADDRESS(ADDR,DEPTH) \ +{ int offset = -1; \ + rtx regs = stack_pointer_rtx; \ + if (ADDR == frame_pointer_rtx) \ + offset = 0; \ + else if (GET_CODE (ADDR) == PLUS && XEXP (ADDR, 0) == frame_pointer_rtx \ + && GET_CODE (XEXP (ADDR, 1)) == CONST_INT) \ + offset = INTVAL (XEXP (ADDR, 1)); \ + else if (GET_CODE (ADDR) == PLUS && XEXP (ADDR, 0) == frame_pointer_rtx) \ + { rtx other_reg = XEXP (ADDR, 1); \ + offset = 0; \ + regs = gen_rtx (PLUS, Pmode, stack_pointer_rtx, other_reg); } \ + else if (GET_CODE (ADDR) == PLUS && XEXP (ADDR, 1) == frame_pointer_rtx) \ + { rtx other_reg = XEXP (ADDR, 0); \ + offset = 0; \ + regs = gen_rtx (PLUS, Pmode, stack_pointer_rtx, other_reg); } \ + else if (GET_CODE (ADDR) == PLUS \ + && GET_CODE (XEXP (ADDR, 0)) == PLUS \ + && XEXP (XEXP (ADDR, 0), 0) == frame_pointer_rtx \ + && GET_CODE (XEXP (ADDR, 1)) == CONST_INT) \ + { rtx other_reg = XEXP (XEXP (ADDR, 0), 1); \ + offset = INTVAL (XEXP (ADDR, 1)); \ + regs = gen_rtx (PLUS, Pmode, stack_pointer_rtx, other_reg); } \ + else if (GET_CODE (ADDR) == PLUS \ + && GET_CODE (XEXP (ADDR, 0)) == PLUS \ + && XEXP (XEXP (ADDR, 0), 1) == frame_pointer_rtx \ + && GET_CODE (XEXP (ADDR, 1)) == CONST_INT) \ + { rtx other_reg = XEXP (XEXP (ADDR, 0), 0); \ + offset = INTVAL (XEXP (ADDR, 1)); \ + regs = gen_rtx (PLUS, Pmode, stack_pointer_rtx, other_reg); } \ + if (offset >= 0) \ + { int regno; \ + extern char call_used_regs[]; \ + for (regno = 16; regno < FIRST_PSEUDO_REGISTER; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + offset += 12; \ + for (regno = 0; regno < 16; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + offset += 4; \ + offset -= 4; \ + ADDR = plus_constant (regs, offset + (DEPTH)); } } \ + +/* 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) < 16 || (unsigned) reg_renumber[REGNO] < 16) +#define REGNO_OK_FOR_BASE_P(REGNO) \ +(((REGNO) ^ 010) < 8 || (unsigned) (reg_renumber[REGNO] ^ 010) < 8) +#define REGNO_OK_FOR_DATA_P(REGNO) \ +((REGNO) < 8 || (unsigned) reg_renumber[REGNO] < 8) +#define REGNO_OK_FOR_FP_P(REGNO) \ +(((REGNO) ^ 020) < 8 || (unsigned) (reg_renumber[REGNO] ^ 020) < 8) +#define REGNO_OK_FOR_FPA_P(REGNO) \ +(((REGNO) >= 24 && (REGNO) < 56) || (reg_renumber[REGNO] >= 24 && reg_renumber[REGNO] < 56)) + +/* 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 68000, and may be used only + in code for printing assembler insns and in conditions for + define_optimization. */ + +/* 1 if X is a data register. */ + +#define DATA_REG_P(X) (REG_P (X) && REGNO_OK_FOR_DATA_P (REGNO (X))) + +/* 1 if X is an fp register. */ + +#define FP_REG_P(X) (REG_P (X) && REGNO_OK_FOR_FP_P (REGNO (X))) + +/* 1 if X is an address register */ + +#define ADDRESS_REG_P(X) (REG_P (X) && REGNO_OK_FOR_BASE_P (REGNO (X))) + +/* 1 if X is a register in the Sun FPA. */ +#define FPA_REG_P(X) (REG_P (X) && REGNO_OK_FOR_FPA_P (REGNO (X))) + +/* 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. */ + +#define CONSTANT_ADDRESS_P(X) CONSTANT_P (X) + +/* Nonzero if the constant value X is a legitimate general operand. + It is given that X satisfies CONSTANT_P or is a CONST_DOUBLE. */ + +#define LEGITIMATE_CONSTANT_P(X) 1 + +/* 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. */ + +#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) ((REGNO (X) ^ 020) >= 8) +/* 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) ((REGNO (X) & ~027) != 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)) + +#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. + + The other macros defined here are used only in GO_IF_LEGITIMATE_ADDRESS. */ + +#define INDIRECTABLE_1_ADDRESS_P(X) \ + (CONSTANT_ADDRESS_P (X) \ + || (GET_CODE (X) == REG && REG_OK_FOR_BASE_P (X)) \ + || ((GET_CODE (X) == PRE_DEC || GET_CODE (X) == POST_INC) \ + && REG_P (XEXP (X, 0)) \ + && REG_OK_FOR_BASE_P (XEXP (X, 0))) \ + || (GET_CODE (X) == PLUS \ + && REG_P (XEXP (X, 0)) && REG_OK_FOR_BASE_P (XEXP (X, 0)) \ + && GET_CODE (XEXP (X, 1)) == CONST_INT \ + && ((unsigned) INTVAL (XEXP (X, 1)) + 0x8000) < 0x10000)) + +#if 0 +/* This should replace the last two lines + except that Sun's assembler does not seem to handle such operands. */ + && (TARGET_68020 ? CONSTANT_ADDRESS_P (XEXP (X, 1)) \ + : (GET_CODE (XEXP (X, 1)) == CONST_INT \ + && ((unsigned) INTVAL (XEXP (X, 1)) + 0x8000) < 0x10000)))) +#endif + + +#define GO_IF_NONINDEXED_ADDRESS(X, ADDR) \ +{ if (INDIRECTABLE_1_ADDRESS_P (X)) goto ADDR; } + +#define GO_IF_INDEXABLE_BASE(X, ADDR) \ +{ if (GET_CODE (X) == LABEL_REF) goto ADDR; \ + if (GET_CODE (X) == REG && REG_OK_FOR_BASE_P (X)) goto ADDR; } + +#define GO_IF_INDEXING(X, ADDR) \ +{ if (GET_CODE (X) == PLUS && LEGITIMATE_INDEX_P (XEXP (X, 0))) \ + { GO_IF_INDEXABLE_BASE (XEXP (X, 1), ADDR); } \ + if (GET_CODE (X) == PLUS && LEGITIMATE_INDEX_P (XEXP (X, 1))) \ + { GO_IF_INDEXABLE_BASE (XEXP (X, 0), ADDR); } } + +#define GO_IF_INDEXED_ADDRESS(X, ADDR) \ +{ GO_IF_INDEXING (X, ADDR); \ + if (GET_CODE (X) == PLUS) \ + { if (GET_CODE (XEXP (X, 1)) == CONST_INT \ + && (unsigned) INTVAL (XEXP (X, 1)) + 0x80 < 0x100) \ + { rtx go_temp = XEXP (X, 0); GO_IF_INDEXING (go_temp, ADDR); } \ + if (GET_CODE (XEXP (X, 0)) == CONST_INT \ + && (unsigned) INTVAL (XEXP (X, 0)) + 0x80 < 0x100) \ + { rtx go_temp = XEXP (X, 1); GO_IF_INDEXING (go_temp, ADDR); } } } + +#define LEGITIMATE_INDEX_REG_P(X) \ + ((GET_CODE (X) == REG && REG_OK_FOR_INDEX_P (X)) \ + || (GET_CODE (X) == SIGN_EXTEND \ + && GET_CODE (XEXP (X, 0)) == REG \ + && GET_MODE (XEXP (X, 0)) == HImode \ + && REG_OK_FOR_INDEX_P (XEXP (X, 0)))) + +#define LEGITIMATE_INDEX_P(X) \ + (LEGITIMATE_INDEX_REG_P (X) \ + || (TARGET_68020 && GET_CODE (X) == MULT \ + && LEGITIMATE_INDEX_REG_P (XEXP (X, 0)) \ + && GET_CODE (XEXP (X, 1)) == CONST_INT \ + && (INTVAL (XEXP (X, 1)) == 2 \ + || INTVAL (XEXP (X, 1)) == 4 \ + || INTVAL (XEXP (X, 1)) == 8))) + +#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \ +{ GO_IF_NONINDEXED_ADDRESS (X, ADDR); \ + GO_IF_INDEXED_ADDRESS (X, 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. + + For the 68000, we handle X+REG by loading X into a register R and + using R+REG. R will go in an address reg and indexing will be used. + However, if REG is a broken-out memory address or multiplication, + nothing needs to be done because REG can certainly go in an address reg. */ + +#define LEGITIMIZE_ADDRESS(X,OLDX,MODE,WIN) \ +{ register int ch = (X) != (OLDX); \ + if (GET_CODE (X) == PLUS) \ + { if (GET_CODE (XEXP (X, 0)) == MULT) \ + ch = 1, XEXP (X, 0) = force_operand (XEXP (X, 0), 0); \ + if (GET_CODE (XEXP (X, 1)) == MULT) \ + ch = 1, XEXP (X, 1) = force_operand (XEXP (X, 1), 0); \ + if (ch && GET_CODE (XEXP (X, 1)) == REG \ + && GET_CODE (XEXP (X, 0)) == REG) \ + return X; \ + if (ch) { GO_IF_LEGITIMATE_ADDRESS (MODE, X, WIN); } \ + if (GET_CODE (XEXP (X, 0)) == REG \ + || (GET_CODE (XEXP (X, 0)) == SIGN_EXTEND \ + && GET_CODE (XEXP (XEXP (X, 0), 0)) == REG \ + && GET_MODE (XEXP (XEXP (X, 0), 0)) == HImode)) \ + { register rtx temp = gen_reg_rtx (Pmode); \ + register rtx val = force_operand (XEXP (X, 1), 0); \ + emit_move_insn (temp, val); \ + XEXP (X, 1) = temp; \ + return X; } \ + else if (GET_CODE (XEXP (X, 1)) == REG \ + || (GET_CODE (XEXP (X, 1)) == SIGN_EXTEND \ + && GET_CODE (XEXP (XEXP (X, 1), 0)) == REG \ + && GET_MODE (XEXP (XEXP (X, 1), 0)) == HImode)) \ + { register rtx temp = gen_reg_rtx (Pmode); \ + register rtx val = force_operand (XEXP (X, 0), 0); \ + emit_move_insn (temp, val); \ + XEXP (X, 0) = temp; \ + return X; }}} + +/* Go to LABEL if ADDR (a legitimate address expression) + has an effect that depends on the machine mode it is used for. + On the 68000, only predecrement and postincrement address depend thus + (the amount of decrement or increment being the length of the operand). */ + +#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR,LABEL) \ + if (GET_CODE (ADDR) == POST_INC || GET_CODE (ADDR) == PRE_DEC) goto LABEL + +/* Specify the machine mode that this machine uses + for the index in the tablejump instruction. */ +#define CASE_VECTOR_MODE HImode + +/* 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 + +/* 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 4 + +/* Define this if zero-extension is slow (more than one real instruction). */ +#define SLOW_ZERO_EXTEND + +/* Nonzero if access to memory by bytes is slow and undesirable. */ +#define SLOW_BYTE_ACCESS 0 + +/* Define if shifts truncate the shift count + which implies one can omit a sign-extension or zero-extension + of a shift count. */ +#define SHIFT_COUNT_TRUNCATED + +/* 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 + +/* 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 + +/* 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 SImode + +/* 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 QImode + +/* 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) \ + case CONST_INT: \ + /* Constant zero is super cheap due to clr instruction. */ \ + if (RTX == const0_rtx) return 0; \ + if ((unsigned) INTVAL (RTX) < 077) return 1; \ + case CONST: \ + case LABEL_REF: \ + case SYMBOL_REF: \ + return 3; \ + case CONST_DOUBLE: \ + return 5; + +/* Tell final.c how to eliminate redundant test instructions. */ + +/* Here we define machine-dependent flags and fields in cc_status + (see `conditions.h'). */ + +/* Set if the cc value is actually in the 68881, so a floating point + conditional branch must be output. */ +#define CC_IN_68881 04000 + +/* Store in cc_status the expressions + that the condition codes will describe + after execution of an instruction whose pattern is EXP. + Do not alter them if the instruction would not alter the cc's. */ + +/* On the 68000, all the insns to store in an address register + fail to set the cc's. However, in some cases these instructions + can make it possibly invalid to use the saved cc's. In those + cases we clear out some or all of the saved cc's so they won't be used. */ + +/* It was claimed recently that addq, subq to an address register + do update the cc's, but the 68000 and 68020 manuals say otherwise. */ + +#define NOTICE_UPDATE_CC(EXP, INSN) \ +{ \ + /* If the cc is being set from the fpa and the + expression is not an explicit floating point + test instruction (which has code to deal with + this), reinit the CC */ \ + if (((cc_status.value1 && FPA_REG_P (cc_status.value1)) \ + || (cc_status.value2 && FPA_REG_P (cc_status.value2))) \ + && !(GET_CODE(EXP) == PARALLEL \ + && GET_CODE (XVECEXP(EXP, 0, 0)) == SET \ + && XEXP (XVECEXP (EXP, 0, 0), 0) == cc0_rtx)) \ + { CC_STATUS_INIT; } \ + else if (GET_CODE (EXP) == SET) \ + { if (ADDRESS_REG_P (SET_DEST (EXP))) \ + { 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; } \ + else if (!FP_REG_P (SET_DEST (EXP)) \ + && SET_DEST (EXP) != cc0_rtx \ + && (FP_REG_P (SET_SRC (EXP)) \ + || GET_CODE (SET_SRC (EXP)) == FIX \ + || GET_CODE (SET_SRC (EXP)) == FLOAT_TRUNCATE \ + || GET_CODE (SET_SRC (EXP)) == FLOAT_EXTEND)) \ + { CC_STATUS_INIT; } \ + /* A pair of move insns doesn't produce a useful overall cc. */ \ + else if (!FP_REG_P (SET_DEST (EXP)) \ + && !FP_REG_P (SET_SRC (EXP)) \ + && GET_MODE_SIZE (GET_MODE (SET_SRC (EXP))) > 4 \ + && (GET_CODE (SET_SRC (EXP)) == REG \ + || GET_CODE (SET_SRC (EXP)) == MEM \ + || GET_CODE (SET_SRC (EXP)) == CONST_DOUBLE))\ + { CC_STATUS_INIT; } \ + else if (GET_CODE (SET_SRC (EXP)) == CALL) \ + { CC_STATUS_INIT; } \ + else if (XEXP (EXP, 0) != pc_rtx) \ + { cc_status.flags = 0; \ + cc_status.value1 = XEXP (EXP, 0); \ + cc_status.value2 = XEXP (EXP, 1); } } \ + else if (GET_CODE (EXP) == PARALLEL \ + && GET_CODE (XVECEXP (EXP, 0, 0)) == SET) \ + { \ + if (ADDRESS_REG_P (XEXP (XVECEXP (EXP, 0, 0), 0))) \ + CC_STATUS_INIT; \ + else if (XEXP (XVECEXP (EXP, 0, 0), 0) != pc_rtx) \ + { cc_status.flags = 0; \ + cc_status.value1 = XEXP (XVECEXP (EXP, 0, 0), 0); \ + cc_status.value2 = XEXP (XVECEXP (EXP, 0, 0), 1); } } \ + else CC_STATUS_INIT; \ + if (cc_status.value2 != 0 \ + && ADDRESS_REG_P (cc_status.value2) \ + && GET_MODE (cc_status.value2) == QImode) \ + CC_STATUS_INIT; \ + if (cc_status.value2 != 0 \ + && !(cc_status.value1 && FPA_REG_P (cc_status.value1))) \ + switch (GET_CODE (cc_status.value2)) \ + { case PLUS: case MINUS: case MULT: case UMULT: \ + case DIV: case UDIV: case MOD: case UMOD: case NEG: \ + case ASHIFT: case LSHIFT: case ASHIFTRT: case LSHIFTRT: \ + case ROTATE: case ROTATERT: \ + if (GET_MODE (cc_status.value2) != VOIDmode) \ + cc_status.flags |= CC_NO_OVERFLOW; \ + break; \ + case ZERO_EXTEND: \ + case ZERO_EXTRACT: \ + /* (SET r1 (ZERO_EXTEND r2)) on this machine + ends with a move insn moving r2 in r2's mode. + Thus, the cc's are set for r2. + This can set N bit spuriously. */ \ + cc_status.flags |= CC_NOT_NEGATIVE; } \ + if (cc_status.value1 && GET_CODE (cc_status.value1) == REG \ + && cc_status.value2 \ + && reg_overlap_mentioned_p (cc_status.value1, cc_status.value2)) \ + cc_status.value2 = 0; \ + if (((cc_status.value1 && FP_REG_P (cc_status.value1)) \ + || (cc_status.value2 && FP_REG_P (cc_status.value2))) \ + && !((cc_status.value1 && FPA_REG_P (cc_status.value1)) \ + || (cc_status.value2 && FPA_REG_P (cc_status.value2)))) \ + cc_status.flags = CC_IN_68881; } + +#define OUTPUT_JUMP(NORMAL, FLOAT, NO_OV) \ +do { if (cc_prev_status.flags & CC_IN_68881) \ + return FLOAT; \ + if (cc_prev_status.flags & CC_NO_OVERFLOW) \ + return NO_OV; \ + return NORMAL; } while (0) + +/* Control the assembler format that we output. */ + +/* Output at beginning of assembler file. */ + +#define ASM_FILE_START(FILE) \ + fprintf (FILE, "#NO_APP\n"); + +/* Output to assembler file text saying following lines + may contain character constants, extra white space, comments, etc. */ + +#define ASM_APP_ON "#APP\n" + +/* Output to assembler file text saying following lines + no longer contain unusual constructs. */ + +#define ASM_APP_OFF "#NO_APP\n" + +/* 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 \ +{"d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", \ + "a0", "a1", "a2", "a3", "a4", "a5", "a6", "sp", \ + "fp0", "fp1", "fp2", "fp3", "fp4", "fp5", "fp6", "fp7", \ + "fpa0", "fpa1", "fpa2", "fpa3", "fpa4", "fpa5", "fpa6", "fpa7", \ + "fpa8", "fpa9", "fpa10", "fpa11", "fpa12", "fpa13", "fpa14", "fpa15", \ + "fpa16", "fpa17", "fpa18", "fpa19", "fpa20", "fpa21", "fpa22", "fpa23", \ + "fpa24", "fpa25", "fpa26", "fpa27", "fpa28", "fpa29", "fpa30", "fpa31", } + +/* How to renumber registers for dbx and gdb. + On the Sun-3, the floating point registers have numbers + 18 to 25, not 16 to 23 as they do in the compiler. */ + +#define DBX_REGISTER_NUMBER(REGNO) ((REGNO) < 16 ? (REGNO) : (REGNO) + 2) + +/* 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 (".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. */ + +#define ASM_OUTPUT_LABELREF(FILE,NAME) \ + fprintf (FILE, "_%s", NAME) + +/* 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) \ + 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%d", PREFIX, NUM) + +/* This is how to output an assembler line defining a `double' constant. */ + +#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \ + fprintf (FILE, "\t.double 0r%.20g\n", (VALUE)) + +/* This is how to output an assembler line defining a `float' constant. */ + +/* Sun's assembler can't handle floating constants written as floating. + However, when cross-compiling, always use that in case format differs. */ + +#ifdef CROSS_COMPILER + +#define ASM_OUTPUT_FLOAT(FILE,VALUE) \ + fprintf (FILE, "\t.float 0r%.10g\n", (VALUE)) + +#else + +#define ASM_OUTPUT_FLOAT(FILE,VALUE) \ +do { union { float f; long l;} tem; \ + tem.f = (VALUE); \ + fprintf (FILE, "\t.long 0x%x\n", tem.l); \ + } while (0) + +#endif /* not CROSS_COMPILER */ + +/* This is how to output an assembler line defining an `int' constant. */ + +#define ASM_OUTPUT_INT(FILE,VALUE) \ +( fprintf (FILE, "\t.long "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +/* Likewise for `char' and `short' constants. */ + +#define ASM_OUTPUT_SHORT(FILE,VALUE) \ +( fprintf (FILE, "\t.word "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +#define ASM_OUTPUT_CHAR(FILE,VALUE) \ +( fprintf (FILE, "\t.byte "), \ + 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.byte 0x%x\n", (VALUE)) + +/* This is how to output an insn to push a register on the stack. + It need not be very fast code. */ + +#define ASM_OUTPUT_REG_PUSH(FILE,REGNO) \ + fprintf (FILE, "\tmovel %s,sp@-\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, "\tmovel sp@+,%s\n", reg_names[REGNO]) + +/* 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.) */ + +#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \ + fprintf (FILE, "\t.long L%d\n", VALUE) + +/* This is how to output an element of a case-vector that is relative. */ + +#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, VALUE, REL) \ + fprintf (FILE, "\t.word L%d-L%d\n", VALUE, REL) + +/* 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) == 1) \ + fprintf (FILE, "\t.even\n"); \ + else if ((LOG) != 0) \ + abort (); + +#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 (".comm ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%u\n", (ROUNDED))) + +/* This says how to output an assembler line + to define a local common symbol. */ + +#define ASM_OUTPUT_LOCAL(FILE, NAME, SIZE, ROUNDED) \ +( fputs (".lcomm ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%u\n", (ROUNDED))) + +/* 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 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 + +/* Output a float value (represented as a C double) as an immediate operand. + This macro is a 68k-specific macro. */ +#define ASM_OUTPUT_FLOAT_OPERAND(FILE,VALUE) \ + fprintf (FILE, "#0r%.9g", (VALUE)) + +/* Output a double value (represented as a C double) as an immediate operand. + This macro is a 68k-specific macro. */ +#define ASM_OUTPUT_DOUBLE_OPERAND(FILE,VALUE) \ + fprintf (FILE, "#0r%.20g", (VALUE)) + +/* 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. + + On the 68000, we use several CODE characters: + '.' for dot needed in Motorola-style opcode names. + '-' for an operand pushing on the stack: + sp@-, -(sp) or -(%sp) depending on the style of syntax. + '+' for an operand pushing on the stack: + sp@+, (sp)+ or (%sp)+ depending on the style of syntax. + '@' for a reference to the top word on the stack: + sp@, (sp) or (%sp) depending on the style of syntax. + '#' for an immediate operand prefix (# in MIT and Motorola syntax + but & in SGS syntax). + '!' for the cc register (used in an `and to cc' insn). + + 'b' for byte insn (no effect, on the Sun; this is for the ISI). + 'd' to force memory addressing to be absolute, not relative. + 'f' for float insn (print a CONST_DOUBLE as a float rather than in hex) + 'w' for FPA insn (print a CONST_DOUBLE as a SunFPA constant rather + than directly). Second part of 'y' below. + 'x' for float insn (print a CONST_DOUBLE as a float rather than in hex), + or print pair of registers as rx:ry. + 'y' for a FPA insn (print pair of registers as rx:ry). This also outputs + CONST_DOUBLE's as SunFPA constant RAM registers if + possible, so it should not be used except for the SunFPA. */ + +#define PRINT_OPERAND_PUNCT_VALID_P(CODE) \ + ((CODE) == '.' || (CODE) == '#' || (CODE) == '-' \ + || (CODE) == '+' || (CODE) == '@' || (CODE) == '!') + +/* This assumes the compiler is running on a big-endian machine. + The support for the other case is left for version 2. */ +#define PRINT_OPERAND_EXTRACT_FLOAT(X) \ + u.i[0] = CONST_DOUBLE_LOW (X); u.i[1] = CONST_DOUBLE_HIGH (X); + +#ifdef CROSS_COMPILER +#define PRINT_OPERAND_PRINT_FLOAT(CODE, FILE) \ + ASM_OUTPUT_FLOAT_OPERAND (FILE, u1.f); +#else +#define PRINT_OPERAND_PRINT_FLOAT(CODE, FILE) \ +{ if (CODE == 'f') \ + ASM_OUTPUT_FLOAT_OPERAND (FILE, u1.f); \ + else \ + fprintf (FILE, "#0x%x", u1.i); } +#endif + +#define PRINT_OPERAND(FILE, X, CODE) \ +{ int i; \ + if (CODE == '.') ; \ + else if (CODE == '#') fprintf (FILE, "#"); \ + else if (CODE == '-') fprintf (FILE, "sp@-"); \ + else if (CODE == '+') fprintf (FILE, "sp@+"); \ + else if (CODE == '@') fprintf (FILE, "sp@"); \ + else if (CODE == '!') fprintf (FILE, "cc"); \ + else if (GET_CODE (X) == REG) \ + { if (REGNO (X) < 16 && (CODE == 'y' || CODE == 'x') && GET_MODE (X) == DFmode) \ + fprintf (FILE, "%s:%s", reg_names[REGNO (X)], reg_names[REGNO (X)+1]); \ + else \ + fprintf (FILE, "%s", reg_names[REGNO (X)]); \ + } \ + else if (GET_CODE (X) == MEM) \ + { \ + output_address (XEXP (X, 0)); \ + if (CODE == 'd' && ! TARGET_68020 \ + && CONSTANT_ADDRESS_P (XEXP (X, 0)) \ + && !(GET_CODE (XEXP (X, 0)) == CONST_INT \ + && INTVAL (XEXP (X, 0)) < 0x8000 \ + && INTVAL (XEXP (X, 0)) >= -0x8000)) \ + fprintf (FILE, ":l"); \ + } \ + else if ((CODE == 'y' || CODE == 'w') \ + && GET_CODE(X) == CONST_DOUBLE \ + && (i = standard_sun_fpa_constant_p (X))) \ + fprintf (FILE, "%%%d", i & 0x1ff); \ + else if (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) == SFmode) \ + { union { double d; int i[2]; } u; \ + union { float f; int i; } u1; \ + PRINT_OPERAND_EXTRACT_FLOAT (X); \ + u1.f = u.d; \ + PRINT_OPERAND_PRINT_FLOAT (CODE, FILE); } \ + else if (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) != DImode) \ + { union { double d; int i[2]; } u; \ + PRINT_OPERAND_EXTRACT_FLOAT (X); \ + ASM_OUTPUT_DOUBLE_OPERAND (FILE, u.d); } \ + else { putc ('#', FILE); output_addr_const (FILE, X); }} + +/* Note that this contains a kludge that knows that the only reason + we have an address (plus (label_ref...) (reg...)) + is in the insn before a tablejump, and we know that m68k.md + generates a label LInnn: on such an insn. */ +#define PRINT_OPERAND_ADDRESS(FILE, ADDR) \ +{ register rtx reg1, reg2, breg, ireg; \ + register rtx addr = ADDR; \ + rtx offset; \ + switch (GET_CODE (addr)) \ + { \ + case REG: \ + fprintf (FILE, "%s@", reg_names[REGNO (addr)]); \ + break; \ + case PRE_DEC: \ + fprintf (FILE, "%s@-", reg_names[REGNO (XEXP (addr, 0))]); \ + break; \ + case POST_INC: \ + fprintf (FILE, "%s@+", reg_names[REGNO (XEXP (addr, 0))]); \ + break; \ + case PLUS: \ + reg1 = 0; reg2 = 0; \ + ireg = 0; breg = 0; \ + offset = 0; \ + if (CONSTANT_ADDRESS_P (XEXP (addr, 0))) \ + { \ + offset = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (CONSTANT_ADDRESS_P (XEXP (addr, 1))) \ + { \ + offset = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + if (GET_CODE (addr) != PLUS) ; \ + else if (GET_CODE (XEXP (addr, 0)) == SIGN_EXTEND) \ + { \ + reg1 = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (GET_CODE (XEXP (addr, 1)) == SIGN_EXTEND) \ + { \ + reg1 = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + else if (GET_CODE (XEXP (addr, 0)) == MULT) \ + { \ + reg1 = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (GET_CODE (XEXP (addr, 1)) == MULT) \ + { \ + reg1 = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + else if (GET_CODE (XEXP (addr, 0)) == REG) \ + { \ + reg1 = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (GET_CODE (XEXP (addr, 1)) == REG) \ + { \ + reg1 = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + if (GET_CODE (addr) == REG || GET_CODE (addr) == MULT \ + || GET_CODE (addr) == SIGN_EXTEND) \ + { if (reg1 == 0) reg1 = addr; else reg2 = addr; addr = 0; } \ +/* for OLD_INDEXING \ + else if (GET_CODE (addr) == PLUS) \ + { \ + if (GET_CODE (XEXP (addr, 0)) == REG) \ + { \ + reg2 = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (GET_CODE (XEXP (addr, 1)) == REG) \ + { \ + reg2 = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + } \ + */ \ + if (offset != 0) { if (addr != 0) abort (); addr = offset; } \ + if ((reg1 && (GET_CODE (reg1) == SIGN_EXTEND \ + || GET_CODE (reg1) == MULT)) \ + || (reg2 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg2)))) \ + { breg = reg2; ireg = reg1; } \ + else if (reg1 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg1))) \ + { breg = reg1; ireg = reg2; } \ + if (ireg != 0 && breg == 0 && GET_CODE (addr) == LABEL_REF) \ + { int scale = 1; \ + if (GET_CODE (ireg) == MULT) \ + { scale = INTVAL (XEXP (ireg, 1)); \ + ireg = XEXP (ireg, 0); } \ + if (GET_CODE (ireg) == SIGN_EXTEND) \ + fprintf (FILE, "pc@(L%d-LI%d-2:b,%s:w", \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + reg_names[REGNO (XEXP (ireg, 0))]); \ + else \ + fprintf (FILE, "pc@(L%d-LI%d-2:b,%s:l", \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + reg_names[REGNO (ireg)]); \ + if (scale != 1) fprintf (FILE, ":%d", scale); \ + putc (')', FILE); \ + break; } \ + if (breg != 0 && ireg == 0 && GET_CODE (addr) == LABEL_REF) \ + { fprintf (FILE, "pc@(L%d-LI%d-2:b,%s:l", \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + reg_names[REGNO (breg)]); \ + putc (')', FILE); \ + break; } \ + if (ireg != 0 || breg != 0) \ + { int scale = 1; \ + if (breg == 0) \ + abort (); \ + if (addr && GET_CODE (addr) == LABEL_REF) abort (); \ + fprintf (FILE, "%s@(", reg_names[REGNO (breg)]); \ + if (addr != 0) \ + output_addr_const (FILE, addr); \ + if (addr != 0 && ireg != 0) \ + putc (',', FILE); \ + if (ireg != 0 && GET_CODE (ireg) == MULT) \ + { scale = INTVAL (XEXP (ireg, 1)); \ + ireg = XEXP (ireg, 0); } \ + if (ireg != 0 && GET_CODE (ireg) == SIGN_EXTEND) \ + fprintf (FILE, "%s:w", reg_names[REGNO (XEXP (ireg, 0))]); \ + else if (ireg != 0) \ + fprintf (FILE, "%s:l", reg_names[REGNO (ireg)]); \ + if (scale != 1) fprintf (FILE, ":%d", scale); \ + putc (')', FILE); \ + break; \ + } \ + else if (reg1 != 0 && GET_CODE (addr) == LABEL_REF) \ + { fprintf (FILE, "pc@(L%d-LI%d-2:b,%s:l)", \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + reg_names[REGNO (reg1)]); \ + break; } \ + default: \ + if (GET_CODE (addr) == CONST_INT \ + && INTVAL (addr) < 0x8000 \ + && INTVAL (addr) >= -0x8000) \ + fprintf (FILE, "%d:w", INTVAL (addr)); \ + else \ + output_addr_const (FILE, addr); \ + }} + +/* +Local variables: +version-control: t +End: +*/ diff --git a/gcc-1.40/config/tm-m88k.h b/gcc-1.40/config/tm-m88k.h new file mode 100644 index 0000000..1725c68 --- /dev/null +++ b/gcc-1.40/config/tm-m88k.h @@ -0,0 +1,1128 @@ +/* Definitions of target machine for GNU compiler, for the Motorola 88000 chip. + Copyright (C) 1988 Free Software Foundation, Inc. + Contributed by Michael Tiemann (tiemann@mcc.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 1, 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. */ + + +/* Note that some other tm- files include this one and then override + many of the definitions that relate to assembler syntax. */ + + +/* Names to predefine in the preprocessor for this target machine. */ + +#define CPP_PREDEFINES "-Dm88000 -Dm88k" + +/* Print subsidiary information on the compiler version in use. */ +#define TARGET_VERSION fprintf (stderr, " (88k)"); + +/* Run-time compilation parameters selecting different hardware subsets. + + On the the m88000, we don't yet need any. */ + +extern int target_flags; + +/* 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 \ + {{ "", TARGET_DEFAULT}} + +#define TARGET_DEFAULT 1 + +/* target machine storage layout */ + +/* Define this if most significant bit is lowest numbered + in instructions that operate on numbered bit-fields. */ +#define BITS_BIG_ENDIAN + +/* Define this if most significant byte of a word is the lowest numbered. */ +/* That is true on the m88000. */ +#define BYTES_BIG_ENDIAN + +/* Define this if most significant word of a multiword number is numbered. */ +/* For the m88000 we can decide arbitrarily + since there are no machine instructions for them. */ +/* #define WORDS_BIG_ENDIAN */ + +/* number of bits in an addressible 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 32 + +/* Width of a word, in units (bytes). */ +#define UNITS_PER_WORD 4 + +/* Width in bits of a pointer. + See also the macro `Pmode' defined below. */ +#define POINTER_SIZE 32 + +/* Allocation boundary (in *bits*) for storing pointers in memory. */ +#define POINTER_BOUNDARY 32 + +/* Allocation boundary (in *bits*) for storing arguments in argument list. */ +#define PARM_BOUNDARY 32 + +/* Allocation boundary (in *bits*) for the code of a function. */ +#define FUNCTION_BOUNDARY 32 + +/* Alignment of field after `int : 0' in a structure. */ +#define EMPTY_FIELD_BOUNDARY 32 + +/* No data type wants to be aligned rounder than this. */ +#define BIGGEST_ALIGNMENT 64 + +/* Define this if move instructions will actually fail to work + when given unaligned data. */ +#define STRICT_ALIGNMENT + +/* 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. + + the m88000 has 32 fullword registers. */ + +#define FIRST_PSEUDO_REGISTER 32 + +/* 1 for registers that have pervasive standard uses + and are not available for the register allocator. + + On the 88000, these are: + Reg 0 = 0 (hardware). + Reg 1 = Subroutine return pointer (hardware). + [Reg 2-9 = Parameter registers (Motorola convention).] + Reg 25 = condition code register (Gnu). + Reg 26-29 = reserved by Motorola. + Reg 30 = frame pointer (software). + Reg 31 = stack pointer (software). */ +#define FIXED_REGISTERS \ + {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, 1, 1, 1, 1, 1, 0, 1} + +/* 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, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 1, 1, 1, 1, 1, 0, 1} + +/* 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 the m88000, ordinary registers hold 32 bits worth; + a single floating point register is always enough for + anything that can be stored in them at all. */ +#define HARD_REGNO_NREGS(REGNO, MODE) \ + ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD) + +/* Value is 1 if hard register REGNO can hold a value of machine-mode MODE. + On the m88000, the cpu registers can hold any mode, but doubles + (and larger) must start and an even register number boundary. */ +#define HARD_REGNO_MODE_OK(REGNO, MODE) \ + (GET_MODE_SIZE (MODE) <= 4 || ((REGNO) & 1) == 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. */ +#define MODES_TIEABLE_P(MODE1, MODE2) \ + (((MODE1) == DFmode || (MODE1) == DImode) \ + == ((MODE2) == DFmode || (MODE2) == DImode)) + +/* Specify the registers used for certain standard purposes. + The values of these macros are register numbers. */ + +/* the m88000 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 31 + +/* Base register for access to local variables of the function. */ +#define FRAME_POINTER_REGNUM 30 + +/* 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. */ +#define FRAME_POINTER_REQUIRED 0 + +/* Base register for access to arguments of the function. */ +#define ARG_POINTER_REGNUM 30 + +/* Register in which static-chain is passed to a function. */ +/* ??? */ +#define STATIC_CHAIN_REGNUM 10 + +/* Register in which address to store a structure value + is passed to a function. */ +#define STRUCT_VALUE_REGNUM 2 +#define STRUCT_VALUE_STACK_PROTECT_REGNUM 3 + +/* 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 88000 has one kind of registers, hence two classes. */ + +enum reg_class { NO_REGS, ALL_REGS, LIM_REG_CLASSES }; + +#define N_REG_CLASSES (int) LIM_REG_CLASSES + +/* Since GENERAL_REGS is the same class as ALL_REGS, + don't give it a different class number; just make it an alias. */ + +#define GENERAL_REGS ALL_REGS + +/* Give names of register classes as strings for dump file. */ + +#define REG_CLASS_NAMES {"NO_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, -1} + +/* 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. */ + +#define REGNO_REG_CLASS(REGNO) ALL_REGS + +/* The class value for index registers, and the one for base regs. */ +#define INDEX_REG_CLASS ALL_REGS +#define BASE_REG_CLASS ALL_REGS + +/* Get reg_class from a letter such as appears in the machine description. */ + +#define REG_CLASS_FROM_LETTER(C) 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. + + For the m88000, `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 the 5-bit operand of a compare insns. */ + +#define CONST_OK_FOR_LETTER_P(VALUE, C) \ + ((C) == 'I' ? (unsigned) (VALUE) < 0x10000 \ + : (C) == 'J' ? (VALUE) == 0 \ + : (C) == 'K' ? (unsigned) (VALUE) < 0x20 \ + : 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' && XINT (VALUE, 0) == 0 && XINT (VALUE, 1) == 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. */ +#define PREFERRED_RELOAD_CLASS(X,CLASS) (CLASS) + +/* Return the maximum number of consecutive registers + needed to represent mode MODE in a register of class CLASS. */ +#define CLASS_MAX_NREGS(CLASS, MODE) \ + ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD) + +/* Stack layout; function entry, exit and calling. */ + +/* 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. + + Do not define this for the Motorola 88000. There are no + negative literals! */ +/* #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. */ +#define STARTING_FRAME_OFFSET 0 + +/* If we generate an insn to push BYTES bytes, + this says how many the stack pointer really advances by. + On the m88000, don't define this because there are no push insns. */ +/* #define PUSH_ROUNDING(BYTES) */ + +/* If BYTES is the size of arguments for a function call, + return the size of the argument block (which is BYTES suitably rounded). + Define this only on machines where the entire call block is allocated + before the args are stored into it. */ + +#define ROUND_CALL_BLOCK_SIZE(BYTES) \ + (((BYTES) + 7) & ~7) + +/* Offset of first parameter from the argument pointer register value. */ +/* For the 88000, this must be non-zero so that addresses of the parms + can always be distinguished. */ +#define FIRST_PARM_OFFSET(FNDECL) 0 + +/* Value is 1 if returning from a function call automatically + pops the arguments described by the number-of-args field in the call. + 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. */ + +#define RETURN_POPS_ARGS(FUNTYPE) 0 + +/* 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 the m88000 the value is found in the second "output" register. */ + +#define FUNCTION_VALUE(VALTYPE, FUNC) \ + gen_rtx (REG, TYPE_MODE (VALTYPE), 2) + +/* ?? But the called function leaves it in the second "input" register. */ + +#define FUNCTION_OUTGOING_VALUE(VALTYPE, FUNC) \ + gen_rtx (REG, TYPE_MODE (VALTYPE), 2) + +/* 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, 2) + +/* 1 if N is a possible register number for a function value + as seen by the caller. + On the m88000, the first "output" reg is the only register thus used. */ + +#define FUNCTION_VALUE_REGNO_P(N) ((N) == 2) + +/* 1 if N is a possible register number for function argument passing. + On the m88000, these are the "output" registers. */ + +#define FUNCTION_ARG_REGNO_P(N) ((N) <= 9 && (N) >= 2) + +/* 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 the m88000, 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 8 or more means all following args should go on the stack. */ + +#define CUMULATIVE_ARGS int + +/* 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. + + On the m88000, the offset normally starts at 0, but starts at 4 bytes + when the function gets a structure-value-address as an + invisible first argument. */ + +#define INIT_CUMULATIVE_ARGS(CUM,FNTYPE) \ + ((CUM) = ((FNTYPE) != 0 && aggregate_value_p ((FNTYPE)))) + +/* 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.) */ + +#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \ + ((CUM) += ((MODE) != BLKmode \ + ? (GET_MODE_SIZE (MODE) + 3) / 4 \ + : (int_size_in_bytes (TYPE) + 3) / 4)) + +/* 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). */ + +/* On the m88000 the first eight words of args are normally in registers + and the rest are pushed. But any arg that won't entirely fit in regs + is pushed. */ + +#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \ +(8 >= ((CUM) \ + + ((MODE) == BLKmode \ + ? (int_size_in_bytes (TYPE) + 3) / 4 \ + : (GET_MODE_SIZE (MODE) + 3) / 4)) \ + ? gen_rtx (REG, (MODE), 2 + (CUM)) \ + : 0) + +/* Define where a function finds its arguments. + This would be different from FUNCTION_ARG if we had register windows. */ + +#define FUNCTION_INCOMING_ARG(CUM, MODE, TYPE, NAMED) \ + FUNCTION_ARG (CUM, 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. */ + +#define FUNCTION_ARG_PARTIAL_NREGS(CUM, MODE, TYPE, NAMED) 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. */ + +#define FUNCTION_PROLOGUE(FILE, SIZE) \ +{ \ + extern char call_used_regs[]; \ + extern int current_function_pretend_args_size; \ + extern int frame_pointer_needed; \ + int fsize = ((SIZE) + current_function_pretend_args_size + 7) & ~7; \ + int regno, nregs, i; \ + int offset = 0; \ + for (regno = 2, nregs = 0; regno < FRAME_POINTER_REGNUM; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + nregs++; \ + nregs = (nregs + 1) & ~1; \ + if (regs_ever_live[1] + frame_pointer_needed + nregs) \ + { \ + if (fsize + 8 + nregs*4 < 0x10000) \ + offset = fsize; \ + fprintf (FILE, "\tsub r31,r31,%d\n", 8 + nregs*4 + offset); \ + } \ + if (frame_pointer_needed) \ + fprintf (FILE, "\tst r30,r31,%d\n", offset); \ + if (regs_ever_live[1]) \ + fprintf (FILE, "\tst r1,r31,%d\n", 4 + offset); \ + if (nregs) \ + for (regno = 2, nregs = 2; regno < FRAME_POINTER_REGNUM; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + if (regno & 1 || !regs_ever_live[regno+1] || call_used_regs[regno+1])\ + fprintf (FILE, "\tst r%d,r31,%d\n", regno, offset + nregs++ * 4);\ + else \ + { \ + fprintf (FILE, "\tst.d r%d,r31,%d\n", regno, offset + nregs * 4);\ + regno += 1; nregs += 2; \ + } \ + if (offset || fsize == 0) /* do nothing. */ ; \ + else if ((unsigned) fsize < 0x10000) \ + fprintf (FILE, "\tsub r31,r31,%d\n", fsize); \ + else fprintf (FILE, "\tor.u r25,r0,hi16(%d)\n\tor r25,r0,lo16(%d)\n\tsub r31,r31,r25\n", fsize, fsize); \ + if (frame_pointer_needed) fprintf (FILE, "\tor r30,r0,r31\n"); \ +} + +/* Output assembler code to FILE to increment profiler label # LABELNO + for profiling a function entry. */ + +#define FUNCTION_PROFILER(FILE, LABELNO) \ + abort (); + +/* 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 may_call_alloca; +extern int current_function_pretend_args_size; + +#define EXIT_IGNORE_STACK \ + (get_frame_size () != 0 \ + || may_call_alloca || current_function_pretend_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. */ + +#define FUNCTION_EPILOGUE(FILE, SIZE) \ +{ \ + extern char call_used_regs[]; \ + extern int may_call_alloca; \ + int fsize = ((SIZE) + current_function_pretend_args_size + 7) & ~7; \ + int nregs, regno, i; \ + for (regno = 2, nregs = 0; regno < FRAME_POINTER_REGNUM; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + nregs++; \ + if (frame_pointer_needed) \ + { \ + if ((unsigned) fsize < 0x10000) \ + fprintf (FILE, "\tadd r31,r30,%d\n", fsize); \ + else fprintf (FILE, "\tor.u r25,r0,hi16(%d)\n\tor r25,r0,lo16(%d)\n\tadd r31,r30,r25\n", fsize, fsize); \ + } \ + else if (fsize) fprintf (FILE, "\tadd r31,r31,%d\n", fsize); \ + if (nregs) \ + for (regno = 2, nregs = 2; regno < FRAME_POINTER_REGNUM; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + if (regno & 1 || !regs_ever_live[regno+1] || call_used_regs[regno+1])\ + fprintf (FILE, "\tld r%d,r31,%d\n", regno, nregs++ * 4);\ + else \ + { \ + fprintf (FILE, "\tld.d r%d,r31,%d\n", regno, nregs * 4);\ + regno += 1; nregs += 2; \ + } \ + if (regs_ever_live[1]) \ + fprintf (FILE, "\tld r1,r31,4\n"); \ + else \ + fprintf (FILE, ";; r1 is set to go!\n"); \ + if (frame_pointer_needed) \ + fprintf (FILE, "\tld r30,r31,0\n"); \ + nregs = (nregs + 1) & ~1; \ + if (regs_ever_live[1] + frame_pointer_needed + (nregs > 2)) \ + fprintf (FILE, "\tjmp.n r1\n\taddu r31,r31,%d\n", nregs * 4); \ + else fprintf (FILE, "\tjmp r1\n"); \ + /* let insn reorganizer know that we are at the end of a function. */ \ + fprintf (FILE, "\tdata\n"); \ +} + +/* If the memory address ADDR is relative to the frame pointer, + correct it to be relative to the stack pointer instead. + This is for when we don't use a frame pointer. + ADDR should be a variable name. */ + +#define FIX_FRAME_POINTER_ADDRESS(ADDR,DEPTH) \ +{ int offset = -1; \ + rtx regs = stack_pointer_rtx; \ + if (ADDR == frame_pointer_rtx) \ + offset = 0; \ + else if (GET_CODE (ADDR) == PLUS && XEXP (ADDR, 0) == frame_pointer_rtx \ + && GET_CODE (XEXP (ADDR, 1)) == CONST_INT) \ + offset = INTVAL (XEXP (ADDR, 1)); \ + else if (GET_CODE (ADDR) == PLUS && XEXP (ADDR, 0) == frame_pointer_rtx) \ + { rtx other_reg = XEXP (ADDR, 1); \ + offset = 0; \ + regs = gen_rtx (PLUS, Pmode, stack_pointer_rtx, other_reg); } \ + else if (GET_CODE (ADDR) == PLUS && XEXP (ADDR, 1) == frame_pointer_rtx) \ + { rtx other_reg = XEXP (ADDR, 0); \ + offset = 0; \ + regs = gen_rtx (PLUS, Pmode, stack_pointer_rtx, other_reg); } \ + if (offset >= 0) \ + { int regno; \ + extern char call_used_regs[]; \ + for (regno = 2; regno < FRAME_POINTER_REGNUM; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + offset += 4; \ + offset -= 4; \ + ADDR = plus_constant (regs, offset + (DEPTH)); } } + + +/* 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] < 32) +#define REGNO_OK_FOR_BASE_P(REGNO) \ + ((REGNO) < 32 || (unsigned) reg_renumber[REGNO] < 32) + +/* 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 the m88000, and may be used only + in code for printing assembler insns and in conditions for + define_optimization. */ + +/* 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. */ + +#define CONSTANT_ADDRESS_P(X) CONSTANT_P (X) + +/* Nonzero if the constant value X is a legitimate general operand. + It is given that X satisfies CONSTANT_P or is a CONST_DOUBLE. */ + +#define LEGITIMATE_CONSTANT_P(X) (1) + +/* 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. */ + +#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) (1) +/* 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) (1) + +#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)) + +#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 the m88000, the actual legitimate addresses must be REG+REG or REG+SMALLINT. + But we can treat a SYMBOL_REF as legitimate if it is part of this + function's constant-pool, because such addresses can actually + be output as REG+SMALLINT. */ + +#define INT_FITS_16_BITS(I) ((unsigned) (I) < 0x10000) + +#define FITS_16_BITS(X) \ + (GET_CODE (X) == CONST_INT && INT_FITS_16_BITS (INTVAL (X))) + +#define LEGITIMATE_INDEX_P(X, MODE) \ + (FITS_16_BITS (X) \ + || (REG_P (X) \ + && REG_OK_FOR_INDEX_P (X)) \ + || (GET_CODE (X) == MULT \ + && REG_P (XEXP (X, 0)) \ + && REG_OK_FOR_INDEX_P (XEXP (X, 0)) \ + && GET_CODE (XEXP (X, 1)) == CONST_INT \ + && (INTVAL (XEXP (X, 1)) == GET_MODE_SIZE (MODE))) \ + || (GET_CODE (X) == MULT \ + && REG_P (XEXP (X, 1)) \ + && REG_OK_FOR_INDEX_P (XEXP (X, 1)) \ + && GET_CODE (XEXP (X, 0)) == CONST_INT \ + && (INTVAL (XEXP (X, 0)) == GET_MODE_SIZE (MODE)) \ + && (warning ("MULT backwards"), 1))) + +#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \ +{ \ + if (GET_CODE (X) == CONST_INT) \ + { \ + if (FITS_16_BITS (X)) \ + goto ADDR; \ + } \ + else if (CONSTANT_ADDRESS_P (X)) \ + goto ADDR; \ + else if (REG_P (X)) \ + { \ + if (REG_OK_FOR_BASE_P (X)) \ + goto ADDR; \ + } \ + else if (GET_CODE (X) == PLUS) \ + if (REG_P (XEXP (X, 0)) \ + && REG_OK_FOR_BASE_P (XEXP (X, 0))) \ + { \ + if (LEGITIMATE_INDEX_P (XEXP (X, 1), MODE)) \ + goto ADDR; \ + } \ + else if (REG_P (XEXP (X, 1)) \ + && REG_OK_FOR_BASE_P (XEXP (X, 1))) \ + { \ + if (LEGITIMATE_INDEX_P (XEXP (X, 0), MODE)) \ + 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 the m88000, change REG+N into REG+REG, and REG+(X*Y) into REG+REG. */ + +#define LEGITIMIZE_ADDRESS(X,OLDX,MODE,WIN) \ +{ if (GET_CODE (X) == PLUS && CONSTANT_ADDRESS_P (XEXP (X, 1))) \ + (X) = gen_rtx (PLUS, SImode, XEXP (X, 0), \ + copy_to_mode_reg (SImode, XEXP (X, 1))); \ + if (GET_CODE (X) == PLUS && CONSTANT_ADDRESS_P (XEXP (X, 0))) \ + (X) = gen_rtx (PLUS, SImode, XEXP (X, 1), \ + copy_to_mode_reg (SImode, XEXP (X, 0))); \ + if (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 0)) == MULT) \ + (X) = gen_rtx (PLUS, SImode, XEXP (X, 1), \ + force_operand (XEXP (X, 0), 0)); \ + if (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 1)) == MULT) \ + (X) = gen_rtx (PLUS, SImode, XEXP (X, 0), \ + force_operand (XEXP (X, 1), 0)); \ + 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 the m88000 this is never true. */ + +#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR,LABEL) + +/* Specify the machine mode that this machine uses + for the index in the tablejump instruction. */ +#define CASE_VECTOR_MODE SImode + +/* Define this if a raw index is all that is needed for a + `tablejump' insn. */ +#define CASE_TAKES_INDEX_RAW + +/* 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 */ + +/* 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 4 + +/* Nonzero if access to memory by bytes is slow and undesirable. */ +#define SLOW_BYTE_ACCESS 0 + +/* Do not break .stabs pseudos into continuations. */ +#define DBX_CONTIN_LENGTH 0 + +/* 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 + +/* 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 + +/* 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 SImode + +/* 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 + +/* 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) \ + case CONST_INT: \ + if ((unsigned) INTVAL (RTX) < 0x10000) return 1; \ + case CONST: \ + case LABEL_REF: \ + case SYMBOL_REF: \ + return 2; \ + case CONST_DOUBLE: \ + return 4; + +/* Tell emit-rtl.c how to initialize special values on a per-function bass. */ +extern int optimize; +extern struct rtx_def *cc0_reg_rtx; + +typedef struct { struct rtx_def *ccr; } cc_status_mdep; +#define CC_STATUS_MDEP cc_status_mdep + +#define INIT_EMIT_MDEP \ +{ \ + cc0_reg_rtx = gen_rtx (REG, SImode, 25); \ +} + +/* Tell final.c how to eliminate redundant test instructions. */ + +/* Here we define machine-dependent flags and fields in cc_status + (see `conditions.h'). */ + +#define CC_IN_FCCR 04000 + +/* Store in cc_status the expressions + that the condition codes will describe + after execution of an instruction whose pattern is EXP. + Do not alter them if the instruction would not alter the cc's. */ + +#define NOTICE_UPDATE_CC(EXP, INSN) \ +{ if (GET_CODE (EXP) == SET) \ + { if (GET_CODE (SET_DEST (EXP)) == CC0) \ + { cc_status.flags = 0; \ + cc_status.value1 = SET_DEST (EXP); \ + cc_status.value2 = SET_SRC (EXP); \ + } \ + else if (GET_CODE (SET_DEST (EXP)) == REG) \ + { 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; \ + } \ + else if (GET_CODE (SET_DEST (EXP)) == MEM) \ + { CC_STATUS_INIT; } \ + } \ + else if (GET_CODE (EXP) == PARALLEL \ + && GET_CODE (XVECEXP (EXP, 0, 0)) == SET) \ + { if (GET_CODE (SET_DEST (XVECEXP (EXP, 0, 0))) == CC0) \ + { cc_status.flags = 0; \ + cc_status.value1 = SET_DEST (XVECEXP (EXP, 0, 0)); \ + cc_status.value2 = SET_SRC (XVECEXP (EXP, 0, 0)); \ + } \ + else if (GET_CODE (SET_DEST (XVECEXP (EXP, 0, 0))) == REG) \ + { if ((cc_status.value1 \ + && reg_overlap_mentioned_p (SET_DEST (XVECEXP (EXP, 0, 0)), cc_status.value1))) \ + cc_status.value1 = 0; \ + if ((cc_status.value2 \ + && reg_overlap_mentioned_p (SET_DEST (XVECEXP (EXP, 0, 0)), cc_status.value2))) \ + cc_status.value2 = 0; \ + } \ + else if (GET_CODE (SET_DEST (XVECEXP (EXP, 0, 0))) == MEM) \ + { CC_STATUS_INIT; } \ + } \ + else if (GET_CODE (EXP) == CALL) \ + { /* all bets are off */ CC_STATUS_INIT; } \ + if (cc_status.value1 && GET_CODE (cc_status.value1) == REG \ + && cc_status.value2 \ + && reg_overlap_mentioned_p (cc_status.value1, cc_status.value2)) \ + printf ("here!\n", cc_status.value2 = 0); \ +} + +/* Control the assembler format that we output. */ + +/* Output at beginning of assembler file. */ + +#define ASM_FILE_START(FILE) + +/* 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 "" + +/* Output before read-only data. */ + +#define TEXT_SECTION_ASM_OP "\ttext" + +/* Output before writable data. */ + +#define DATA_SECTION_ASM_OP "\tdata" + +/* How to refer to registers in assembler output. + This sequence is indexed by compiler's hard-register-number (see above). */ + +#define REGISTER_NAMES \ +{"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", \ + "r10", "r11", "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19", \ + "r20", "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", \ + "r30", "r31"} + +/* How to renumber registers for dbx and gdb. */ + +#define DBX_REGISTER_NUMBER(REGNO) (REGNO) + +/* 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 ("\tglobal\t", 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. */ + +#define ASM_OUTPUT_LABELREF(FILE,NAME) \ + fprintf (FILE, "_%s", NAME) + +/* 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) \ + 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%d", PREFIX, NUM) + +/* This is how to output an assembler line defining a `double' constant. */ + +#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \ + fprintf (FILE, "\tdouble %.20e\n", (VALUE)) + +/* This is how to output an assembler line defining a `float' constant. */ + +#define ASM_OUTPUT_FLOAT(FILE,VALUE) \ + fprintf (FILE, "\tfloat %.12e\n", (VALUE)) + +/* This is how to output an assembler line defining an `int' constant. */ + +#define ASM_OUTPUT_INT(FILE,VALUE) \ +( fprintf (FILE, "\tword "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +/* Likewise for `short' and `char' constants. */ + +#define ASM_OUTPUT_SHORT(FILE,VALUE) \ +( fprintf (FILE, "\thalf "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +#define ASM_OUTPUT_CHAR(FILE,VALUE) \ +( fprintf (FILE, "\tbyte "), \ + 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, "\tbyte 0x%x\n", (VALUE)) + +#define ASM_OUTPUT_ASCII(FILE, P, SIZE) \ + output_ascii (FILE, P, SIZE) + +#define ASM_OUTPUT_ADDR_VEC_PROLOGUE(FILE, MODE, LEN) \ + fprintf (FILE, "\tjmp r1\n"); + +/* This is how to output an element of a case-vector that is absolute. */ + +#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \ + fprintf (FILE, "\t@L%d\n", VALUE) + +/* This is how to output an element of a case-vector that is relative. + (the m88000 does not use such vectors, + but we must define this macro anyway.) */ + +#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, VALUE, REL) \ + fprintf (FILE, "\tword @L%d-@L%d\n", VALUE, REL) + +/* 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, "\talign %d\n", 1<<(LOG)) + +#define ASM_OUTPUT_SKIP(FILE,SIZE) \ + fprintf (FILE, "\tzero %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 ("\tcomm ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%u\n", (ROUNDED))) + +/* This says how to output an assembler line + to define a local common symbol. */ + +#define ASM_OUTPUT_LOCAL(FILE, NAME, SIZE, ROUNDED) \ +( fprintf ((FILE), "\talign %d\n", (SIZE) <= 4 ? 4 : 8), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ":\n\tzero %u\n", (ROUNDED))) + +/* 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 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 + +/* 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. + + On the m88000, the CODE can be `r', meaning this is a register-only operand + and an immediate zero should be represented as `r0'. */ + +#define PRINT_OPERAND(FILE, X, CODE) \ +{ if (GET_CODE (X) == REG) \ + fprintf (FILE, "%s", reg_names[REGNO (X)]); \ + else if (GET_CODE (X) == MEM) \ + output_address (XEXP (X, 0)); \ + else if (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) == SFmode) \ + { union { double d; int i[2]; } u; \ + union { float f; int i; } u1; \ + u.i[0] = CONST_DOUBLE_LOW (X); u.i[1] = CONST_DOUBLE_HIGH (X); \ + u1.f = u.d; \ + if (CODE == 'f') \ + fprintf (FILE, "0r%.9g", u1.f); \ + else \ + fprintf (FILE, "0x%x", u1.i); } \ + else if (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) != DImode) \ + { union { double d; int i[2]; } u; \ + u.i[0] = CONST_DOUBLE_LOW (X); u.i[1] = CONST_DOUBLE_HIGH (X); \ + fprintf (FILE, "0r%.20g", u.d); } \ + else if ((CODE) == 'r' && (X) == const0_rtx) \ + fprintf (FILE, "r0"); \ + else { output_addr_const (FILE, X); }} + +/* Print a memory address as an operand to reference that memory location. */ + +#define PRINT_OPERAND_ADDRESS(FILE, ADDR) \ +{ register rtx base, index = 0; \ + register rtx addr = ADDR; \ + register rtx reg0, reg1; \ + switch (GET_CODE (addr)) \ + { \ + case REG: \ + fprintf (FILE, "r0,%s", reg_names[REGNO (addr)]); \ + break; \ + case PLUS: \ + reg0 = XEXP (addr, 0); \ + reg1 = XEXP (addr, 1); \ + if (GET_CODE (reg0) == MULT) \ + { rtx tmp = reg0; reg0 = reg1; reg1 = tmp; } \ + if (REG_P (reg0)) \ + if (REG_P (reg1)) \ + fprintf (FILE, "%s,%s", \ + reg_names[REGNO (reg0)], \ + reg_names[REGNO (reg1)]); \ + else if (GET_CODE (reg1) == CONST_INT) \ + { \ + int offset = INTVAL (reg1); \ + fprintf (FILE, "%s,%d", reg_names[REGNO (reg0)], offset); \ + } \ + else if (GET_CODE (reg1) == MULT) \ + fprintf (FILE, "%s[%s]", \ + reg_names[REGNO (reg0)], \ + reg_names[REGNO (XEXP (reg1, 0))]); \ + else fatal ("bad XEXP (1) to PRINT_OPERAND_ADDRESS"); \ + else fatal ("unknown PLUS case in PRINT_OPERAND_ADDRESS"); \ + break; \ + case MULT: \ + fprintf (FILE, "r0[%s]", reg_names[REGNO (XEXP (addr, 0))]); \ + break; \ + default: \ + fprintf (FILE, "r0,"); \ + output_addr_const (FILE, addr); \ + }} + diff --git a/gcc-1.40/config/tm-mips-bsd.h b/gcc-1.40/config/tm-mips-bsd.h new file mode 100644 index 0000000..0659703 --- /dev/null +++ b/gcc-1.40/config/tm-mips-bsd.h @@ -0,0 +1,3 @@ +#define MIPS_BSD43 + +#include "tm-mips.h" diff --git a/gcc-1.40/config/tm-mips-news.h b/gcc-1.40/config/tm-mips-news.h new file mode 100644 index 0000000..c42e055 --- /dev/null +++ b/gcc-1.40/config/tm-mips-news.h @@ -0,0 +1,19 @@ +/* like pmax except BIG ENDIAN instead of LITTLE ENDIAN */ + +#define MIPS_NEWS +#include "tm-mips.h" + +#undef CPP_SPEC + /* default RISC NEWS environment */ +#define CPP_SPEC "-Dr3000 -DLANGUAGE_C -DMIPSEB -DSYSTYPE_BSD -Dsony_news -Dunix -I/usr/include2.11" + +#undef MACHINE_TYPE +#define MACHINE_TYPE "Sony NEWS (RISC NEWS)" + +/* Define this if most significant byte of a word is the lowest numbered. +*/ +#define BYTES_BIG_ENDIAN + +/* Define this if most significant word of a multiword number is numbered. +*/ +#define WORDS_BIG_ENDIAN diff --git a/gcc-1.40/config/tm-mips-sysv.h b/gcc-1.40/config/tm-mips-sysv.h new file mode 100644 index 0000000..d3fa7d1 --- /dev/null +++ b/gcc-1.40/config/tm-mips-sysv.h @@ -0,0 +1,5 @@ +#define MIPS_SYSV + +#include "tm-mips.h" + +#define TARGET_MEM_FUNCTIONS diff --git a/gcc-1.40/config/tm-mips.h b/gcc-1.40/config/tm-mips.h new file mode 100644 index 0000000..8a044a4 --- /dev/null +++ b/gcc-1.40/config/tm-mips.h @@ -0,0 +1,2309 @@ +/* Definitions of target machine for GNU compiler. MIPS version. + Contributed by A. Lichnewsky, lich@inria.inria.fr + Changes by Michael Meissner, meissner@osf.org + Copyright (C) 1989, 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 1, 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 needs to be reformatted so that it looks like the + rest of GCC. ??? */ + +/*---------------------------------------------------------------------- + +SWITCHES: + + -O optimization. Implies -mgpOPT + -O1 Same as -O, mips compatibility + -O2 Implies -O -fomit-frame-pointer -fstrength-reduce + -O3 Implies -O2 + -finline-functions + + -mG0 -mG1 -mG2 + Construct a size to be passed to GCC for Data / Sdata selection. + + Value is ( (i=G0 + 2 G1 + 4 G2) , (i < 6) ? ( 1<> 8) + + /* Position independent code */ +#define TARGET_PIC (target_flags & 0x00002000) +#define TARGET_PIC_LARGE_OBJECT (target_flags & 0x00004000) + + + +/* 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 \ +{ {"mips-as", 0x00000001}, /* MIPS assembler */ \ + {"gas", -0x00000001}, /* GNU assembler */ \ + {"debug", 0x00000002}, /* Eliminate version in output*/ \ + {"nodebug", -0x00000002}, \ + {"debuga", 0x00000004}, /* don't fold SP pushes into frame */ \ + {"nodebuga", -0x00000004}, \ + {"debugb", 0x00000010}, /* GO_IF_LEGITIMATE_ADDRESS debug */ \ + {"nodebugb", -0x00000010}, \ + {"debugc", 0x00000020}, /* fix frame ptr debug */ \ + {"nodebugc", -0x00000020}, \ + {"debugd", 0x00000040}, /* branch/cc0 debug */ \ + {"nodebugd", -0x00000040}, \ + {"rnames", 0x00000008}, /* Register names like $a0 */ \ + {"nornames", -0x00000008}, /* Register names like $21 */ \ + {"nofixed-ovfl", 0x00000080}, /* Use addu and subu */ \ + {"fixed-ovfl", -0x00000080}, /* Use add and sub */ \ + {"G0", 0x00000100}, /* Bit 1 of sdata size */ \ + {"nG0", -0x00000100}, \ + {"noG0", -0x00000100}, \ + {"G1", 0x00000200}, /* Bit 2 of sdata size */ \ + {"nG1", -0x00000200}, \ + {"noG1", -0x00000200}, \ + {"G2", 0x00000400}, /* Bit 3 of sdata size */ \ + {"nG2", -0x00000400}, \ + {"noG2", -0x00000400}, \ + {"gpOPT", 0x00001000}, /* Optimize for global ptr */ \ + {"ngpOPT", -0x00001000}, \ + {"nogpOPT", -0x00001000}, \ + {"pic", 0x00002000}, /* Position independent code */ \ + {"npic", -0x00002000}, \ + {"nopic", -0x00002000}, \ + {"pic-large-object", 0x00004000}, /* Don't opt pic local funcs */ \ + {"nopic-large-object", -0x00004000}, \ + {"debuge", 0x00008000}, /* FUNCTION_ARG debug */ \ + {"nodebuge", -0x00008000}, \ + {"", TARGET_DEFAULT}} + +/* Default target_flags if no switches specified (-mmips-as, -mnofixed-ovfl, + -G0, -G1 [same as -G 8]). OSF/1 does not set -mmips-as, and sets -G 0. */ + +#ifndef OSF_OS +#define TARGET_DEFAULT 0x00000381 +#else +#define TARGET_DEFAULT 0x00000080 +#endif + +/* Default GVALUE (data item size threshold for selection of Sdata/data) + is computed : GVALUE == ( ((i=G0+2*G1+4*G2) < 6) + ? 1< 0) + +/* 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. */ +#define STATIC_CHAIN_REGNUM 2 + +/* Register in which address to store a structure value + is passed to a function. */ +#define STRUCT_VALUE_REGNUM 4 + +/* Mips registers used in prologue/epilogue code when the stack frame + is larger than 32K bytes. These registers must come from the + scratch register set, and not used for passing and returning + arguments and any other information used in the calling sequence + (such as pic). */ +#define MIPS_TEMP1_REGNUM 8 +#define MIPS_TEMP2_REGNUM 9 + +/* Define NO_FUNCTION_CSE if it is as good or better to call a constant + function address than to call an address kept in a register. */ +#define NO_FUNCTION_CSE + + +/* 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 MIPS has general and floating point registers. */ + + +enum reg_class { NO_REGS, GR_REGS, FP_REGS, ALL_REGS, LIM_REG_CLASSES } ; + +#define N_REG_CLASSES (int) LIM_REG_CLASSES + +#define GENERAL_REGS GR_REGS + +/* Give names of register classes as strings for dump file. */ + +#define REG_CLASS_NAMES \ + {"NO_REGS", "GR_REGS", "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 {{0x00000000, 0x00000000}, \ + {0xffffffff, 0x00000000}, \ + {0x00000000, 0xffffffff}, \ + {0xffffffff, 0xffffffff}} + + +/* 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. */ + +#define REGNO_REG_CLASS(REGNO) ((FP_REG_P (REGNO)) ? FP_REGS : GR_REGS) + +/* Define a table that lets us find quickly all the reg classes + containing a given one. This is the initializer for an + N_REG_CLASSES x N_REG_CLASSES array of reg class codes. + Row N is a sequence containing all the class codes for + classes that contain all the regs in class N. Each row + contains no duplicates, and is terminated by LIM_REG_CLASSES. */ + +/* We give just a dummy for the first element, which is for NO_REGS. */ +/* #define REG_CLASS_SUPERCLASSES {{LIM_REG_CLASSES}, \ + {GR_REGS,ALL_REGS,LIM_REG_CLASSES}, \ + {FP_REGS,ALL_REGS,LIM_REG_CLASSES}, \ + {ALL_REGS,LIM_REG_CLASSES} \ +} +*/ +/* We give just a dummy for the first element, which is for NO_REGS. */ +#define REG_CLASS_SUPERCLASSES {{LIM_REG_CLASSES}, \ + {ALL_REGS,LIM_REG_CLASSES}, \ + {ALL_REGS,LIM_REG_CLASSES}, \ + {LIM_REG_CLASSES} \ +} + +/* The inverse relationship: + for each class, a list of all reg classes contained in it. */ +#define REG_CLASS_SUBCLASSES \ +{{LIM_REG_CLASSES}, \ + {GR_REGS,LIM_REG_CLASSES}, \ + {FP_REGS,LIM_REG_CLASSES},\ + {GR_REGS, FP_REGS, ALL_REGS, LIM_REG_CLASSES}\ +} + +/* Define a table that lets us find quickly the class + for the subunion of any two classes. + + We say "subunion" because the result need not be exactly + the union; it may instead be a subclass of the union + (though the closer to the union, the better). + But if it contains anything beyond union of the two classes, + you will lose! + + This is an initializer for an N_REG_CLASSES x N_REG_CLASSES + array of reg class codes. The subunion of classes C1 and C2 + is just element [C1, C2]. */ + +#define REG_CLASS_SUBUNION \ +{{NO_REGS, GR_REGS, FP_REGS, ALL_REGS}, \ + {GR_REGS, GR_REGS, ALL_REGS, ALL_REGS}, \ + {FP_REGS, ALL_REGS, FP_REGS, ALL_REGS}, \ + {ALL_REGS, ALL_REGS, ALL_REGS, ALL_REGS}} + +/* The class value for index registers, and the one for base regs. */ + +#define INDEX_REG_CLASS GR_REGS +#define BASE_REG_CLASS GR_REGS + + + /* REGISTER AND CONSTANT CLASSES + */ + +/* Get reg_class from a letter such as appears in the machine +description. */ + /* DEFINED REGISTER CLASSES: + ** + ** 'f' : Floating point registers + ** 'y' : General register when used to + ** transfer chunks of Floating point + ** with mfc1 mtc1 insn + */ + +#define REG_CLASS_FROM_LETTER(C) \ + ((C) == 'f' ? FP_REGS: \ + (C) == 'y' ? GR_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. */ + +/* For MIPS, `I' is used for the range of constants an arithmetic insn + can actually contain (16 bits signed integers). + `J' is used for the range which is just zero (since that is + available as $R0). + `K' is used for the range of constants a logical insn + can actually contain (16 bit zero-extended integers). +*/ + +#define SMALL_INT(X) ((unsigned) (INTVAL (X) + 0x8000) < 0x10000) +#define SMALL_INT_UNSIGNED(X) ((unsigned) (INTVAL (X)) < 0x10000) + +#define CONST_OK_FOR_LETTER_P(VALUE, C) \ + ((C) == 'I' ? (unsigned) ((VALUE) + 0x8000) < 0x10000 \ + : (C) == 'J' ? (VALUE) == 0 \ + : (C) == 'K' ? (unsigned) (VALUE) < 0x10000 \ + : 0) + +/* Similar, but for floating constants, and defining letters G and H. + Here VALUE is the CONST_DOUBLE rtx itself. */ + + /* DEFINED FLOATING CONSTANT CLASSES: + ** + ** 'G' : Floating point 0 + */ +#define CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C) \ + ((C) == 'G' && CONST_DOUBLE_LOW ((VALUE)) == 0 \ + && CONST_DOUBLE_HIGH ((VALUE)) == 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. */ + +#define PREFERRED_RELOAD_CLASS(X,CLASS) \ + (((GET_MODE(X) == SFmode) || (GET_MODE(X) == DFmode))? FP_REGS : \ + ((GET_MODE(X) == VOIDmode) ? GR_REGS :(CLASS))) + +/* Same but Mode has been extracted already +*/ + +#define PREFERRED_RELOAD_CLASS_FM(X,CLASS) \ + ((((X) == SFmode) || ((X) == DFmode))? FP_REGS : \ + (((X) == VOIDmode) ? GR_REGS :(CLASS))) + +/* Return the maximum number of consecutive registers + needed to represent mode MODE in a register of class CLASS. */ + +#define CLASS_MAX_NREGS(CLASS, MODE) \ + ((((MODE) == DFmode) || ((MODE) == SFmode)) ? 2 \ + : ((MODE) == VOIDmode)? ((CLASS) == FP_REGS ? 2 :1) \ + : ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)) + + +/* Stack layout; function entry, exit and calling. */ + +/* 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. */ +#define STARTING_FRAME_OFFSET -8 + +/* If we generate an insn to push BYTES bytes, + this says how many the stack pointer really advances by. + On the vax, sp@- in a byte insn really pushes a word. */ + +/* #define PUSH_ROUNDING(BYTES) 0 */ + +/* Offset of first parameter from the argument pointer register value. */ +#define FIRST_PARM_OFFSET(FNDECL) 0 + +/* Offset from top-of-stack address to location to store the + function parameter if it can't go in a register. + Addresses for following parameters are computed relative to this one. + + It also has the effect of counting register arguments in the total + argument size. */ +#define FIRST_PARM_CALLER_OFFSET(FNDECL) 0 + +/* When a parameter is passed in a register, stack space is still + allocated for it. For the MIPS, stack space must be allocated, cf + Asm Lang Prog Guide page 7-8. + + BEWARE that some space is also allocated for non existing arguments + in register. In case an argument list is of form GF used registers + are a0 (a2,a3), but we should push over a1... */ +#define REG_PARM_STACK_SPACE + +/* Align stack frames on 64 bits (Double Word ). */ +#define STACK_BOUNDARY 64 + + +/* Standard GCC stack related variables that we reference. */ + +extern int optimize; +extern int may_call_alloca; +extern int current_function_calls_alloca; +extern int frame_pointer_needed; +extern int flag_omit_frame_pointer; + +/* MIPS external variables defined in out-mips.c. */ + +extern char *reg_numchar[]; /* register names as $r2, etc. */ +extern char *current_function_name; /* current function being compiled */ +extern int num_source_filenames; /* current .file # */ +extern int inside_function; /* != 0 if inside of a function */ +extern int stack_args_pushed; /* max bytes pushed for calls */ +extern int stack_args_preallocated; /* # bytes for args preallocated */ +extern int sdb_label_count; /* block start/end next label # */ +extern int mips_section_threshold; /* # bytes of data/sdata cutoff */ +extern int sym_lineno; /* sgi next label # for each stmt */ + + +/* Make sure 16 bytes are always allocated on the stack. */ +#ifndef STACK_ARGS_ADJUST +#define STACK_ARGS_ADJUST(SIZE) \ +{ \ + if (SIZE.constant < 16) \ + SIZE.constant = 16; \ +} +#endif + +/* Value is 1 if returning from a function call automatically + pops the arguments described by the number-of-args field in the call. + 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. */ + +#define RETURN_POPS_ARGS(FUNTYPE) 0 + + +/* Symbolic macros for the registers used to return integer and floating + point values. */ + +#define GP_RETURN 2 +#define FP_RETURN 32 + +/* Symbolic macros for the first/last argument registers. */ + +#define GP_ARG_FIRST 4 +#define GP_ARG_LAST 7 +#define FP_ARG_FIRST 44 +#define FP_ARG_LAST 47 + +#define MAX_ARGS_IN_REGISTERS 4 + +/* 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, \ + (GET_MODE_CLASS (MODE) == MODE_FLOAT) \ + ? FP_RETURN \ + : GP_RETURN) + +/* 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. */ + +#define FUNCTION_VALUE(VALTYPE, FUNC) LIBCALL_VALUE (TYPE_MODE (VALTYPE)) + + +/* 1 if N is a possible register number for a function value. + On the MIPS, R2 R3 and F0 F2 are the only register thus used. + Currently, R2 and F0 are only implemented here (C has no complex type) */ + +#define FUNCTION_VALUE_REGNO_P(N) ((N) == GP_RETURN || (N) == FP_RETURN) + +/* 1 if N is a possible register number for function argument passing. */ + +#define FUNCTION_ARG_REGNO_P(N) (((N) >= GP_ARG_FIRST && (N) <= GP_ARG_LAST) \ + || ((N) >= FP_ARG_FIRST && (N) <= FP_ARG_LAST \ + && (0 == (N) % 2))) + +/* A C expression which can inhibit the returning of certain function + values in registers, based on the type of value. A nonzero value says + to return the function value in memory, just as large structures are + always returned. Here TYPE will be a C expression of type + `tree', representing the data type of the value. + + Note that values of mode `BLKmode' are returned in memory + regardless of this macro. Also, the option `-fpcc-struct-return' + takes effect regardless of this macro. On most systems, it is + possible to leave the macro undefined; this causes a default + definition to be used, whose value is the constant 0. + + GCC normally converts 1 byte structures into chars, 2 byte + structs into shorts, and 4 byte structs into ints, and returns + them this way. Defining the following macro overides this, + to give us MIPS cc compatibility. */ + +#define RETURN_IN_MEMORY(TYPE) \ + ((TREE_CODE (TYPE) == RECORD_TYPE) || (TREE_CODE (TYPE) == UNION_TYPE)) + + +/* 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. +*/ + +typedef struct mips_args { + int gp_reg_found; + int arg_number; + int arg_words; +} *CUMULATIVE_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) \ +do { \ + CUM = (CUMULATIVE_ARGS) alloca (sizeof (*CUM)); \ + init_cumulative_args (CUM, FNTYPE); \ +} while (0) + +/* 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.) */ + +#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \ + (function_arg_advance(CUM, MODE, TYPE, NAMED)) + +extern void function_arg_advance(); + +/* 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)) + +/* 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)) + + +/* 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. */ + +extern void function_prologue (); + +#define FUNCTION_PROLOGUE(FILE, SIZE) function_prologue(FILE, 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. */ + +extern void function_epilogue (); + +#define FUNCTION_EPILOGUE(FILE, SIZE) function_epilogue(FILE, SIZE) + +/* Tell prologue and epilogue if Register containing return + address should be saved / restored. */ + +#define MUST_SAVE_REGISTER(regno) \ + ((regs_ever_live[regno] && !call_used_regs[regno]) || \ + (regno == FRAME_POINTER_REGNUM && frame_pointer_needed) || \ + (regno == 31 && regs_ever_live[31])) + +/* ALIGN FRAMES on double word boundaries */ + +#define AL_ADJUST_ALIGN(LOC) (((LOC)+7) & 0xfffffff8) + + +/* If the memory Address ADDR is relative to the frame pointer, + correct it to be relative to the stack pointer. This is for + when we don't use a frame pointer. + ADDR should be a variable name. */ + +#define FIX_FRAME_POINTER_ADDRESS(ADDR,DEPTH) \ +{ ADDR = mips_fix_frame_pointer(ADDR, DEPTH); } + +extern struct rtx_def *mips_fix_frame_pointer (); + +/* Output assembler code to FILE to increment profiler label # LABELNO + for profiling a function entry. */ + +#define FUNCTION_PROFILER(FILE, LABELNO) \ +{ \ + register char **reg_ptr = (TARGET_NAME_REGS) ? reg_names : reg_numchar; \ + \ + fprintf (FILE, "\t.set\tnoreorder\n"); \ + fprintf (FILE, "\t.set\tnoat\n"); \ + fprintf (FILE, "\tmove\t%s,%s\t\t# save current return address\n", \ + reg_ptr[1], reg_ptr[31]); \ + fprintf (FILE, "\tjal\t_mcount\n"); \ + fprintf (FILE, "\tsubu\t%s,%s,8\t\t# _mcount pops 2 words from stack\n", \ + reg_ptr[STACK_POINTER_REGNUM], reg_ptr[STACK_POINTER_REGNUM]); \ + fprintf (FILE, "\t.set\treorder\n"); \ + fprintf (FILE, "\t.set\tat\n"); \ +} + +/* 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. */ + +#define EXIT_IGNORE_STACK 1 + + +/* Addressing modes, and classification of registers for them. */ + +/* #define HAVE_POST_INCREMENT */ +/* #define HAVE_POST_DECREMENT */ + +/* #define HAVE_PRE_DECREMENT */ +/* #define HAVE_PRE_INCREMENT */ + +/* 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. + These definitions are NOT overridden anywhere. */ + +#define REGNO_OK_FOR_INDEX_P(regno) \ +((regno) < FIRST_PSEUDO_REGISTER || reg_renumber[regno] >= 0) + +#define REGNO_OK_FOR_BASE_P(regno) \ +((regno) < FIRST_PSEUDO_REGISTER || reg_renumber[regno] >= 0) + +/* 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 all. + 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. + Some source files that are used after register allocation + need to be strict. */ + +#ifndef REG_OK_STRICT + +#define REG_OK_FOR_INDEX_P(X) 1 /* ok if index or pseudo reg */ +#define REG_OK_FOR_BASE_P(X) 1 /* ok if base reg. of pseudo reg */ + +#else + +#define REG_OK_FOR_INDEX_P(X) REGNO_OK_FOR_INDEX_P (REGNO (X)) +#define REG_OK_FOR_BASE_P(X) REGNO_OK_FOR_BASE_P (REGNO (X)) + +#endif + + +/* Maximum number of registers that can appear in a valid memory address. */ + +#define MAX_REGS_PER_ADDRESS 1 + +/* 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. + + The other macros defined here are used only in GO_IF_LEGITIMATE_ADDRESS, + except for CONSTANT_ADDRESS_P which is actually machine-independent. */ + +/* 1 if X is an address that we could indirect through. */ +#define INDIRECTABLE_ADDRESS_P(X) \ + (CONSTANT_ADDRESS_P (X) \ + || (GET_CODE (X) == REG && REG_OK_FOR_BASE_P (X)) \ + || (GET_CODE (X) == PLUS \ + && ((xplus0 = XEXP (X, 0)), \ + (xplus1 = XEXP (X, 1)), \ + ((GET_CODE (xplus0) != REG && GET_CODE (xplus1) == REG) \ + ? ((xplus0 = XEXP (X, 1)), (xplus1 = XEXP (X, 0))) \ + : 0), \ + GET_CODE (xplus0) == REG) \ + && REG_OK_FOR_BASE_P (xplus0) \ + && ((GET_CODE (xplus1) == CONST_INT && SMALL_INT (xplus1)) \ + || (GET_CODE (xplus1) == LABEL_REF) \ + || (GET_CODE (xplus1) == SYMBOL_REF) \ + || (GET_CODE (xplus1) == CONST) \ + || (xplus0 == stack_pointer_rtx \ + && (GET_CODE (xplus1) == CONST || (GET_CODE (xplus1) == SYMBOL_REF)))))) + + +#if 1 +extern void trace (); +#define GO_PRINTF(x) trace(x) +#define GO_DEBUG_RTX(x) debug_rtx(x) + +#else +#define GO_PRINTF(x) +#define GO_DEBUG_RTX(x) +#endif + +/* Go to ADDR if X is a valid address not using indexing. + (This much is the easy part.) */ +#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \ +{ \ + register rtx xinsn = (X); \ + register rtx xplus0, xplus1; \ + \ + if (TARGET_DEBUGB_MODE) \ + { \ + GO_PRINTF ("\n==================== GO_IF_LEGITIMATE_ADDRESS\n"); \ + GO_DEBUG_RTX (xinsn); \ + } \ + \ + if (GET_CODE (xinsn) == REG) goto ADDR; \ + if (INDIRECTABLE_ADDRESS_P (xinsn)) goto ADDR; \ + \ + if (TARGET_DEBUGB_MODE) \ + GO_PRINTF ("Not a legitimate address\n"); \ +} + + +#define CONSTANT_ADDRESS_P(X) CONSTANT_P (X) + + +/* Nonzero if the constant value X is a legitimate general operand. + It is given that X satisfies CONSTANT_P or is a CONST_DOUBLE. + + At present, GAS doesn't understand li.[sd], so don't allow it + to be generated at present. Also, the MIPS assembler does not + grok li.d Infinity. */ + +#define LEGITIMATE_CONSTANT_P(X) (GET_CODE (X) != CONST_DOUBLE) + +/* 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. + + For the MIPS (so far ..), nothing needs to be done. + + ACHTUNG this is actually used by the FLOW analysis to get rid + of statements.... + +*/ + +#define LEGITIMIZE_ADDRESS(X,OLDX,MODE,WIN) {} + +/* Go to LABEL if ADDR (a legitimate address expression) + has an effect that depends on the machine mode it is used for. */ + +#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR,LABEL) {} + + +/* 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. + Do not define this if the table should contain absolute addresses. */ +/* #define CASE_VECTOR_PC_RELATIVE */ + +/* 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 4 + +/* Nonzero if access to memory by bytes is slow and undesirable. */ +#define SLOW_BYTE_ACCESS 0 + +/* 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 + +/* Declarations for condition code stuff. */ +extern void compare_collect (); +extern void compare_restore (); + +/* Define this if zero-extension is slow (more than one real instruction). */ +#define SLOW_ZERO_EXTEND + +/* Define if shifts truncate the shift count + which implies one can omit a sign-extension or zero-extension + of a shift count. + + Only 5 bits are used in SLLV and SRLV +*/ +#define SHIFT_COUNT_TRUNCATED + + +/* 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 SImode + +/* A function address in a call instruction + is a word address (for indexing purposes) + so give the MEM rtx a words's mode. */ + +#define FUNCTION_MODE SImode + +/* Define TARGET_MEM_FUNCTIONS if we want to use calls to memcpy and + memset, instead of the BSD functions bcopy and bzero. */ + +#if defined(MIPS_SYSV) || defined(OSF_OS) +#define TARGET_MEM_FUNCTIONS +#endif + +/* 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) \ + case CONST_INT: \ + /* Constant zero is super cheap due to register 0. */ \ + if (RTX == const0_rtx) return 0; \ + if ((INTVAL (RTX) < 0x7fff) && (- INTVAL(RTX) < 0x7fff)) return 1; \ + case CONST: \ + case LABEL_REF: \ + case SYMBOL_REF: \ + return 3; \ + case CONST_DOUBLE: \ + return 5; + +/* Used in by the peephole code. */ +#define additive_op(op,mode) (GET_CODE (op) == PLUS || GET_CODE (op) == MINUS) + + +/* Tell final.c how to eliminate redundant test instructions. */ + +/* Here we define machine-dependent flags and fields in cc_status + (see `conditions.h'). No extra ones are needed for the vax. */ +/* Tell final.c how to eliminate redundant test instructions. */ + +/* Tell final.c how to eliminate redundant test instructions. */ + +/* Here we define machine-dependent flags and fields in cc_status + (see `conditions.h'). No extra ones are needed for the vax. */ + +/* Store in cc_status the expressions + that the condition codes will describe + after execution of an instruction whose pattern is EXP. + Do not alter them if the instruction would not alter the cc's. */ + +#define NOTICE_UPDATE_CC(EXP, INSN) \ + CC_STATUS_INIT; + + +/* Here we define machine-dependent flags and fields in cc_status + (see `conditions.h'). */ + + +/* Control the assembler format that we output. */ + +/* Output at beginning of assembler file. + If we are optimizing to use the global pointer, create a temporary + file to hold all of the text stuff, and write it out to the end. + This is needed because the MIPS assembler is evidently one pass, + and if it hasn't seen the relevant .comm/.lcomm/.extern/.sdata + declaration when the code is processed, it generates a two + instruction sequence. */ + +extern void mips_asm_file_start (); + +#define ASM_FILE_START(STREAM) mips_asm_file_start (STREAM) + +/* Output to assembler file text saying following lines + may contain character constants, extra white space, comments, etc. */ + +#define ASM_APP_ON " #APP\n" + +/* Output to assembler file text saying following lines + no longer contain unusual constructs. */ + +#define ASM_APP_OFF " #NO_APP\n" + +/* How to refer to registers in assembler output. + This sequence is indexed by compiler's hard-register-number (see above). */ + +#define REGISTER_NAMES \ +{"$0", "at", "v0", "v1", "a0", "a1", "a2", "a3", "t0", \ + "t1", "t2", "t3", "t4", "t5", "t6", "t7","s0", \ + "s1","s2","s3","s4","s5","s6","s7","t8","t9", \ + "k0","k1","gp","sp","fp","ra", \ + "$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" \ +} +#define REGISTER_NUMCHAR \ +{ \ +"$0","$1","$2","$3","$4","$5","$6","$7","$8","$9", \ +"$10","$11","$12","$13","$14","$15","$16","$17","$18","$19", \ +"$20","$21","$22","$23","$24","$25","$26","$27","$28","$sp", \ +"$fp","$31", \ +"$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" \ +} + +#define REG_NAME(reg) (TARGET_NAME_REGS ? reg_names[reg] : reg_numchar[reg]) + + +/* 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 + + +/* Print an instruction operand X on file FILE. + CODE is the code from the %-spec that requested printing this operand; + if `%z3' was used to print operand 3, then CODE is 'z'. + CODE is used as follows: + + LIST OF PRINT OPERAND CODES: + + 'x' X is CONST_INT, prints 16 bits in hex format. + 'd' output integer constant in decimal, + ':' Prints an 'u' if flag -mnofixed-ovfl (for addu vs. add) */ + +#define PRINT_OPERAND_PUNCT_VALID_P(CODE) \ + ((CODE) == ':') + +#define PRINT_OPERAND(FILE, X, CODE) \ +{ \ + if ((CODE) == ':') \ + { \ + if (TARGET_NOFIXED_OVFL) \ + fprintf(FILE,"u"); \ + } \ + \ + else if (GET_CODE (X) == REG) \ + { \ + int regnum = REGNO (X); \ + \ + if (CODE == 'M') \ + regnum += MOST_SIGNIFICANT_WORD; \ + else if (CODE == 'L') \ + regnum += LEAST_SIGNIFICANT_WORD; \ + else if (CODE == 'D') \ + regnum++; \ + \ + fprintf (FILE, "%s", \ + ((TARGET_NAME_REGS) ? reg_names : reg_numchar)[regnum]); \ + } \ + \ + else if (GET_CODE (X) == MEM) \ + output_address (XEXP (X, 0)); \ + \ + else if (GET_CODE (X) == CONST_DOUBLE) \ + { \ + union { double d; int i[2]; } u; \ + u.i[0] = CONST_DOUBLE_LOW (X); \ + u.i[1] = CONST_DOUBLE_HIGH (X); \ + if (GET_MODE (X) == SFmode) \ + { \ + float f; \ + f = u.d; \ + u.d = f; \ + } \ + fprintf (FILE, "%.20e", u.d); \ + } \ + \ + else if ((CODE == 'x') && (GET_CODE(X) == CONST_INT)) \ + fprintf(FILE,"0x%x", 0xffff & (INTVAL(X))); \ + \ + else if ((CODE == 'd') && (GET_CODE(X) == CONST_INT)) \ + fprintf(FILE,"%d", (INTVAL(X))); \ + \ + else if ((CODE) == 'd') \ + fatal ("Code d was found & insn was not CONST_INT"); \ + \ + else \ + output_addr_const (FILE, X); \ +} + + +/* Print a memory operand whose address is X, on file FILE. */ + +#define PRINT_OPERAND_ADDRESS(FILE, ADDR) \ +{ \ + register rtx addr = ADDR; \ + register char **reg_ptr = (TARGET_NAME_REGS) ? reg_names : reg_numchar; \ + \ + switch (GET_CODE (addr)) \ + { \ + default: \ + abort_with_insn (addr, "PRINT_OPERAND_ADDRESS, illegal insn #1"); \ + break; \ + \ + case REG: \ + fprintf (FILE, "0(%s)", reg_ptr [REGNO (addr)]); \ + break; \ + \ + case PLUS: \ + { \ + register rtx reg = (rtx)0; \ + register rtx offset = (rtx)0; \ + register rtx arg0 = XEXP (addr, 0); \ + register rtx arg1 = XEXP (addr, 1); \ + \ + if (GET_CODE (arg0) == REG) \ + { \ + reg = arg0; \ + offset = arg1; \ + if (GET_CODE (offset) == REG) \ + abort_with_insn (addr, "PRINT_OPERAND_ADDRESS, 2 regs"); \ + } \ + else if (GET_CODE (arg1) == REG) \ + { \ + reg = arg1; \ + offset = arg0; \ + } \ + else if (CONSTANT_P (arg0) && CONSTANT_P (arg1)) \ + { \ + output_addr_const (FILE, addr); \ + break; \ + } \ + else \ + abort_with_insn (addr, "PRINT_OPERAND_ADDRESS, no regs"); \ + \ + if (!CONSTANT_P (offset)) \ + abort_with_insn (addr, "PRINT_OPERAND_ADDRESS, illegal insn #2"); \ + \ + output_addr_const (FILE, offset); \ + fprintf (FILE, "(%s)", reg_ptr [REGNO (reg)]); \ + } \ + break; \ + \ + case LABEL_REF: \ + case SYMBOL_REF: \ + case CONST_INT: \ + case CONST: \ + output_addr_const (FILE, addr); \ + break; \ + } \ +} + + +/* How to tell the debugger about changes of source files. Note, the + mips ECOFF format cannot deal with changes of files inside of + functions, which means the output of parser generators like bison + is generally not debuggable without using the -l switch. Lose, + lose, lose. Silicon graphics seems to want all .file's hardwired + to 1. */ + +#ifndef SET_FILE_NUMBER +#define SET_FILE_NUMBER() ++num_source_filenames +#endif + +#define ASM_OUTPUT_SOURCE_FILENAME(STREAM, NAME) \ +{ \ + SET_FILE_NUMBER (); \ + fprintf (STREAM, "\t%s.file\t%d \"%s\"\n", \ + (TARGET_GAS || !inside_function) ? "" : "#", \ + num_source_filenames, NAME); \ +} + +/* This is how to output a note the debugger telling it the line number + to which the following sequence of instructions corresponds. + Silicon graphics puts a label after each .loc. */ + +#ifndef LABEL_AFTER_LOC +#define LABEL_AFTER_LOC(STREAM) +#endif + +#define ASM_OUTPUT_SOURCE_LINE(STREAM, LINE) \ +{ \ + fprintf (STREAM, "\n\t.loc\t%d %d\n", num_source_filenames, LINE); \ + LABEL_AFTER_LOC (STREAM); \ +} + +/* The MIPS implementation uses some labels for it's own purposed. The + following lists what labels are created, and are all formed by the + pattern $L[a-z].*. The machine independent portion of GCC creates + labels matching: $L[A-Z][0-9]+ and $L[0-9]+. + + LM[0-9]+ Sillicon graphics label before each stmt. + $Lb[0-9]+ Begin blocks for MIPS debug support + $Ldtable Beginning of the PIC data table + $Le[0-9]+ End blocks for MIPS debug support + $Ls[0-9]+ FP-SP difference if -fomit-frame-pointer */ + +/* 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. + + If we are optimizing the gp, remember that this label has been put + out, so we know not to emit an .extern for it in mips_asm_file_end. + We use one of the common bits in the IDENTIFIER tree node for this, + since those bits seem to be unused, and we don't have any method + of getting the decl nodes from the name. */ + +#ifndef COLLECT +#define ASM_OUTPUT_LABEL(STREAM,NAME) \ +do { \ + assemble_name (STREAM, NAME); \ + fputs (":\n", STREAM); \ + \ + if (TARGET_GP_OPT && mips_section_threshold != 0) \ + { \ + tree name_tree = get_identifier (NAME); \ + TREE_ADDRESSABLE (name_tree) = 1; \ + } \ +} while (0) + +#else +#define ASM_OUTPUT_LABEL(STREAM,NAME) \ +do { \ + assemble_name (STREAM, NAME); \ + fputs (":\n", STREAM); \ +} while (0) +#endif + +/* 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(STREAM,NAME) \ + do { \ + fputs ("\t.globl\t", STREAM); \ + assemble_name (STREAM, NAME); \ + fputs ("\n", STREAM); \ + } while (0) + +/* This says how to output an assembler line + to define a global common symbol. */ + +#define ASM_OUTPUT_COMMON(STREAM, NAME, SIZE, ROUNDED) \ +do { \ + fputs ("\n\t.comm\t", (STREAM)); \ + assemble_name ((STREAM), (NAME)); \ + fprintf ((STREAM), ",%u\n", (ROUNDED)); \ + \ + if (TARGET_GP_OPT && mips_section_threshold != 0) \ + { \ + tree name_tree = get_identifier (NAME); \ + TREE_ADDRESSABLE (name_tree) = 1; \ + } \ +} while (0) + +/* This says how to output an assembler line + to define a local common symbol. */ + +#define ASM_OUTPUT_LOCAL(STREAM, NAME, SIZE, ROUNDED) \ +do { \ + fputs ("\n\t.lcomm\t", (STREAM)); \ + assemble_name ((STREAM), (NAME)); \ + fprintf ((STREAM), ",%u\n", (ROUNDED)); \ + \ + if (TARGET_GP_OPT && mips_section_threshold != 0) \ + { \ + tree name_tree = get_identifier (NAME); \ + TREE_ADDRESSABLE (name_tree) = 1; \ + } \ +} while (0) + + +/* This says how to output an external. It would be possible not to + output anything and let undefined symbol become external. However + the assembler uses length information on externals to allocate in + data/sdata bss/sbss, thereby saving exec time. */ + +#define ASM_OUTPUT_EXTERNAL(STREAM,DECL,NAME) \ + mips_output_external(STREAM,DECL,NAME) + +/* This says what to print at the end of the assembly file */ +#define ASM_FILE_END(STREAM) mips_asm_file_end(STREAM) + + +/* This is how to declare a function name. The actual work of + emitting the label is moved to function_prologue, so that we can + get the line number correctly emitted before the .ent directive, + and after any .file directives. + + Also, switch files if we are optimizing the global pointer. */ + +#define ASM_DECLARE_FUNCTION_NAME(STREAM,NAME,DECL) \ +{ \ + extern FILE *asm_out_text_file; \ + if (TARGET_GP_OPT) \ + STREAM = asm_out_text_file; \ + \ + current_function_name = NAME; \ +} + +/* This is how to output a reference to a user-level label named NAME. + `assemble_name' uses this. */ + +#define ASM_OUTPUT_LABELREF(STREAM,NAME) \ + fprintf (STREAM, "%s", NAME) + +/* 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(STREAM,PREFIX,NUM) \ + fprintf (STREAM, "$%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%d", PREFIX, NUM) + +/* This is how to output an assembler line defining a `double' constant. */ + +#define ASM_OUTPUT_DOUBLE(STREAM,VALUE) \ +{ \ + union { double d; long l[2]; } u2; \ + u2.d = VALUE; \ + fprintf (STREAM, "\t.word\t0x%08lx\t\t# %.20g\n\t.word\t0x%08lx\n", \ + u2.l[0], u2.d, u2.l[1]); \ +} + +/* This is how to output an assembler line defining a `float' constant. */ + +#define ASM_OUTPUT_FLOAT(STREAM,VALUE) \ +{ \ + union { float f; long l; } u2; \ + u2.f = VALUE; \ + fprintf (STREAM, "\t.word\t0x%08lx\t\t# %.12g\n", u2.l, u2.f); \ +} + +/* This is how to output an assembler line defining an `int' constant. */ + +#define ASM_OUTPUT_INT(STREAM,VALUE) \ +{ \ + fprintf (STREAM, "\t.word\t"); \ + output_addr_const (STREAM, (VALUE)); \ + fprintf (STREAM, "\n"); \ +} + +/* Likewise for `char' and `short' constants. */ + +#define ASM_OUTPUT_SHORT(STREAM,VALUE) \ +{ \ + fprintf (STREAM, "\t.half\t"); \ + output_addr_const (STREAM, (VALUE)); \ + fprintf (STREAM, "\n"); \ +} + +#define ASM_OUTPUT_CHAR(STREAM,VALUE) \ +{ \ + fprintf (STREAM, "\t.byte\t"); \ + output_addr_const (STREAM, (VALUE)); \ + fprintf (STREAM, "\n"); \ +} + +/* This is how to output an assembler line defining an `int' constant, + which is not in tree format (for collect.c). */ + +#define ASM_OUTPUT_INT_CONST(STREAM,VALUE) \ + fprintf(STREAM, "\t.word\t%d\n", VALUE) + +/* This is how to output an assembler line defining an external/static + address which is not in tree format (for collect.c). */ + +#define ASM_OUTPUT_PTR_INT_SUM(STREAM, NAME, VALUE) \ +do { \ + fprintf (STREAM, "\t.word\t"); \ + ASM_OUTPUT_LABELREF (STREAM, NAME); \ + fprintf (STREAM, "+%d\n", VALUE); \ +} while (0) + +#define ASM_OUTPUT_LABELREF_AS_INT(STREAM, NAME) \ +do { \ + fprintf (STREAM, "\t.word\t"); \ + ASM_OUTPUT_LABELREF (STREAM, NAME); \ + fprintf (STREAM, "\n"); \ +} while (0) + +/* This is how to output an assembler line for a numeric constant byte. */ + +#define ASM_OUTPUT_BYTE(STREAM,VALUE) \ +{ \ + fprintf (STREAM, "\t.byte\t0x%x\n", (VALUE)); \ +} + +/* This is how to output an element of a case-vector that is absolute. */ + +#define ASM_OUTPUT_ADDR_VEC_ELT(STREAM, VALUE) \ +{ \ + fprintf (STREAM, "\t.word\t$L%d\n", VALUE); \ +} + +/* This is how to output an element of a case-vector that is relative. + (We do not use such vectors, + but we must define this macro anyway.) */ + +#define ASM_OUTPUT_ADDR_DIFF_ELT(STREAM, VALUE, REL) \ +{ \ + fprintf (STREAM, "\t.word\t$L%d-$L%d\n", VALUE, REL); \ +} + +/* This is how to emit the initial label for switch statements. We + need to put the switch labels somewhere else from the text section, + because the MIPS assembler gets real confused about line numbers if + .word's appear in the text section. */ + +#define ASM_OUTPUT_CASE_LABEL(STREAM, PREFIX, NUM, JUMPTABLE) \ +{ \ + rdata_section (); \ + ASM_OUTPUT_ALIGN (STREAM, 2); \ + ASM_OUTPUT_INTERNAL_LABEL (STREAM, PREFIX, NUM); \ +} + +/* Output at the end of a switch's jump table. */ + +#define ASM_OUTPUT_CASE_END(STREAM, NUM, INSN) \ +{ \ + text_section (); \ +} + +/* 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(STREAM,LOG) \ +{ \ + int mask = (1 << (LOG)) - 1; \ + fprintf (STREAM, "\t.align\t%d\n", (LOG)); \ +} + +/* This is how to output an assembler line to to advance the location + counter by SIZE bytes. */ +#define ASM_OUTPUT_SKIP(STREAM,SIZE) \ +{ \ + fprintf (STREAM, "\t.space\t%u\n", (SIZE)); \ +} + +/* This is how to output a string. */ +#define ASM_OUTPUT_ASCII(STREAM, STRING, LEN) \ +do { \ + register int i, c, len = LEN, cur_pos = 17; \ + register unsigned char *string = (unsigned char *)STRING; \ + fprintf (STREAM, "\t.ascii\t\""); \ + for (i = 0; i < len; i++) \ + { \ + register int c = string[i]; \ + \ + switch (c) \ + { \ + case '\"': \ + case '\\': \ + putc ('\\', STREAM); \ + putc (c, STREAM); \ + cur_pos += 2; \ + break; \ + \ + case TARGET_NEWLINE: \ + fputs ("\\n", STREAM); \ + if (i+1 < len \ + && (((c = string[i+1]) >= '\040' && c <= '~') \ + || c == TARGET_TAB)) \ + cur_pos = 32767; /* break right here */ \ + else \ + cur_pos += 2; \ + break; \ + \ + case TARGET_TAB: \ + fputs ("\\t", STREAM); \ + cur_pos += 2; \ + break; \ + \ + case TARGET_FF: \ + fputs ("\\f", STREAM); \ + cur_pos += 2; \ + break; \ + \ + case TARGET_BS: \ + fputs ("\\b", STREAM); \ + cur_pos += 2; \ + break; \ + \ + case TARGET_CR: \ + fputs ("\\r", STREAM); \ + cur_pos += 2; \ + break; \ + \ + default: \ + if (c >= ' ' && c < 0177) \ + { \ + putc (c, STREAM); \ + cur_pos++; \ + } \ + else \ + { \ + fprintf (STREAM, "\\%03o", c); \ + cur_pos += 4; \ + } \ + } \ + \ + if (cur_pos > 72 && i+1 < len) \ + { \ + cur_pos = 17; \ + fprintf (STREAM, "\"\n\t.ascii\t\""); \ + } \ + } \ + fprintf (STREAM, "\"\n"); \ +} while (0) + +/* Handle certain cpp directives used in header files on sysV. */ +#define SCCS_DIRECTIVE + +/* Output #ident as a in the read-only data section. */ +#define ASM_OUTPUT_IDENT(FILE, STRING) \ +{ \ + char *p = STRING; \ + int size = strlen (p) + 1; \ + rdata_section (); \ + assemble_string (p, size); \ +} + + +/* Output before read-only data. */ + +#define TEXT_SECTION_ASM_OP "\t.text" + +/* Output before writable data. */ + +#define DATA_SECTION_ASM_OP "\t.data" + +/* Output before writable short data. */ + +#define SDATA_SECTION_ASM_OP "\t.sdata" + +/* Output before read-only data. */ + +#define RDATA_SECTION_ASM_OP "\t.rdata" + +/* What other sections we support other than the normal .data/.text. */ + +#define EXTRA_SECTIONS in_sdata, in_rdata, in_last_p1 + +/* Define the additional functions to select our additional sections. */ + +/* on the MIPS it is not a good idea to put constants in the text + section, since this defeats the sdata/data mechanism. This is + especially true when -O is used. In this case an effort is made to + address with faster (gp) register relative addressing, which can + only get at sdata and sbss items (there is no stext !!) However, + if the constant is too large for sdata, and it's readonly, it + will go into the .rdata section. */ + +#define EXTRA_SECTION_FUNCTIONS \ +void \ +sdata_section () \ +{ \ + if (in_section != in_sdata) \ + { \ + fprintf (asm_out_file, "%s\n", SDATA_SECTION_ASM_OP); \ + in_section = in_sdata; \ + } \ +} \ + \ +void \ +rdata_section () \ +{ \ + if (in_section != in_rdata) \ + { \ + fprintf (asm_out_file, "%s\n", RDATA_SECTION_ASM_OP); \ + in_section = in_rdata; \ + } \ +} + +/* Given a decl node or constant node, choose the section to output it in + and select that section. */ + +#define SELECT_SECTION_MODE(MODE,RTX) \ +{ \ + extern int mips_section_threshold; \ + if ((GET_MODE_SIZE(MODE) / BITS_PER_UNIT) <= mips_section_threshold \ + && mips_section_threshold > 0) \ + sdata_section (); \ + else \ + rdata_section (); \ +} \ + +#define SELECT_SECTION(DECL) \ +{ \ + extern int mips_section_threshold; \ + if (int_size_in_bytes (TREE_TYPE (DECL)) <= mips_section_threshold \ + && mips_section_threshold > 0) \ + sdata_section (); \ + else if (TREE_CODE (DECL) == STRING_CST) \ + { \ + if (flag_writable_strings) \ + data_section (); \ + else \ + rdata_section (); \ + } \ + else if (TREE_CODE (DECL) != VAR_DECL) \ + rdata_section (); \ + else if (!TREE_READONLY (DECL) || TREE_VOLATILE (DECL)) \ + data_section (); \ + else \ + rdata_section (); \ +} + + +/* 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 ASM_OUTPUT_REG_POP(STREAM,REGNO) \ +do { \ + extern char *reg_numchar[]; \ + char **reg_name_ptr = (TARGET_NAME_REGS) ? reg_names : reg_numchar; \ + fprintf (STREAM, "\tsubu\t%s,%s,4\n\tsw\t%s,0(%s)\n", \ + reg_name_ptr[STACK_POINTER_REGNUM], \ + reg_name_ptr[STACK_POINTER_REGNUM], \ + reg_name_ptr[REGNO], \ + reg_name_ptr[STACK_POINTER_REGNUM]); \ +} while (0) + +#define ASM_OUTPUT_REG_PUSH(STREAM,REGNO) \ +do { \ + extern char *reg_numchar[]; \ + char **reg_name_ptr = (TARGET_NAME_REGS) ? reg_names : reg_numchar; \ + fprintf (STREAM, "\tlw\t%s,0(%s)\n\taddu\t%s,%s,4\n", \ + reg_name_ptr[REGNO], \ + reg_name_ptr[STACK_POINTER_REGNUM], \ + reg_name_ptr[STACK_POINTER_REGNUM], \ + reg_name_ptr[STACK_POINTER_REGNUM]); \ +} while (0) + + +/* Define the parentheses used to group arithmetic operations + in assembler code. */ + +#define ASM_OPEN_PAREN "(" +#define ASM_CLOSE_PAREN ")" + + +/* Tell G++'s collect that MIPS' based ports do not have leading + underscores. */ + +#ifndef NO_UNDERSCORES +#define NO_UNDERSCORES +#endif NO_UNDERSCORES + +/* Tell G++ that we need to run collect. */ + +#ifndef USE_COLLECT +#define USE_COLLECT +#endif + +#ifndef EXTENDED_COFF +#define EXTENDED_COFF +#endif + +/* The following are for collect.c which has it's own idea of + which macros should be used. */ + +#define ASM_INT_OP ".word " +#define ASM_SHORT_OP ".half " +#define ASM_CHAR_OP ".byte " diff --git a/gcc-1.40/config/tm-news.h b/gcc-1.40/config/tm-news.h new file mode 100644 index 0000000..6ed2771 --- /dev/null +++ b/gcc-1.40/config/tm-news.h @@ -0,0 +1,408 @@ +/* Definitions of target machine for GNU compiler. SONY NEWS-OS 3.0 version. + Copyright (C) 1987, 1989 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 1, 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. */ + +#ifndef USE_GAS +/* This controls conditionals in tm-m68k.h. */ +#define MOTOROLA +#define SONY_ASM +#endif + +#include "tm-m68k.h" + +/* See tm-m68k.h. 7 means 68020 with 68881. */ + +#define TARGET_DEFAULT 7 + +/* Define __HAVE_68881__ in preprocessor, unless -msoft-float is specified. + This will control the use of inline 68881 insns in certain macros. */ + +#define CPP_SPEC "%{!msoft-float:-D__HAVE_68881__}" + +/* Names to predefine in the preprocessor for this target machine. */ +/* These are the ones defined by Sony, plus mc68000 for uniformity with + GCC on other 68000 systems. */ + +#ifdef news700 +#define CPP_PREDEFINES "-Dunix -Dbsd43 -Dsony -Dsony_news -Dmc68000 -Dmc68020 -Dnews700" +#endif +#ifdef news800 +#define CPP_PREDEFINES "-Dunix -Dbsd43 -Dsony -Dsony_news -Dmc68000 -Dmc68020 -Dnews800" +#endif +#ifdef news900 +#define CPP_PREDEFINES "-Dunix -Dbsd43 -Dsony -Dsony_news -Dmc68000 -Dmc68020 -Dnews900" +#endif +#ifdef news1500 +#define CPP_PREDEFINES "-Dunix -Dbsd43 -Dsony -Dsony_news -Dmc68000 -Dmc68020 -Dmc68030 -Dnews1500" +#endif +#ifdef news1700 +#define CPP_PREDEFINES "-Dunix -Dbsd43 -Dsony -Dsony_news -Dmc68000 -Dmc68020 -Dmc68030 -Dnews1700" +#endif +#ifdef news1800 +#define CPP_PREDEFINES "-Dunix -Dbsd43 -Dsony -Dsony_news -Dmc68000 -Dmc68020 -Dmc68030 -Dnews1800" +#endif +#ifdef news1900 +#define CPP_PREDEFINES "-Dunix -Dbsd43 -Dsony -Dsony_news -Dmc68000 -Dmc68020 -Dmc68030 -Dnews1900" +#endif + +/* This is BSD, so it wants DBX format. */ + +#define DBX_DEBUGGING_INFO + +/* Override parts of tm-m68k.h to fit Sony's assembler syntax. */ + +#undef POINTER_BOUNDARY +#undef BIGGEST_ALIGNMENT +#undef CALL_USED_REGISTERS +#undef FUNCTION_VALUE +#undef LIBCALL_VALUE +#undef FUNCTION_PROFILER + +#ifdef MOTOROLA +#undef FUNCTION_PROLOGUE +#undef FUNCTION_EPILOGUE +#undef REGISTER_NAMES +#undef ASM_OUTPUT_REG_PUSH +#undef ASM_OUTPUT_REG_POP +#undef ASM_OUTPUT_DOUBLE +#undef ASM_OUTPUT_SKIP +#undef ASM_FORMAT_PRIVATE_NAME +#undef PRINT_OPERAND +#undef PRINT_OPERAND_ADDRESS +#endif + +#undef ASM_OUTPUT_ALIGN + +/* Allocation boundary (in *bits*) for storing pointers in memory. */ +#define POINTER_BOUNDARY 32 + +/* There is no point aligning anything to a rounder boundary than this. */ +#define BIGGEST_ALIGNMENT 32 + +/* A bitfield declared as `int' forces `int' alignment for the struct. */ +#define PCC_BITFIELD_TYPE_MATTERS 1 + +/* NEWS makes d2, d3, fp2 and fp3 unsaved registers, unlike the Sun system. */ + +#define CALL_USED_REGISTERS \ + {1, 1, 1, 1, 0, 0, 0, 0, \ + 1, 1, 0, 0, 0, 0, 0, 1, \ + 1, 1, 1, 1, 0, 0, 0, 0} + +/* NEWS returns floats and doubles in fp0, not d0/d1. */ + +#define FUNCTION_VALUE(VALTYPE,FUNC) LIBCALL_VALUE (TYPE_MODE (VALTYPE)) + +#define LIBCALL_VALUE(MODE) \ + gen_rtx (REG, (MODE), ((TARGET_68881 && ((MODE) == SFmode || (MODE) == DFmode)) ? 16 : 0)) + +#define ASM_OUTPUT_ALIGN(FILE,LOG) \ + fprintf (FILE, "\t.align %d\n", (LOG)) + +#ifdef MOTOROLA + +/* Don't try to define `gcc_compiled.' since the assembler does not + accept symbols with periods. This is no real loss since GDB only + really needs it for parms passed in registers. */ +#define ASM_IDENTIFY_GCC(FILE) + +#define FUNCTION_PROLOGUE(FILE, SIZE) \ +{ register int regno; \ + register int mask = 0; \ + extern char call_used_regs[]; \ + int fsize = ((SIZE) + 3) & -4; \ + if (frame_pointer_needed) \ + { if (fsize < 0x8000) \ + fprintf (FILE, "\tlink fp,#%d\n", -fsize); \ + else if (TARGET_68020) \ + fprintf (FILE, "\tlink.l fp,#%d\n", -fsize); \ + else \ + fprintf (FILE, "\tlink fp,#0\n\tsub.l #%d,sp\n", fsize); } \ + for (regno = 16; regno < FIRST_PSEUDO_REGISTER; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + mask |= 1 << (regno - 16); \ + if (mask != 0) \ + fprintf (FILE, "\tfmovem.x #0x%x,-(sp)\n", mask & 0xff); \ + mask = 0; \ + for (regno = 0; regno < 16; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + mask |= 1 << (15 - regno); \ + if (frame_pointer_needed) \ + mask &= ~ (1 << (15-FRAME_POINTER_REGNUM)); \ + if (exact_log2 (mask) >= 0) \ + fprintf (FILE, "\tmove.l %s,-(sp)\n", reg_names[15 - exact_log2 (mask)]); \ + else if (mask) fprintf (FILE, "\tmovem.l #0x%x,-(sp)\n", mask); } + +#define FUNCTION_PROFILER(FILE, LABEL_NO) \ + fprintf (FILE, "\tmove.l #LP%d,d0\n\tjsr mcount\n", (LABEL_NO)); + +#define FUNCTION_EPILOGUE(FILE, SIZE) \ +{ register int regno; \ + register int mask, fmask; \ + register int nregs; \ + int offset, foffset; \ + extern char call_used_regs[]; \ + extern int current_function_pops_args; \ + extern int current_function_args_size; \ + int fsize = ((SIZE) + 3) & -4; \ + int big = 0; \ + nregs = 0; fmask = 0; \ + for (regno = 16; regno < FIRST_PSEUDO_REGISTER; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + { nregs++; fmask |= 1 << (23 - regno); } \ + foffset = nregs * 12; \ + nregs = 0; mask = 0; \ + if (frame_pointer_needed) regs_ever_live[FRAME_POINTER_REGNUM] = 0; \ + for (regno = 0; regno < 16; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + { nregs++; mask |= 1 << regno; } \ + offset = foffset + nregs * 4; \ + if (offset + fsize >= 0x8000 \ + && frame_pointer_needed \ + && (mask || fmask)) \ + { fprintf (FILE, "\tmove.l #%d,a0\n", -fsize); \ + fsize = 0, big = 1; } \ + if (exact_log2 (mask) >= 0) { \ + if (big) \ + fprintf (FILE, "\tmove.l (-%d,fp,a0.l),%s\n", \ + offset + fsize, reg_names[exact_log2 (mask)]); \ + else if (! frame_pointer_needed) \ + fprintf (FILE, "\tmove.l (sp)+,%s\n", \ + reg_names[exact_log2 (mask)]); \ + else \ + fprintf (FILE, "\tmove.l (-%d,fp),%s\n", \ + offset + fsize, reg_names[exact_log2 (mask)]); } \ + else if (mask) { \ + if (big) \ + fprintf (FILE, "\tmovem.l (-%d,fp,a0.l),#0x%x\n", \ + offset + fsize, mask); \ + else if (! frame_pointer_needed) \ + fprintf (FILE, "\tmovem.l (sp)+,#0x%x\n", mask); \ + else \ + fprintf (FILE, "\tmovem.l (-%d,fp),#0x%x\n", \ + offset + fsize, mask); } \ + if (fmask) { \ + if (big) \ + fprintf (FILE, "\tfmovem.x (-%d,fp,a0.l),#0x%x\n", \ + foffset + fsize, fmask); \ + else if (! frame_pointer_needed) \ + fprintf (FILE, "\tfmovem.x (sp)+,#0x%x\n", fmask); \ + else \ + fprintf (FILE, "\tfmovem.x (-%d,fp),#0x%x\n", \ + foffset + fsize, fmask); } \ + if (frame_pointer_needed) \ + fprintf (FILE, "\tunlk fp\n"); \ + if (current_function_pops_args && current_function_args_size) \ + fprintf (FILE, "\trtd #%d\n", current_function_args_size); \ + else fprintf (FILE, "\trts\n"); } + +/* Difference from tm-m68k.h is in `fp' instead of `a6'. */ + +#define REGISTER_NAMES \ +{"d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", \ + "a0", "a1", "a2", "a3", "a4", "a5", "fp", "sp", \ + "fp0", "fp1", "fp2", "fp3", "fp4", "fp5", "fp6", "fp7"} + +/* This is how to output an insn to push a register on the stack. + It need not be very fast code. */ + +#define ASM_OUTPUT_REG_PUSH(FILE,REGNO) \ + fprintf (FILE, "\tmove.l %s,-(sp)\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, "\tmove.l (sp)+,%s\n", reg_names[REGNO]) + +#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \ + fprintf (FILE, "\t.double 0d%.20e\n", (VALUE)) + +#define ASM_OUTPUT_SKIP(FILE,SIZE) \ + fprintf (FILE, "\t.space %u\n", (SIZE)) + +/* 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)) + 13), \ + sprintf ((OUTPUT), "%s$$$%d", (NAME), (LABELNO))) + +#define PRINT_OPERAND(FILE, X, CODE) \ +{ if (CODE == '.') fprintf (FILE, "."); \ + else if (CODE == '#') fprintf (FILE, "#"); \ + else if (CODE == '-') fprintf (FILE, "-(sp)"); \ + else if (CODE == '+') fprintf (FILE, "(sp)+"); \ + else if (CODE == '@') fprintf (FILE, "(sp)"); \ + else if (CODE == '!') fprintf (FILE, "ccr"); \ + else if (GET_CODE (X) == REG) \ + fprintf (FILE, "%s", reg_names[REGNO (X)]); \ + else if (GET_CODE (X) == MEM) \ + output_address (XEXP (X, 0)); \ + else if (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) == SFmode) \ + { union { double d; int i[2]; } u; \ + union { float f; int i; } u1; \ + u.i[0] = CONST_DOUBLE_LOW (X); u.i[1] = CONST_DOUBLE_HIGH (X); \ + u1.f = u.d; \ + if (CODE == 'f') \ + fprintf (FILE, "#0f%.9e", u1.f); \ + else \ + fprintf (FILE, "#0x%x", u1.i); } \ + else if (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) != DImode) \ + { union { double d; int i[2]; } u; \ + u.i[0] = CONST_DOUBLE_LOW (X); u.i[1] = CONST_DOUBLE_HIGH (X); \ + fprintf (FILE, "#0d%.20e", u.d); } \ + else if (CODE == 'b') output_addr_const (FILE, X); \ + else { putc ('#', FILE); output_addr_const (FILE, X); }} + +#define PRINT_OPERAND_ADDRESS(FILE, ADDR) \ +{ register rtx reg1, reg2, breg, ireg; \ + register rtx addr = ADDR; \ + rtx offset; \ + switch (GET_CODE (addr)) \ + { \ + case REG: \ + fprintf (FILE, "(%s)", reg_names[REGNO (addr)]); \ + break; \ + case PRE_DEC: \ + fprintf (FILE, "-(%s)", reg_names[REGNO (XEXP (addr, 0))]); \ + break; \ + case POST_INC: \ + fprintf (FILE, "(%s)+", reg_names[REGNO (XEXP (addr, 0))]); \ + break; \ + case PLUS: \ + reg1 = 0; reg2 = 0; \ + ireg = 0; breg = 0; \ + offset = 0; \ + if (CONSTANT_ADDRESS_P (XEXP (addr, 0))) \ + { \ + offset = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (CONSTANT_ADDRESS_P (XEXP (addr, 1))) \ + { \ + offset = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + if (GET_CODE (addr) != PLUS) ; \ + else if (GET_CODE (XEXP (addr, 0)) == SIGN_EXTEND) \ + { \ + reg1 = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (GET_CODE (XEXP (addr, 1)) == SIGN_EXTEND) \ + { \ + reg1 = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + else if (GET_CODE (XEXP (addr, 0)) == MULT) \ + { \ + reg1 = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (GET_CODE (XEXP (addr, 1)) == MULT) \ + { \ + reg1 = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + else if (GET_CODE (XEXP (addr, 0)) == REG) \ + { \ + reg1 = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (GET_CODE (XEXP (addr, 1)) == REG) \ + { \ + reg1 = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + if (GET_CODE (addr) == REG || GET_CODE (addr) == MULT \ + || GET_CODE (addr) == SIGN_EXTEND) \ + { if (reg1 == 0) reg1 = addr; else reg2 = addr; addr = 0; } \ + if (offset != 0) { if (addr != 0) abort (); addr = offset; } \ + if ((reg1 && (GET_CODE (reg1) == SIGN_EXTEND \ + || GET_CODE (reg1) == MULT)) \ + || (reg2 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg2)))) \ + { breg = reg2; ireg = reg1; } \ + else if (reg1 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg1))) \ + { breg = reg1; ireg = reg2; } \ + if (ireg != 0 && breg == 0 && GET_CODE (addr) == LABEL_REF) \ + { int scale = 1; \ + if (GET_CODE (ireg) == MULT) \ + { scale = INTVAL (XEXP (ireg, 1)); \ + ireg = XEXP (ireg, 0); } \ + if (GET_CODE (ireg) == SIGN_EXTEND) \ + fprintf (FILE, "(L%d.b,pc,%s.w", \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + reg_names[REGNO (XEXP (ireg, 0))]); \ + else \ + fprintf (FILE, "(L%d.b,pc,%s.l", \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + reg_names[REGNO (ireg)]); \ + if (scale != 1) fprintf (FILE, "*%d", scale); \ + putc (')', FILE); \ + break; } \ + if (breg != 0 && ireg == 0 && GET_CODE (addr) == LABEL_REF) \ + { fprintf (FILE, "(L%d.b,pc,%s.l", \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + reg_names[REGNO (breg)]); \ + putc (')', FILE); \ + break; } \ + if (ireg != 0 || breg != 0) \ + { int scale = 1; \ + if (breg == 0) \ + abort (); \ + if (addr && GET_CODE (addr) == LABEL_REF) abort (); \ + fprintf (FILE, "("); \ + if (addr != 0) { \ + output_addr_const (FILE, addr); \ + putc (',', FILE); } \ + fprintf (FILE, "%s", reg_names[REGNO (breg)]); \ + if (ireg != 0) \ + putc (',', FILE); \ + if (ireg != 0 && GET_CODE (ireg) == MULT) \ + { scale = INTVAL (XEXP (ireg, 1)); \ + ireg = XEXP (ireg, 0); } \ + if (ireg != 0 && GET_CODE (ireg) == SIGN_EXTEND) \ + fprintf (FILE, "%s.w", reg_names[REGNO (XEXP (ireg, 0))]); \ + else if (ireg != 0) \ + fprintf (FILE, "%s.l", reg_names[REGNO (ireg)]); \ + if (scale != 1) fprintf (FILE, "*%d", scale); \ + putc (')', FILE); \ + break; \ + } \ + else if (reg1 != 0 && GET_CODE (addr) == LABEL_REF) \ + { fprintf (FILE, "(L%d.b,pc,%s.l)", \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + reg_names[REGNO (reg1)]); \ + break; } \ + default: \ + if (GET_CODE (addr) == CONST_INT \ + && INTVAL (addr) < 0x8000 \ + && INTVAL (addr) >= -0x8000) \ + fprintf (FILE, "%d.w", INTVAL (addr)); \ + else \ + output_addr_const (FILE, addr); \ + }} + +#else /* Using GAS, which uses the MIT assembler syntax, like a Sun. */ + +#define FUNCTION_PROFILER(FILE, LABEL_NO) \ + fprintf (FILE, "\tmovl #LP%d,d0\n\tjsr mcount\n", (LABEL_NO)); + +#endif /* MOTOROLA */ diff --git a/gcc-1.40/config/tm-newsgas.h b/gcc-1.40/config/tm-newsgas.h new file mode 100644 index 0000000..ac36e6b --- /dev/null +++ b/gcc-1.40/config/tm-newsgas.h @@ -0,0 +1,7 @@ +/* In Sony versions before 3.0, use the GNU Assembler, because the + system's assembler has no way to assemble the difference of two + labels for the displacement in a switch-dispatch instruction. */ + +#define USE_GAS + +#include "tm-news.h" diff --git a/gcc-1.40/config/tm-next.h b/gcc-1.40/config/tm-next.h new file mode 100644 index 0000000..4292b27 --- /dev/null +++ b/gcc-1.40/config/tm-next.h @@ -0,0 +1,98 @@ +/* tm-next.h: Definitions for Next as target machine for GNU C compiler. */ + +#include "tm-m68k.h" + +/* Enable recent gcc to compile under the old gcc in Next release 1.0. */ +#define __inline inline + +/* See tm-m68k.h. 7 means 68020/030 with 68881/882. */ + +#define TARGET_DEFAULT 7 + +/* These compiler options take an argument. */ + +#define WORD_SWITCH_TAKES_ARG(STR) \ + (!strcmp (STR, "Ttext") || !strcmp (STR, "Tdata")) + +/* Names to predefine in the preprocessor for this target machine. */ + +#define CPP_PREDEFINES "-Dmc68000 -DNeXT -Dunix -D__MACH__" + +/* Machine dependent ccp options. */ + +#define CPP_SPEC "%{bsd:-D__STRICT_BSD__}" + +/* Machine dependent ld options. */ + +#define LINK_SPEC "%{Z} %{M} %{Mach} %{segcreate*} %{seglinkedit}" + +/* Machine dependent libraries. */ + +#define LIB_SPEC "%{!p:%{!pg:-lsys_s}} %{pg:-lsys_p}" + +/* We specify crt0.o as -lcrt0.o so that ld will search the library path. */ +#define STARTFILE_SPEC \ + "%{pg:-lgcrt0.o}%{!pg: \ + %{p:%e-p profiling is no longer supported. Use -pg instead.} \ + %{!p:-lcrt0.o}}" + +/* Every structure or union's size must be a multiple of 2 bytes. */ + +#define STRUCTURE_SIZE_BOUNDARY 16 + +/* We want C++ style comments to be supported for Objective-C */ + +#define CPLUSPLUS + +/* Why not? */ + +#define DOLLARS_IN_IDENTIFIERS 1 + +#if 0 /* These pertain to code changes that are not present in 1.36. */ + +/* Allow Mach -MD and -MMD make depend switches. */ + +#define MACH_MAKE_DEPEND + +/* These options take an argument. Note that we don't support -Ttext or -Tdata. */ + +#define WORD_SWITCH_TAKES_ARG(STR) (!strcmp (STR, "MD") || !strcmp (STR, +"MMD")) + +#endif /* 0 */ + +/* Allow #sscs (but don't do anything). */ + +#define SCCS_DIRECTIVE + +/* We use Dbx symbol format. */ + +#define DBX_DEBUGGING_INFO + +/* This is how to output an assembler line defining a `double' constant. */ + +#undef ASM_OUTPUT_DOUBLE +#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \ + (isinf ((VALUE)) \ + ? fprintf (FILE, "\t.double 0r%s99e999\n", ((VALUE) > 0 ? "" : "-")) \ + : fprintf (FILE, "\t.double 0r%.20e\n", (VALUE))) + +/* This is how to output an assembler line defining a `float' constant. */ + +#undef ASM_OUTPUT_FLOAT +#define ASM_OUTPUT_FLOAT(FILE,VALUE) \ + (isinf ((VALUE)) \ + ? fprintf (FILE, "\t.single 0r%s99e999\n", ((VALUE) > 0 ? "" : "-")) \ + : fprintf (FILE, "\t.single 0r%.20e\n", (VALUE))) + +#undef ASM_OUTPUT_FLOAT_OPERAND +#define ASM_OUTPUT_FLOAT_OPERAND(FILE,VALUE) \ + (isinf ((VALUE)) \ + ? fprintf (FILE, "#0r%s99e999", ((VALUE) > 0 ? "" : "-")) \ + : fprintf (FILE, "#0r%.9g", (VALUE))) + +#undef ASM_OUTPUT_DOUBLE_OPERAND +#define ASM_OUTPUT_DOUBLE_OPERAND(FILE,VALUE) \ + (isinf ((VALUE)) \ + ? fprintf (FILE, "#0r%s99e999", ((VALUE) > 0 ? "" : "-")) \ + : fprintf (FILE, "#0r%.20g", (VALUE))) diff --git a/gcc-1.40/config/tm-ns32k.h b/gcc-1.40/config/tm-ns32k.h new file mode 100644 index 0000000..16cb7b4 --- /dev/null +++ b/gcc-1.40/config/tm-ns32k.h @@ -0,0 +1,1457 @@ +/* Definitions of target machine for GNU compiler. NS32000 version. + Copyright (C) 1988 Free Software Foundation, Inc. + Contributed by Michael Tiemann (tiemann@mcc.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 1, 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. */ + + +/* Note that some other tm- files include this one and then override + many of the definitions that relate to assembler syntax. */ + + +/* Names to predefine in the preprocessor for this target machine. */ + +#define CPP_PREDEFINES "-Dns32000 -Dunix" + +/* Print subsidiary information on the compiler version in use. */ +#define TARGET_VERSION fprintf (stderr, " (32000, National syntax)"); + +/* Run-time compilation parameters selecting different hardware subsets. */ + +extern int target_flags; + +/* Macros used in the machine description to test the flags. */ + +/* Compile 32081 insns for floating point (not library calls). */ +#define TARGET_32081 (target_flags & 1) +/* Compile using rtd insn calling sequence. + This will not work unless you use prototypes at least + for all functions that can take varying numbers of args. */ +#define TARGET_RTD (target_flags & 2) +/* Compile passing first two args in regs 0 and 1. */ +#define TARGET_REGPARM (target_flags & 4) + +/* 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 \ + { { "32081", 1}, \ + { "soft-float", -1}, \ + { "rtd", 2}, \ + { "nortd", -2}, \ + { "regparm", 4}, \ + { "noregparm", -4}, \ + { "", TARGET_DEFAULT}} + +/* target machine storage layout */ + +/* Define this if most significant bit is lowest numbered + in instructions that operate on numbered bit-fields. + This is not true on the ns32k. */ +/* #define BITS_BIG_ENDIAN */ + +/* Define this if most significant byte of a word is the lowest numbered. */ +/* That is not true on the ns32k. */ +/* #define BYTES_BIG_ENDIAN */ + +/* Define this if most significant word of a multiword number is numbered. */ +/* This is not true on the ns32k. */ +/* #define WORDS_BIG_ENDIAN */ + +/* Number of bits in an addressible 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 32000, this would still be 32. + But on a machine with 16-bit registers, this would be 16. */ +#define BITS_PER_WORD 32 + +/* Width of a word, in units (bytes). */ +#define UNITS_PER_WORD 4 + +/* Width in bits of a pointer. + See also the macro `Pmode' defined below. */ +#define POINTER_SIZE 32 + +/* Allocation boundary (in *bits*) for storing pointers in memory. */ +#define POINTER_BOUNDARY 16 + +/* Allocation boundary (in *bits*) for storing arguments in argument list. */ +#define PARM_BOUNDARY 32 + +/* Boundary (in *bits*) on which stack pointer should be aligned. */ +#define STACK_BOUNDARY 32 + +/* Allocation boundary (in *bits*) for the code of a function. */ +#define FUNCTION_BOUNDARY 16 + +/* Alignment of field after `int : 0' in a structure. */ +#define EMPTY_FIELD_BOUNDARY 32 + +/* Every structure's size must be a multiple of this. */ +#define STRUCTURE_SIZE_BOUNDARY 8 + +/* No data type wants to be aligned rounder than this. */ +#define BIGGEST_ALIGNMENT 32 + +/* Define this if move instructions will actually fail to work + when given unaligned data. National claims that the NS32032 + works without strict alignment, but rumor has it that operands + crossing a page boundary cause unpredictable results. */ +#define STRICT_ALIGNMENT + +/* 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. */ +#define FIRST_PSEUDO_REGISTER 18 + +/* 1 for registers that have pervasive standard uses + and are not available for the register allocator. + On the ns32k, these are the FP, SP, (SB and PC are not included here). */ +#define FIXED_REGISTERS {0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + 1, 1} + +/* 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, 0, 0, 0, 0, 0, \ + 1, 1, 1, 1, 0, 0, 0, 0, \ + 1, 1} + +/* 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 the ns32k, all registers are 32 bits long. */ +#define HARD_REGNO_NREGS(REGNO, MODE) \ + ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD) + +/* Value is 1 if hard register REGNO can hold a value of machine-mode MODE. + On the 32000, all registers can hold all modes, except that + double precision floats (and double ints) must fall on even-register + boundaries */ +#define HARD_REGNO_MODE_OK(REGNO, MODE) \ + ((MODE) == DFmode \ + ? (((REGNO) & 1) == 0 \ + && (TARGET_32081 ? (REGNO) < 16 : (REGNO) < 8)) \ + : (MODE) == DImode ? ((REGNO) & 1) == 0 && (REGNO) < 8 \ + : 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) == DFmode || (MODE1) == DImode) == ((MODE2) == DFmode || (MODE2) == DImode)) + +/* Specify the registers used for certain standard purposes. + The values of these macros are register numbers. */ + +/* NS32000 pc is not overloaded on a register. */ +/* #define PC_REGNUM */ + +/* Register to use for pushing function arguments. */ +#define STACK_POINTER_REGNUM 17 + +/* Base register for access to local variables of the function. */ +#define FRAME_POINTER_REGNUM 16 + +/* 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. */ +#define FRAME_POINTER_REQUIRED 0 + +/* Base register for access to arguments of the function. */ +#define ARG_POINTER_REGNUM 16 + +/* Register in which static-chain is passed to a function. */ +#define STATIC_CHAIN_REGNUM 1 + +/* Register in which address to store a structure value + is passed to a function. */ +#define STRUCT_VALUE_REGNUM 2 + +/* 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. */ + +enum reg_class { NO_REGS, GENERAL_REGS, FLOAT_REGS, GEN_AND_FLOAT_REGS, + GEN_AND_MEM_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", "GENERAL_REGS", "FLOAT_REGS", "GEN_AND_FLOAT_REGS", "GEN_AND_MEM_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, 0x00ff, 0xff00, 0xffff, 0x300ff, 0x3ffff, } + +/* 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. */ + +#define REGNO_REG_CLASS(REGNO) \ + ((REGNO) < 8 ? GENERAL_REGS : (REGNO) < 16 ? FLOAT_REGS : ALL_REGS) + +/* The class value for index registers, and the one for base regs. */ + +#define INDEX_REG_CLASS GENERAL_REGS +#define BASE_REG_CLASS GEN_AND_MEM_REGS + +/* Get reg_class from a letter such as appears in the machine description. */ + +#define REG_CLASS_FROM_LETTER(C) \ + ((C) == 'r' ? GENERAL_REGS \ + : (C) == 'f' ? FLOAT_REGS \ + : (C) == 'x' ? GEN_AND_MEM_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. + + On the ns32k, these letters are used as follows: + + I : Matches integers which are valid shift amounts for scaled indexing. + These are 0, 1, 2, 3 for byte, word, double, and quadword. + J : Matches integers which fit a "quick" operand. + K : Matches integers 0 to 7 (for inss and exts instructions). */ + +#define CONST_OK_FOR_LETTER_P(VALUE, C) \ + ((VALUE) < 8 && (VALUE) + 8 >= 0 ? \ + ((C) == 'I' ? (0 <= (VALUE) && (VALUE) <= 3) : \ + (C) == 'J' ? (VALUE) <= 7 : \ + (C) == 'K' ? 0 <= (VALUE) : 0) : 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) 1 + +/* 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. */ + +#define PREFERRED_RELOAD_CLASS(X,CLASS) (CLASS) + +/* Return the maximum number of consecutive registers + needed to represent mode MODE in a register of class CLASS. */ +/* On the 32000, this is the size of MODE in words */ +#define CLASS_MAX_NREGS(CLASS, MODE) \ + ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD) + +/* Stack layout; function entry, exit and calling. */ + +/* 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. */ +#define STARTING_FRAME_OFFSET 0 + +/* If we generate an insn to push BYTES bytes, + this says how many the stack pointer really advances by. + On the 32000, sp@- in a byte insn really pushes a BYTE. */ +#define PUSH_ROUNDING(BYTES) (BYTES) + +/* Offset of first parameter from the argument pointer register value. */ +#define FIRST_PARM_OFFSET(FNDECL) 8 + +/* Value is 1 if returning from a function call automatically + pops the arguments described by the number-of-args field in the call. + 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. + + On the 32000, the RET insn may be used to pop them if the number + of args is fixed, but if the number is variable then the caller + must pop them all. RET can't be used for library calls now + because the library is compiled with the Unix compiler. + Use of RET is a selectable option, since it is incompatible with + standard Unix calling sequences. If the option is not selected, + the caller must always pop the args. */ + +#define RETURN_POPS_ARGS(FUNTYPE) \ + (TARGET_RTD && TREE_CODE (FUNTYPE) != IDENTIFIER_NODE \ + && (TYPE_ARG_TYPES (FUNTYPE) == 0 \ + || TREE_VALUE (tree_last (TYPE_ARG_TYPES (FUNTYPE))) == void_type_node)) + +/* 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 the 32000 the return value is in R0, + or perhaps in F0 is there is fp support. */ + +#define FUNCTION_VALUE(VALTYPE, FUNC) \ + (TREE_CODE (VALTYPE) == REAL_TYPE && TARGET_32081 \ + ? gen_rtx (REG, TYPE_MODE (VALTYPE), 8) \ + : gen_rtx (REG, TYPE_MODE (VALTYPE), 0)) + +/* Define how to find the value returned by a library function + assuming the value has mode MODE. */ + +/* On the 32000 the return value is in R0, + or perhaps F0 is there is fp support. */ + +#define LIBCALL_VALUE(MODE) \ + (((MODE) == DFmode || (MODE) == SFmode) && TARGET_32081 \ + ? gen_rtx (REG, MODE, 8) \ + : gen_rtx (REG, MODE, 0)) + +/* Define this if PCC uses the nonreentrant convention for returning + structure and union values. */ + +#define PCC_STATIC_STRUCT_RETURN + +/* 1 if N is a possible register number for a function value. + On the 32000, R0 and F0 are the only registers thus used. */ + +#define FUNCTION_VALUE_REGNO_P(N) (((N) & ~8) == 0) + +/* 1 if N is a possible register number for function argument passing. + On the 32000, no registers are used in this way. */ + +#define FUNCTION_ARG_REGNO_P(N) 0 + +/* 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 the ns32k, this is a single integer, which is a number of bytes + of arguments scanned so far. */ + +#define CUMULATIVE_ARGS int + +/* 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. + + On the ns32k, the offset starts at 0. */ + +#define INIT_CUMULATIVE_ARGS(CUM,FNTYPE) \ + ((CUM) = 0) + +/* 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.) */ + +#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \ + ((CUM) += ((MODE) != BLKmode \ + ? (GET_MODE_SIZE (MODE) + 3) & ~3 \ + : (int_size_in_bytes (TYPE) + 3) & ~3)) + +/* Define where to put the arguments 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). */ + +/* On the 32000 all args are pushed, except if -mregparm is specified + then the first two words of arguments are passed in r0, r1. + *NOTE* -mregparm does not work. + It exists only to test register calling conventions. */ + +#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \ +((TARGET_REGPARM && (CUM) < 8) ? gen_rtx (REG, (MODE), (CUM) / 4) : 0) + +/* 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. */ + +#define FUNCTION_ARG_PARTIAL_NREGS(CUM, MODE, TYPE, NAMED) \ +((TARGET_REGPARM && (CUM) < 8 \ + && 8 < ((CUM) + ((MODE) == BLKmode \ + ? int_size_in_bytes (TYPE) \ + : GET_MODE_SIZE (MODE)))) \ + ? 2 - (CUM) / 4 : 0) + +#ifndef MAIN_FUNCTION_PROLOGUE +#define MAIN_FUNCTION_PROLOGUE +#endif + +/* 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. */ + +#define FUNCTION_PROLOGUE(FILE, SIZE) \ +{ register int regno; \ + int used_regs_buf[8], *bufp = used_regs_buf; \ + int used_fregs_buf[8], *fbufp = used_fregs_buf; \ + extern char call_used_regs[]; \ + MAIN_FUNCTION_PROLOGUE; \ + for (regno = 0; regno < 8; regno++) \ + if (regs_ever_live[regno] && !call_used_regs[regno]) { \ + *bufp++ = regno; \ + } \ + *bufp = -1; \ + for (; regno < 16; regno++) \ + if (regs_ever_live[regno] && !call_used_regs[regno]) { \ + *fbufp++ = regno; \ + } \ + *fbufp = -1; \ + bufp = used_regs_buf; \ + if (frame_pointer_needed) \ + { \ + fprintf (FILE, "\tenter ["); \ + while (*bufp >= 0) \ + { \ + fprintf (FILE, "r%d", *bufp++); \ + if (*bufp >= 0) \ + fputc (',', FILE); \ + } \ + fprintf (FILE, "],%d\n", SIZE); \ + } \ + else while (*bufp >= 0) \ + fprintf (FILE, "\tmovd r%d,tos\n", *bufp++); \ + fbufp = used_fregs_buf; \ + while (*fbufp >= 0) \ + { \ + if ((*fbufp & 1) || (fbufp[0] != fbufp[1] - 1)) \ + fprintf (FILE, "\tmovf f%d,tos\n", *fbufp++ - 8); \ + else \ + { \ + fprintf (FILE, "\tmovl f%d,tos\n", fbufp[0] - 8); \ + fbufp += 2; \ + } \ + } \ +} + +/* Output assembler code to FILE to increment profiler label # LABELNO + for profiling a function entry. + + THIS DEFINITION FOR THE 32000 IS A GUESS. IT HAS NOT BEEN TESTED. */ + +#define FUNCTION_PROFILER(FILE, LABELNO) \ + fprintf (FILE, "\taddr LP%d,r0\n\tbsr mcount\n", (LABELNO)) + +/* 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. */ + +/* #define EXIT_IGNORE_STACK */ + +/* 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) \ +{ extern int current_function_pops_args; \ + extern int current_function_args_size; \ + register int regno; \ + int used_regs_buf[8], *bufp = used_regs_buf; \ + int used_fregs_buf[8], *fbufp = used_fregs_buf; \ + extern char call_used_regs[]; \ + *fbufp++ = -2; \ + for (regno = 8; regno < 16; regno++) \ + if (regs_ever_live[regno] && !call_used_regs[regno]) { \ + *fbufp++ = regno; \ + } \ + fbufp--; \ + while (fbufp > used_fregs_buf) \ + { \ + if ((*fbufp & 1) && fbufp[0] == fbufp[-1] + 1) \ + { \ + fprintf (FILE, "\tmovl tos,f%d\n", fbufp[-1] - 8); \ + fbufp -= 2; \ + } \ + else fprintf (FILE, "\tmovf tos,f%d\n", *fbufp-- - 8); \ + } \ + for (regno = 0; regno < 8; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + *bufp++ = regno; \ + if (frame_pointer_needed) \ + { \ + fprintf (FILE, "\texit ["); \ + while (bufp > used_regs_buf) \ + { \ + fprintf (FILE, "r%d", *--bufp); \ + if (bufp > used_regs_buf) \ + fputc (',', FILE); \ + } \ + fprintf (FILE, "]\n"); \ + } \ + else \ + { \ + while (bufp > used_regs_buf) \ + fprintf (FILE, "\tmovd tos,r%d\n", *--bufp); \ + } \ + if (current_function_pops_args && current_function_args_size) \ + fprintf (FILE, "\tret %d\n", current_function_args_size); \ + else fprintf (FILE, "\tret 0\n"); } + +/* If the memory address ADDR is relative to the frame pointer, + correct it to be relative to the stack pointer instead. + This is for when we don't use a frame pointer. + ADDR should be a variable name. */ + +#if 0 +#define FIX_FRAME_POINTER_ADDRESS(ADDR,DEPTH) \ +{ int offset = -1; \ + if (GET_CODE (ADDR) == REG && REGNO (ADDR) == FRAME_POINTER_REGNUM) \ + offset = 0; \ + else if (GET_CODE (ADDR) == PLUS && GET_CODE (XEXP (ADDR, 0)) == REG \ + && REGNO (XEXP (ADDR, 0)) == FRAME_POINTER_REGNUM \ + && GET_CODE (XEXP (ADDR, 1)) == CONST_INT) \ + offset = INTVAL (XEXP (ADDR, 1)); \ + if (offset >= 0) \ + { int regno; \ + extern char call_used_regs[]; \ + for (regno = 0; regno < 8; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + offset += 4; \ + offset -= 4; \ + ADDR = plus_constant (gen_rtx (REG, Pmode, STACK_POINTER_REGNUM), \ + offset + (DEPTH)); } } +#else +#define FIX_FRAME_POINTER_ADDRESS(ADDR,DEPTH) \ + if (check_reg(ADDR, FRAME_POINTER_REGNUM)) { \ + register int regno, offset = (DEPTH) - 4; \ + extern char call_used_regs[]; \ + for (regno = 0; regno < 16; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + offset += 4; \ + if (GET_CODE (ADDR) == REG && REGNO (ADDR) == FRAME_POINTER_REGNUM) \ + ADDR = plus_constant(stack_pointer_rtx, offset); \ + else if (GET_CODE(ADDR) == PLUS) { \ + register rtx a0 = XEXP(ADDR, 0); \ + if (GET_CODE(a0) == REG && REGNO(a0) == FRAME_POINTER_REGNUM) \ + if (GET_CODE(XEXP(ADDR, 1)) == CONST_INT) \ + ADDR = plus_constant(stack_pointer_rtx, \ + offset + INTVAL(XEXP(ADDR, 1))); \ + else \ + ADDR = plus_constant(gen_rtx(PLUS, Pmode, \ + stack_pointer_rtx, XEXP (ADDR, 1)), \ + offset); \ + else if (GET_CODE(a0) == MEM) { \ + register rtx a1 = XEXP(a0, 0); \ + if (GET_CODE(a1) == REG && REGNO(a1) == FRAME_POINTER_REGNUM) \ + ADDR = gen_rtx(PLUS, Pmode, \ + gen_rtx(MEM, Pmode, \ + plus_constant(stack_pointer_rtx, offset)), \ + XEXP(ADDR, 1)); \ + else if (GET_CODE(a1) == PLUS && GET_CODE(XEXP(a1, 0)) == REG \ + && REGNO(XEXP(a1, 0)) == FRAME_POINTER_REGNUM) \ + ADDR = gen_rtx(PLUS, Pmode, \ + gen_rtx(MEM, Pmode, \ + plus_constant(stack_pointer_rtx, \ + offset+INTVAL(XEXP(a1, 1)))),\ + XEXP(ADDR, 1)); \ + else \ + abort(); \ + } else if (GET_CODE(XEXP(ADDR, 1)) == MEM) { \ + register rtx a1 = XEXP(XEXP(ADDR, 1), 0); \ + if (GET_CODE(a1) == REG && REGNO(a1) == FRAME_POINTER_REGNUM) \ + ADDR = gen_rtx(PLUS, Pmode, \ + XEXP(ADDR, 0), \ + gen_rtx(MEM, Pmode, \ + plus_constant(stack_pointer_rtx, \ + offset))); \ + else if (GET_CODE(a1) == PLUS && GET_CODE(XEXP(a1, 0)) == REG \ + && REGNO(XEXP(a1, 0)) == FRAME_POINTER_REGNUM) \ + ADDR = gen_rtx(PLUS, Pmode, \ + XEXP(ADDR, 0), \ + gen_rtx(MEM, Pmode, \ + plus_constant(stack_pointer_rtx, \ + offset+INTVAL(XEXP(a1, 1)))));\ + else \ + abort(); \ + } else \ + abort(); \ + } else if (GET_CODE(ADDR) == MEM) { \ + register rtx a0 = XEXP(ADDR, 0); \ + if (GET_CODE (a0) == REG && REGNO (a0) == FRAME_POINTER_REGNUM) \ + ADDR = gen_rtx(MEM, Pmode, \ + plus_constant(stack_pointer_rtx, offset)); \ + else if (GET_CODE(a0) == PLUS && GET_CODE(XEXP(a0, 0)) == REG \ + && REGNO(XEXP(a0, 0)) == FRAME_POINTER_REGNUM \ + && GET_CODE(XEXP(a0, 1)) == CONST_INT) \ + ADDR = gen_rtx(MEM, Pmode, \ + plus_constant(stack_pointer_rtx, \ + offset + INTVAL(XEXP(a0, 1)))); \ + else \ + abort(); \ + } else \ + abort(); \ + } +#endif + +/* 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. */ + +/* note that FP and SP cannot be used as an index. What about PC? */ +#define REGNO_OK_FOR_INDEX_P(REGNO) \ +((REGNO) < 8 || (unsigned)reg_renumber[REGNO] < 8) +#define REGNO_OK_FOR_BASE_P(REGNO) \ +((REGNO) < 8 || (unsigned)reg_renumber[REGNO] < 8 \ + || (REGNO) == FRAME_POINTER_REGNUM || (REGNO) == STACK_POINTER_REGNUM) + +/* 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. */ + +#define CONSTANT_ADDRESS_P(X) \ + (GET_CODE (X) == LABEL_REF || GET_CODE (X) == SYMBOL_REF \ + || GET_CODE (X) == CONST \ + || (GET_CODE (X) == CONST_INT \ + && ((unsigned)INTVAL (X) >= 0xe0000000 \ + || (unsigned)INTVAL (X) < 0x20000000))) + +#define CONSTANT_ADDRESS_NO_LABEL_P(X) \ + (GET_CODE (X) == CONST_INT \ + && ((unsigned)INTVAL (X) >= 0xe0000000 \ + || (unsigned)INTVAL (X) < 0x20000000)) + +/* Nonzero if the constant value X is a legitimate general operand. + It is given that X satisfies CONSTANT_P or is a CONST_DOUBLE. */ + +#define LEGITIMATE_CONSTANT_P(X) 1 + +/* 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. */ + +#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) \ + (REGNO (X) < 8 || REGNO (X) >= FIRST_PSEUDO_REGISTER) +/* Nonzero if X is a hard reg that can be used as a base reg + of if it is a pseudo reg. */ +#define REG_OK_FOR_BASE_P(X) (REGNO (X) < 8 || REGNO (X) >= FRAME_POINTER_REGNUM) +/* Nonzero if X is a floating point reg or a pseudo reg. */ + +#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)) + +#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. + + The other macros defined here are used only in GO_IF_LEGITIMATE_ADDRESS. */ + +/* 1 if X is an address that we could indirect through. */ +/***** NOTE ***** There is a bug in the Sequent assembler which fails + to fixup addressing information for symbols used as offsets + from registers which are not FP or SP (or SB or PC). This + makes _x(fp) valid, while _x(r0) is invalid. */ + +#define INDIRECTABLE_1_ADDRESS_P(X) \ + (CONSTANT_P (X) \ + || (GET_CODE (X) == REG && REG_OK_FOR_BASE_P (X)) \ + || (GET_CODE (X) == PLUS \ + && GET_CODE (XEXP (X, 0)) == REG \ + && REG_OK_FOR_BASE_P (XEXP (X, 0)) \ + && CONSTANT_ADDRESS_P (XEXP (X, 1)))) + +#define MEM_REG(X) \ + ((GET_CODE (X) == REG && (REGNO (X) ^ 16) < 2) \ + || (GET_CODE (X) == SYMBOL_REF)) + +#define INDIRECTABLE_2_ADDRESS_P(X) \ + (GET_CODE (X) == MEM \ + && (((xfoo0 = XEXP (X, 0), MEM_REG (xfoo0)) \ + || (GET_CODE (xfoo0) == PLUS \ + && GET_CODE (XEXP (xfoo0, 0)) == REG \ + && MEM_REG (XEXP (xfoo0, 0)) \ + && CONSTANT_ADDRESS_NO_LABEL_P (XEXP (xfoo0, 1)))) \ + || CONSTANT_ADDRESS_P (xfoo0))) + +#define INDIRECTABLE_ADDRESS_P(X) \ + (INDIRECTABLE_1_ADDRESS_P(X) \ + || INDIRECTABLE_2_ADDRESS_P (X) \ + || (GET_CODE (X) == PLUS \ + && CONSTANT_ADDRESS_NO_LABEL_P (XEXP (X, 1)) \ + && INDIRECTABLE_2_ADDRESS_P (XEXP (X, 0)))) + +/* Go to ADDR if X is a valid address not using indexing. + (This much is the easy part.) */ +#define GO_IF_NONINDEXED_ADDRESS(X, ADDR) \ +{ register rtx xfoob = (X); \ + if (GET_CODE (xfoob) == REG) goto ADDR; \ + if (INDIRECTABLE_1_ADDRESS_P(X)) goto ADDR; \ + if (INDIRECTABLE_2_ADDRESS_P (X)) goto ADDR; \ + if (GET_CODE (X) == PLUS) \ + if (CONSTANT_ADDRESS_NO_LABEL_P (XEXP (X, 1))) \ + if (INDIRECTABLE_2_ADDRESS_P (XEXP (X, 0))) \ + goto ADDR; \ +} + +/* 1 if PROD is either a reg times size of mode MODE + or just a reg, if MODE is just one byte. Actually, on the ns32k, + since the index mode is independent of the operand size, + we can match more stuff... + + This macro's expansion uses the temporary variables xfoo0, xfoo1 + and xfoo2 that must be declared in the surrounding context. */ +#define INDEX_TERM_P(PROD, MODE) \ +((GET_CODE (PROD) == REG && REG_OK_FOR_INDEX_P (PROD)) \ + || (GET_CODE (PROD) == MULT \ + && (xfoo0 = XEXP (PROD, 0), xfoo1 = XEXP (PROD, 1), \ + (GET_CODE (xfoo1) == CONST_INT \ + && GET_CODE (xfoo0) == REG \ + && FITS_INDEX_RANGE (INTVAL (xfoo1)) \ + && REG_OK_FOR_INDEX_P (xfoo0))))) + +#define FITS_INDEX_RANGE(X) \ + ((xfoo2 = (unsigned)(X)-1), \ + ((xfoo2 < 4 && xfoo2 != 2) || xfoo2 == 7)) + +#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \ +{ register rtx xfooy, xfooz, xfoo0, xfoo1; \ + unsigned xfoo2; \ + xfooy = X; \ + GO_IF_NONINDEXED_ADDRESS (xfooy, ADDR); \ + if (GET_CODE (xfooy) == PLUS) \ + { \ + if (GET_CODE (XEXP (xfooy, 1)) == CONST_INT \ + && GET_CODE (XEXP (xfooy, 0)) == PLUS) \ + xfooy = XEXP (xfooy, 0); \ + else if (GET_CODE (XEXP (xfooy, 0)) == CONST_INT \ + && GET_CODE (XEXP (xfooy, 1)) == PLUS) \ + xfooy = XEXP (xfooy, 1); \ + xfooz = XEXP (xfooy, 1); \ + if (INDEX_TERM_P (xfooz, MODE)) \ + { rtx t = XEXP (xfooy, 0); GO_IF_NONINDEXED_ADDRESS (t, ADDR); }\ + xfooz = XEXP (xfooy, 0); \ + if (INDEX_TERM_P (xfooz, MODE)) \ + { rtx t = XEXP (xfooy, 1); GO_IF_NONINDEXED_ADDRESS (t, ADDR); }\ + } \ + else if (INDEX_TERM_P (xfooy, MODE)) \ + goto ADDR; \ + else if (GET_CODE (xfooy) == PRE_DEC) \ + if (REGNO (XEXP (xfooy, 0)) == STACK_POINTER_REGNUM) goto ADDR; \ + else abort (); \ +} + +/* 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. + + For the ns32k, we do nothing */ + +#define LEGITIMIZE_ADDRESS(X,OLDX,MODE,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 ns32k, only predecrement and postincrement address depend thus + (the amount of decrement or increment being the length of the operand). */ + +#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR,LABEL) \ + { if (GET_CODE (ADDR) == POST_INC || GET_CODE (ADDR) == PRE_DEC) \ + goto LABEL;} + +/* Specify the machine mode that this machine uses + for the index in the tablejump instruction. + Can do SImode, but HI mode is more efficient. */ +#define CASE_VECTOR_MODE HImode + +/* 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 + +/* 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 4 + +/* Define this if zero-extension is slow (more than one real instruction). */ +/* #define SLOW_ZERO_EXTEND */ + +/* Nonzero if access to memory by bytes is slow and undesirable. */ +#define SLOW_BYTE_ACCESS 0 + +/* Define if shifts truncate the shift count + which implies one can omit a sign-extension or zero-extension + of a shift count. */ +/* #define SHIFT_COUNT_TRUNCATED */ + +/* 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 + +/* 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 + +/* 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 SImode + +/* 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 QImode + +/* 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) \ + case CONST_INT: \ + if (INTVAL (RTX) <= 7 && INTVAL (RTX) >= -8) return 0; \ + if (INTVAL (RTX) < 0x4000 && INTVAL (RTX) >= -0x4000) \ + return 1; \ + case CONST: \ + case LABEL_REF: \ + case SYMBOL_REF: \ + return 3; \ + case CONST_DOUBLE: \ + return 5; + +/* Tell final.c how to eliminate redundant test instructions. */ + +/* Here we define machine-dependent flags and fields in cc_status + (see `conditions.h'). */ + +/* This bit means that what ought to be in the Z bit + should be tested in the F bit. */ +#define CC_Z_IN_F 04000 + +/* This bit means that what ought to be in the Z bit + is complemented in the F bit. */ +#define CC_Z_IN_NOT_F 010000 + +/* Store in cc_status the expressions + that the condition codes will describe + after execution of an instruction whose pattern is EXP. + Do not alter them if the instruction would not alter the cc's. */ + +#define NOTICE_UPDATE_CC(EXP, INSN) \ +{ if (GET_CODE (EXP) == SET) \ + { if (GET_CODE (SET_DEST (EXP)) == CC0) \ + { cc_status.flags = 0; \ + cc_status.value1 = SET_DEST (EXP); \ + cc_status.value2 = SET_SRC (EXP); \ + } \ + else if (GET_CODE (SET_SRC (EXP)) == CALL) \ + { CC_STATUS_INIT; } \ + else if (GET_CODE (SET_DEST (EXP)) == REG) \ + { 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; \ + } \ + else if (GET_CODE (SET_DEST (EXP)) == MEM) \ + { CC_STATUS_INIT; } \ + } \ + else if (GET_CODE (EXP) == PARALLEL \ + && GET_CODE (XVECEXP (EXP, 0, 0)) == SET) \ + { if (GET_CODE (SET_DEST (XVECEXP (EXP, 0, 0))) == CC0) \ + { cc_status.flags = 0; \ + cc_status.value1 = SET_DEST (XVECEXP (EXP, 0, 0)); \ + cc_status.value2 = SET_SRC (XVECEXP (EXP, 0, 0)); \ + } \ + else if (GET_CODE (SET_DEST (XVECEXP (EXP, 0, 0))) == REG) \ + { if (cc_status.value1 \ + && reg_overlap_mentioned_p (SET_DEST (XVECEXP (EXP, 0, 0)), cc_status.value1)) \ + cc_status.value1 = 0; \ + if (cc_status.value2 \ + && reg_overlap_mentioned_p (SET_DEST (XVECEXP (EXP, 0, 0)), cc_status.value2)) \ + cc_status.value2 = 0; \ + } \ + else if (GET_CODE (SET_DEST (XVECEXP (EXP, 0, 0))) == MEM) \ + { CC_STATUS_INIT; } \ + } \ + else if (GET_CODE (EXP) == CALL) \ + { /* all bets are off */ CC_STATUS_INIT; } \ + else { /* nothing happens? CC_STATUS_INIT; */} \ + if (cc_status.value1 && GET_CODE (cc_status.value1) == REG \ + && cc_status.value2 \ + && reg_overlap_mentioned_p (cc_status.value1, cc_status.value2)) \ + printf ("here!\n", cc_status.value2 = 0); \ +} + +#define OUTPUT_JUMP(NORMAL, NO_OV) \ +{ if (cc_status.flags & CC_NO_OVERFLOW) \ + return NO_OV; \ + return NORMAL; } + +/* Control the assembler format that we output. */ + +/* Output at beginning of assembler file. */ + +#define ASM_FILE_START(FILE) fprintf (FILE, "#NO_APP\n"); + +/* Output to assembler file text saying following lines + may contain character constants, extra white space, comments, etc. */ + +#define ASM_APP_ON "#APP\n" + +/* Output to assembler file text saying following lines + no longer contain unusual constructs. */ + +#define ASM_APP_OFF "#NO_APP\n" + +/* 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 \ +{"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", \ + "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", \ + "fp", "sp"} + +/* How to renumber registers for dbx and gdb. + NS32000 may need more change in the numeration. */ + +#define DBX_REGISTER_NUMBER(REGNO) ((REGNO < 8) ? (REGNO)+4 : (REGNO)) + +/* 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 (".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. */ + +#define ASM_OUTPUT_LABELREF(FILE,NAME) \ + fprintf (FILE, "_%s", NAME) + +/* 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) \ + 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%d", PREFIX, NUM) + +/* This is how to align the code that follows an unconditional branch. */ + +#define ASM_OUTPUT_ALIGN_CODE(FILE) \ + fprintf (FILE, "\t.align 4\n") + +/* This is how to output an assembler line defining a `double' constant. */ + +#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \ + fprintf (FILE, "\t.double 0d%.20e\n", (VALUE)) + +/* This is how to output an assembler line defining a `float' constant. */ + +#define ASM_OUTPUT_FLOAT(FILE,VALUE) \ + fprintf (FILE, "\t.float 0f%.20e\n", (VALUE)) + +/* This is how to output an assembler line defining an `int' constant. */ + +#define ASM_OUTPUT_INT(FILE,VALUE) \ +( fprintf (FILE, "\t.long "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +/* Likewise for `char' and `short' constants. */ + +#define ASM_OUTPUT_SHORT(FILE,VALUE) \ +( fprintf (FILE, "\t.word "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +#define ASM_OUTPUT_CHAR(FILE,VALUE) \ +( fprintf (FILE, "\t.byte "), \ + 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.byte 0x%x\n", (VALUE)) + +/* This is how to output an insn to push a register on the stack. + It need not be very fast code. */ + +#define ASM_OUTPUT_REG_PUSH(FILE,REGNO) \ + fprintf (FILE, "\tmovd %s,tos\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, "\tmovd tos,%s\n", reg_names[REGNO]) + +/* 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.) */ + +#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \ + fprintf (FILE, "\t.long L%d\n", VALUE) + +/* This is how to output an element of a case-vector that is relative. */ +/* ** Notice that the second element is LI format! */ +#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, VALUE, REL) \ + fprintf (FILE, "\t.word L%d-LI%d\n", VALUE, REL) + +/* 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) \ + fprintf (FILE, "\t.align %d\n", (LOG)) + +#define ASM_OUTPUT_SKIP(FILE,SIZE) \ + fprintf (FILE, "\t.space %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 (".comm ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%u\n", (ROUNDED))) + +/* This says how to output an assembler line + to define a local common symbol. */ + +#define ASM_OUTPUT_LOCAL(FILE, NAME, SIZE, ROUNDED) \ +( fputs (".lcomm ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%u\n", (ROUNDED))) + +/* 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 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 + +/* Print an instruction operand X on file FILE. + CODE is the code from the %-spec that requested printing this operand; + if `%z3' was used to print operand 3, then CODE is 'z'. */ + +/* %$ means print the prefix for an immediate operand. */ + +#define PRINT_OPERAND_PUNCT_VALID_P(CODE) \ + ((CODE) == '$' || (CODE) == '?') + +#define PRINT_OPERAND(FILE, X, CODE) \ +{ if (CODE == '$') fprintf (FILE, "$"); \ + else if (CODE == '?'); \ + else if (GET_CODE (X) == REG) \ + fprintf (FILE, "%s", reg_names[REGNO (X)]); \ + else if (GET_CODE (X) == MEM) \ + output_address (XEXP (X, 0)); \ + else if (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) != DImode) \ + if (GET_MODE (X) == DFmode) \ + { union { double d; int i[2]; } u; \ + u.i[0] = CONST_DOUBLE_LOW (X); u.i[1] = CONST_DOUBLE_HIGH (X); \ + fprintf (FILE, "$0d%.20e", u.d); } \ + else \ + { union { double d; int i[2]; } u; \ + u.i[0] = CONST_DOUBLE_LOW (X); u.i[1] = CONST_DOUBLE_HIGH (X); \ + fprintf (FILE, "$0f%.20e", u.d); } \ + else { putc ('$', FILE); output_addr_const (FILE, X); }} + +/* Print a memory operand whose address is X, on file FILE. */ + +#define PRINT_OPERAND_ADDRESS(FILE, ADDR) \ +{ register rtx reg1, reg2, breg, ireg; \ + register rtx addr = ADDR; \ + rtx offset; \ + int mem=0, multval, offset_printed; \ + char reg1_str[256], reg2_str[256]; \ + retry: \ + switch (GET_CODE (addr)) \ + { \ + case MEM: \ + fprintf (FILE, "0("); \ + addr = XEXP (addr, 0); \ + mem =1; \ + goto retry; \ + case REG: \ + fprintf (FILE, "0(%s)", reg_names[REGNO (addr)]); \ + break; \ + case PRE_DEC: \ + if (REGNO(XEXP(addr, 0)) != STACK_POINTER_REGNUM) \ + fprintf(FILE, ")1:%d", REGNO(XEXP(addr,0))); \ + else fprintf (FILE, "tos", reg_names[REGNO (XEXP (addr, 0))]); \ + break; \ + case POST_INC: \ + if (REGNO(XEXP(addr, 0)) != STACK_POINTER_REGNUM) \ + fprintf(FILE, ")2:%d", REGNO(XEXP(addr,0))); \ + else fprintf (FILE, "tos", reg_names[REGNO (XEXP (addr, 0))]); \ + break; \ + case MULT: \ + reg1 = XEXP (addr, 0); /* [rX:Y] */ \ + reg2 = XEXP (addr, 1); /* CONST/REG */ \ + if (GET_CODE (reg1) == CONST_INT && GET_CODE(reg2) == REG) { \ + reg1 = reg2; \ + reg2 = XEXP (addr, 0); /* [rX:Y] */ \ + } else \ + if (GET_CODE (reg2) != CONST_INT || \ + GET_CODE (reg1) != REG) { \ + abort(); \ + } \ + fprintf (FILE, "0[%s:%c]", \ + reg_names[ REGNO(reg1) ], \ + "XbwXdXXXq"[INTVAL (reg2)]); \ + break; \ + case PLUS: \ + reg1 = 0; reg2 = 0; \ + ireg = 0; breg = 0; \ + offset = 0; \ + multval = 0; \ + reg1_str[0] = 0; reg2_str[0] = 0; \ + offset_printed = 0; \ + if (CONSTANT_ADDRESS_P (XEXP (addr, 0)) \ + || GET_CODE (XEXP (addr, 0)) == MEM) \ + { \ + /* CONST / MEM(PLUS((REG)(CONST))) */ \ + offset = XEXP (addr, 0); \ + /* (REG) / PLUS((REG)(CONST)) / MULT((REG)(CONST)) */ \ + addr = XEXP (addr, 1); \ + } \ + else if (CONSTANT_ADDRESS_P (XEXP (addr, 1)) \ + || GET_CODE (XEXP (addr, 1)) == MEM) \ + { \ + /* CONST / MEM(PLUS((REG)(CONST))) */ \ + offset = XEXP (addr, 1); \ + /* (REG) / PLUS((REG)(CONST)) / MULT((REG)(CONST)) */ \ + addr = XEXP (addr, 0); \ + } \ + if (offset != 0) { \ + if (GET_CODE (offset) == MEM) { \ + offset = XEXP (offset, 0); /* skip MEM */ \ + switch (GET_CODE (offset)) { \ + case REG: \ + sprintf (reg1_str, "(%s)", \ + reg_names[REGNO (offset)]); \ + offset = 0; \ + break; \ + case PLUS: \ + if (!CONSTANT_ADDRESS_P (XEXP (offset, 1))) { \ + fprintf (FILE, \ + "PROGRAM in disorder PRINT_ADDR, PLUS, PLUS\n"); \ + print_rtl(FILE, offset); \ + exit (1); \ + } \ + if (GET_CODE (XEXP(offset,0)) != REG) { \ + fprintf (FILE, \ + "PROGRAM in disorder PRINT_ADDR, PLUS, REG\n"); \ + print_rtl(FILE, offset); \ + exit (1); \ + } \ + sprintf (reg1_str, "(%s))", \ + reg_names[REGNO (XEXP(offset,0))]); \ + offset = XEXP (offset, 1); \ + break; \ + default: \ + abort(); \ + } \ + } else { /* !MEM */ \ + if (!CONSTANT_ADDRESS_P (offset)) { \ + abort(); \ + } \ + output_addr_const (FILE, offset); \ + offset_printed = 1; \ + offset = 0; \ + } \ + } \ + \ + if (GET_CODE (addr) == PLUS) { \ + if (GET_CODE (XEXP (addr, 0)) == MULT) \ + { \ + reg1 = XEXP (addr, 0); /* [rX:Y] */ \ + addr = XEXP (addr, 1); /* CONST/REG */ \ + if (GET_CODE (XEXP (reg1, 1)) != CONST_INT || \ + GET_CODE (XEXP (reg1, 0)) != REG) { \ + abort(); \ + } \ + sprintf (reg2_str, "[%s:%c]", \ + reg_names[ REGNO(XEXP (reg1, 0)) ], \ + "XbwXdXXXq"[INTVAL (XEXP (reg1, 1))]); \ + reg1 = 0; \ + } \ + else if (GET_CODE (XEXP (addr, 1)) == MULT) \ + { \ + reg1 = XEXP (addr, 1); /* [rX:Y] */ \ + addr = XEXP (addr, 0); /* CONST */ \ + if (GET_CODE (XEXP (reg1, 1)) != CONST_INT || \ + GET_CODE (XEXP (reg1, 0)) != REG) { \ + abort(); \ + } \ + sprintf (reg2_str, "[%s:%c]", \ + reg_names[ REGNO(XEXP (reg1, 0)) ], \ + "XbwXdXXXq"[INTVAL (XEXP (reg1, 1))]); \ + reg1 = 0; \ + } \ + else if (GET_CODE (XEXP (addr, 0)) == REG \ + && REGNO (XEXP (addr, 0)) < 8) \ + { \ + sprintf (reg2_str, "[%s:b]", \ + reg_names[ REGNO(XEXP (addr, 0)) ]); \ + addr = XEXP (addr, 1); /* CONST / REG */ \ + } \ + else if (GET_CODE (XEXP (addr, 1)) == REG \ + && REGNO (XEXP (addr, 1)) < 8) \ + { \ + sprintf (reg2_str, "[%s:b]", \ + reg_names[ REGNO(XEXP (addr, 1)) ]); \ + addr = XEXP (addr, 0); /* CONST / REG */ \ + } \ + else abort (); \ + } \ + if (addr) \ + switch (GET_CODE (addr)) { \ + case MULT: \ + if(*reg2_str) { \ + fprintf (FILE, \ + "PROGRAM in disorder PRINT_ADDR, INDEX, two mults\n"); \ + print_rtl(FILE, addr); \ + exit (1); \ + } \ + reg1 = XEXP (addr, 0); /* [rX:Y] */ \ + addr = XEXP (addr, 1); /* CONST */ \ + if (GET_CODE (addr) != CONST_INT) { \ + fprintf (FILE, \ + "PROGRAM in disorder PRINT_ADDR, INDEX, !CONS3 (%d)\n", \ + GET_CODE (addr)); \ + print_rtl(FILE, addr); \ + exit (1); \ + } \ + sprintf (reg2_str, "[%s:%c]", reg_names[ REGNO(reg1) ], \ + "XbwXdXXXq"[INTVAL (addr)]); \ + break; \ + case REG: \ + if (!*reg1_str) { \ + if (offset || offset_printed) \ + sprintf (reg1_str, "(%s)", reg_names[REGNO (addr)]); \ + else \ + sprintf (reg1_str, "0(%s)", reg_names[REGNO (addr)]); \ + } else if (!*reg2_str) \ + sprintf (reg2_str, "[%s:b]", \ + reg_names[REGNO (addr)]); \ + else abort(); \ + break; \ + case MEM: \ + addr = XEXP(addr,0); \ + switch (GET_CODE(addr)) { \ + case REG: \ + if (!*reg1_str) { \ + if (offset || offset_printed) \ + sprintf (reg1_str, "(0(%s))", \ + reg_names[REGNO (addr)]); \ + else \ + sprintf (reg1_str, "0(0(%s))", \ + reg_names[REGNO (addr)]); \ + } else \ + abort(); \ + break; \ + case PLUS: \ + if (GET_CODE (XEXP (addr, 0)) == REG) { \ + if (!*reg1_str) { \ + sprintf (reg1_str, "(%s))", \ + reg_names[REGNO(XEXP(addr, 0))]); \ + offset = XEXP(addr, 1); \ + } else \ + abort(); \ + } else { \ + if (!*reg1_str) { \ + sprintf (reg1_str, "(%s))", \ + reg_names[REGNO(XEXP(addr, 1))]); \ + offset = XEXP(addr, 0); \ + } else \ + abort(); \ + } \ + break; \ + default: \ + abort(); \ + } \ + break; \ + default: \ + if (offset_printed) \ + fprintf (FILE, "+"); \ + output_addr_const (FILE, addr); \ + offset_printed ++; \ + } \ + if (offset) { \ + if(!offset_printed) \ + fputc ('0', FILE); \ + fputc ('(', FILE); \ + output_addr_const (FILE, offset); \ + } \ + if (*reg1_str) \ + fprintf (FILE, "%s", reg1_str); \ + if (*reg2_str) \ + fprintf (FILE, "%s", reg2_str); \ + break; \ + default: \ + output_addr_const (FILE, addr); \ + } \ + if(mem) \ + fprintf(FILE,")");} + +/* +Local variables: +version-control: t +End: +*/ diff --git a/gcc-1.40/config/tm-pyr.h b/gcc-1.40/config/tm-pyr.h new file mode 100644 index 0000000..6d1c593 --- /dev/null +++ b/gcc-1.40/config/tm-pyr.h @@ -0,0 +1,1406 @@ +/* Definitions of target machine for GNU compiler for Pyramid 90 Series. + Copyright (C) 1989 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 1, 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. */ + +/* + * If you're going to change this, and you haven't already, + * you should get and read + * ``OSx Operating System Porting Guide'', + * publication number 4100-0066-A + * Revision A + * Pyramid Technology Corporation. + * + * or whatever the most recent version is. In any case, page and + * section number references given herein refer to this document. + * + * The instruction table for gdb lists the available insns and + * the valid addressing modes. + * + * Any other information on the Pyramid architecture is proprietary + * and hard to get. (Pyramid cc -S and adb are also useful.) + * + */ + +/*** Run-time compilation parameters selecting different hardware subsets. ***/ + +/* Names to predefine in the preprocessor for this target machine. */ + +#define CPP_PREDEFINES "-Dpyr -Dunix" + +/* Print subsidiary information on the compiler version in use. */ + +#define TARGET_VERSION fprintf (stderr, " (pyr)"); + +extern int target_flags; + +/* Nonzero if compiling code that Unix assembler can assemble. */ +#define TARGET_UNIX_ASM (target_flags & 1) + +/* Use the indexed addressing modes (were once not known to work). + Leaving this in means we can disable them and so find out what + they win us. */ +#define TARGET_INDEX (target_flags & 2) + +/* Implement stdarg in the same fashion used on all other machines. */ +#define TARGET_GNU_STDARG (target_flags & 4) + +/* Compile using RETD to pop off the args. + This will not work unless you use prototypes at least + for all functions that can take varying numbers of args. + This contravenes the Pyramid calling convention, so we don't + do it yet. */ + +#define TARGET_RETD (target_flags & 8) + +/* Macros used in the machine description to test the flags. */ + +/* 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. + + -mgnu will be useful if we ever have GAS on a pyramid. + -mindex was used to enable indexing when I didn't understand + how pyramid's indexing modes worked. */ + +#define TARGET_SWITCHES \ + { {"unix", 1}, \ + {"gnu", -1}, \ + {"index", 2}, \ + {"noindex", -2}, \ + {"gnu-stdarg", 4}, \ + {"nognu-stdarg", -4}, \ + {"retd", 8}, \ + {"no-retd", -8}, \ + { "", TARGET_DEFAULT}} + +/* Default target_flags if no switches specified. + + (equivalent to "-munix -mindex -mgnu-stdarg") */ + +#ifndef TARGET_DEFAULT +#define TARGET_DEFAULT (1 + 2 + 4) +#endif + +/*** Target machine storage layout ***/ + +/* Define this if most significant bit is lowest numbered + in instructions that operate on numbered bit-fields. + This is not true on the pyramid. */ +/* #define BITS_BIG_ENDIAN */ + +/* Define this if most significant byte of a word is the lowest numbered. */ +#define BYTES_BIG_ENDIAN + +/* Define this if most significant word of a multiword number is numbered. */ +#define WORDS_BIG_ENDIAN + +/* Number of bits in an addressible 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 32 + +/* Width of a word, in units (bytes). */ +#define UNITS_PER_WORD 4 + +/* Width in bits of a pointer. + See also the macro `Pmode' defined below. */ +#define POINTER_SIZE 32 + +/* Allocation boundary (in *bits*) for storing pointers in memory. */ +#define POINTER_BOUNDARY 32 + +/* Allocation boundary (in *bits*) for storing arguments in argument list. */ +#define PARM_BOUNDARY 32 + +/* Boundary (in *bits*) on which stack pointer should be aligned. */ +#define STACK_BOUNDARY 32 + +/* Allocation boundary (in *bits*) for the code of a function. */ +#define FUNCTION_BOUNDARY 32 + +/* Alignment of field after `int : 0' in a structure. */ +#define EMPTY_FIELD_BOUNDARY 32 + +/* Every structure's size must be a multiple of this. */ +/* --> FIXME: I don't know if this is what pyr cc does. */ +#define STRUCTURE_SIZE_BOUNDARY 32 + +/* No data type wants to be aligned rounder than this. */ +#define BIGGEST_ALIGNMENT 32 + +/* Make strings word-aligned so dhrystone will run faster. + Pyramid documentation says the best alignment is to align + on the size of a cache line, which is 16 bytes. + Newer pyrs have single insns that do strcmp() and strcpy(), so this + may not actually win anything. */ +/* Try to increase aligment. */ + +/* Use kludge to maintain alignment for pyramid. See + DATA_SECTION_ASM_OP below. */ +#define CONSTANT_ALIGNMENT(CODE, TYPEALIGN) \ + ((CODE) == STRING_CST ? (TYPEALIGN) * 4 : (TYPEALIGN)) + +/* Define this if move instructions will actually fail to work + when given unaligned data. */ +#define STRICT_ALIGNMENT + +/*** 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. */ + +/* Nota Bene: + Pyramids have 64 addressable 32-bit registers, arranged as four + groups: global, parameter, local, and temporary. + The sixteen global registers are fairly conventional; the last + four are overloaded with a PSW, frame pointer, and stack pointer. + The non-dedicated global registers used to be reserved for Pyramid + operating systems, and still have cryptic and undocumented uses for + certain library calls. We avoid them. + + The parameter, local, and temporary registers provide _register_ + _windowing_. Each procedure call has its own set of these 48 + registers, which constitute its call frame. (These frames are + allocated on a stack separate from the conventional data stack, + called the _control_ _stack_. + facility hereby the temporary registers of frame n + become the parameter registers of frame n+1, viz.: + + 0 15 0 15 0 15 + +------------+------------+------------+ + | | | | + +------------+------------+------------+ + Parameter Local Temporary + + ^ + | + v + + 0 15 0 15 0 15 + +------------+------------+------------+ + | | | | + +------------+------------+------------+ + Parameter Local Temporary + + + Temporary registers are used for parameter passing, and are not + preserved across calls. TR14 and TR15 are reserved and should + never be used; since they are used to save the next frame's PC + and stack pointer, their contents may be destroyed at any time by + an interrupt. + */ + +#define PYR_GREG(n) (n) +#define PYR_PREG(n) (16+(n)) +#define PYR_LREG(n) (32+(n)) +#define PYR_TREG(n) (48+(n)) + +#define FIRST_PSEUDO_REGISTER 64 + +/* 1 for registers that have pervasive standard uses + and are not available for the register allocator. + + On the pyramid, these are LOGPSW, CFP, SP, PC, but we leave the other + global regs alone as well. */ + +#define FIXED_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, 1, 1, 1, 1, \ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, \ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1} + +/* 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, 1, 1, 1, 1, \ + 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} + +/* #define DEFAULT_CALLER_SAVES */ + +/* 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 the pyramid, all registers are one word long. */ +#define HARD_REGNO_NREGS(REGNO, MODE) \ + ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD) + +/* Value is 1 if hard register REGNO can hold a value of machine-mode MODE. + On the pyramid, all registers can hold all modes. */ + +/* -->FIXME: this is not the case for 64-bit quantities in tr11/12 through + --> TR14/15. This should be fixed, but to do it correctly, we also + --> need to fix MODES_TIEABLE_P. Yuk. We ignore this, since GCC should + --> do the "right" thing due to FIXED_REGISTERS. */ +#define HARD_REGNO_MODE_OK(REGNO, MODE) 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) 1 + +/* Specify the registers used for certain standard purposes. + The values of these macros are register numbers. */ + +/* Pyramid pc is overloaded on global register 15. */ +#define PC_REGNUM PYR_GREG(15) + +/* Register to use for pushing function arguments. + --> on Pyramids, the data stack pointer. */ +#define STACK_POINTER_REGNUM PYR_GREG(14) + +/* Base register for access to local variables of the function. + Pyramid uses CFP (GR13) as both frame pointer and argument pointer. */ +#define FRAME_POINTER_REGNUM 13 /* PYR_GREG(13) */ + +/* 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. + + Setting this to 1 can't break anything. Since the Pyramid has + register windows, I don't know if defining this to be zero can + win anything. It could changed later, if it wins. */ +#define FRAME_POINTER_REQUIRED 1 + +/* Base register for access to arguments of the function. */ +#define ARG_POINTER_REGNUM 13 /* PYR_GREG(13) */ + +/* Register in which static-chain is passed to a function. */ +/* If needed, Pyramid says to use temporary register 12. */ +#define STATIC_CHAIN_REGNUM PYR_TREG(12) + +/* Register in which address to store a structure value + is passed to a function. + On a Pyramid, this is temporary register 0 (TR0). */ + +#define STRUCT_VALUE_REGNUM PYR_TREG(0) +#define STRUCT_VALUE_INCOMING_REGNUM PYR_PREG(0) + +/* 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 pyramid has only one kind of registers, so NO_REGS and ALL_REGS + are the only classes. */ + +enum reg_class { NO_REGS, ALL_REGS, LIM_REG_CLASSES }; + +#define N_REG_CLASSES (int) LIM_REG_CLASSES + +/* Since GENERAL_REGS is the same class as ALL_REGS, + don't give it a different class number; just make it an alias. */ + +#define GENERAL_REGS ALL_REGS + +/* Give names of register classes as strings for dump file. */ + +#define REG_CLASS_NAMES \ + {"NO_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}, {0xffffffff,0xffffffff}} + +/* 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. */ + +#define REGNO_REG_CLASS(REGNO) ALL_REGS + +/* The class value for index registers, and the one for base regs. */ + +#define BASE_REG_CLASS ALL_REGS +#define INDEX_REG_CLASS ALL_REGS + +/* Get reg_class from a letter such as appears in the machine description. */ + +#define REG_CLASS_FROM_LETTER(C) NO_REGS + +/* 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. */ + +#define PREFERRED_RELOAD_CLASS(X,CLASS) (CLASS) + +/* Return the maximum number of consecutive registers + needed to represent mode MODE in a register of class CLASS. */ +/* On the pyramid, this is always the size of MODE in words, + since all registers are the same size. */ +#define CLASS_MAX_NREGS(CLASS, MODE) \ + ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD) + +/* 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. + + --> For the Pyramid, 'I' can be used for the 6-bit signed integers + --> (-32 to 31) allowed as immediate short operands in many + --> instructions. 'J' cane be used for any value that doesn't fit + --> in 6 bits. */ + +#define CONST_OK_FOR_LETTER_P(VALUE, C) \ + ((C) == 'I' ? (VALUE) >= -32 && (VALUE) < 32 : \ + (C) == 'J' ? (VALUE) < -32 || (VALUE) >= 32 : \ + (C) == 'K' ? (VALUE) == 0xff || (VALUE) == 0xffff : 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) 1 + + +/*** Stack layout; function entry, exit and calling. ***/ + +/* 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. */ +/* FIXME: this used to work when defined as 0. But that makes gnu + stdargs clobber the first arg. What gives?? */ +#define STARTING_FRAME_OFFSET 0 + +/* Offset of first parameter from the argument pointer register value. */ +#define FIRST_PARM_OFFSET(FNDECL) 0 + +/* Value is 1 if returning from a function call automatically + pops the arguments described by the number-of-args field in the call. + 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. + + The Pyramid OSx Porting Guide says we are never to do this; + using RETD in this way violates the Pyramid calling convention. + We may nevertheless provide this as an option. */ + +#define RETURN_POPS_ARGS(FUNTYPE) \ + (TARGET_RETD && TREE_CODE (FUNTYPE) != IDENTIFIER_NODE \ + && (TYPE_ARG_TYPES (FUNTYPE) == 0 \ + || TREE_VALUE (tree_last (TYPE_ARG_TYPES (FUNTYPE))) == void_type_node)) + +/* 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. */ + +/* --> Pyramid has register windows. + --> The caller sees the return value is in TR0(/TR1) regardless of + --> its type. */ + +#define FUNCTION_VALUE(VALTYPE, FUNC) \ + gen_rtx (REG, TYPE_MODE (VALTYPE), PYR_TREG(0)) + +/* --> but the callee has to leave it in PR0(/PR1) */ + +#define FUNCTION_OUTGOING_VALUE(VALTYPE, FUNC) \ + gen_rtx (REG, TYPE_MODE (VALTYPE), PYR_PREG(0)) + +/* Define how to find the value returned by a library function + assuming the value has mode MODE. */ + +/* --> On Pyramid the return value is in TR0/TR1 regardless. */ + +#define LIBCALL_VALUE(MODE) gen_rtx (REG, MODE, PYR_TREG(0)) + +/* Define this if PCC uses the nonreentrant convention for returning + structure and union values. */ + +#define PCC_STATIC_STRUCT_RETURN + +/* 1 if N is a possible register number for a function value + as seen by the caller. + + On the Pyramid, TR0 is the only register thus used. */ + +#define FUNCTION_VALUE_REGNO_P(N) ((N) == PYR_TREG(0)) + +/* 1 if N is a possible register number for function argument passing. + On the Pyramid, the first twelve temporary registers are available. */ + +/* FIXME FIXME FIXME + it's not clear whether this macro should be defined from the point + of view of the caller or the callee. Since it's never actually used + in GNU CC, the point is somewhat moot :-). + + This definition is consistent with register usage in the md's for + other register-window architectures (sparc and spur). + */ +#define FUNCTION_ARG_REGNO_P(N) ((PYR_TREG(0) <= (N)) && ((N) <= PYR_TREG(11))) + +/*** Parameter passing: FUNCTION_ARG and FUNCTION_INCOMING_ARG ***/ + +/* 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 Pyramids, each parameter is passed either completely on the stack + or completely in registers. No parameter larger than a double may + be passed in a register. Also, no struct or union may be passed in + a register, even if it would fit. + + So parameters are not necessarily passed "consecutively". + Thus we need a vector data type: one element to record how many + parameters have been passed in registers and on the stack, + respectively. + + ((These constraints seem like a gross waste of registers. But if we + ignore the constraint about structs & unions, we won`t be able to + freely mix gcc-compiled code and pyr cc-compiled code. It looks + like better argument passing conventions, and a machine-dependent + flag to enable them, might be a win.)) */ + + +#define CUMULATIVE_ARGS int + +/* Define the number of registers that can hold paramters. + This macro is used only in other macro definitions below. */ +#define NPARM_REGS 12 + +/* Decide whether or not a parameter can be put in a register. + (We may still have problems with libcalls. GCC doesn't seem + to know about anything more than the machine mode. I trust + structures are never passed to a libcall... + + If compiling with -mgnu-stdarg, this definition should make + functions using the gcc-supplied stdarg, and calls to such + functions (declared with an arglist ending in"..."), work. + But such fns won't be able to call pyr cc-compiled + varargs fns (eg, printf(), _doprnt.) + + If compiling with -mnognu-stdarg, this definition should make + calls to pyr cc-compiled functions work. Functions using + the gcc-supplied stdarg will be utterly broken. + There will be no better solution until RMS can be persuaded that + one is needed. + + This macro is used only in other macro definitions below. + (well, it may be used in out-pyr.c, because the damn pyramid cc + can't handle the macro definition of PARAM_SAFE_FOR_REG_P ! */ + + +#define INNER_PARAM_SAFE_HELPER(TYPE) \ + ((TARGET_GNU_STDARG ? (! TREE_ADDRESSABLE ((tree)TYPE)): 1) \ + && (TREE_CODE ((tree)TYPE) != RECORD_TYPE) \ + && (TREE_CODE ((tree)TYPE) != UNION_TYPE)) + +#ifdef __GNUC__ +#define PARAM_SAFE_HELPER(TYPE) \ + INNER_PARAM_SAFE_HELPER((TYPE)) +#else +extern int inner_param_safe_helper(); +#define PARAM_SAFE_HELPER(TYPE) \ + inner_param_safe_helper((tree)(TYPE)) +#endif + +/* Be careful with the expression (long) (TYPE) == 0. + Writing it in more obvious/correct forms makes the Pyr cc + dump core! */ +#define PARAM_SAFE_FOR_REG_P(MODE, TYPE, NAMED) \ + (((MODE) != BLKmode) \ + && ((TARGET_GNU_STDARG) ? (NAMED) : 1) \ + && ((((long)(TYPE))==0) || PARAM_SAFE_HELPER((TYPE)))) + +/* 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. */ + +#define INIT_CUMULATIVE_ARGS(CUM,FNTYPE) \ + ((CUM) = (FNTYPE && !flag_pcc_struct_return && aggregate_value_p (FNTYPE))) + +/* 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). */ + +#define FUNCTION_ARG_HELPER(CUM, MODE, TYPE, NAMED) \ +(PARAM_SAFE_FOR_REG_P(MODE,TYPE,NAMED) \ + ? (NPARM_REGS >= ((CUM) \ + + ((MODE) == BLKmode \ + ? (int_size_in_bytes (TYPE) + 3) / 4 \ + : (GET_MODE_SIZE (MODE) + 3) / 4)) \ + ? gen_rtx (REG, (MODE), PYR_TREG(CUM)) \ + : 0) \ + : 0) +#ifdef __GNUC__ +#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \ + FUNCTION_ARG_HELPER(CUM, MODE, TYPE, NAMED) +#else +/***************** Avoid bug in Pyramid OSx compiler... ******************/ +#define FUNCTION_ARG (rtx) pyr_function_arg +extern void* pyr_function_arg (); +#endif + +/* 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) \ +(PARAM_SAFE_FOR_REG_P(MODE,TYPE,NAMED) \ + ? (NPARM_REGS >= ((CUM) \ + + ((MODE) == BLKmode \ + ? (int_size_in_bytes (TYPE) + 3) / 4 \ + : (GET_MODE_SIZE (MODE) + 3) / 4)) \ + ? gen_rtx (REG, (MODE), PYR_PREG(CUM)) \ + : 0) \ + : 0) + +/* 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.) */ + +#define FUNCTION_ARG_ADVANCE(CUM,MODE,TYPE,NAMED) \ +((CUM) += (PARAM_SAFE_FOR_REG_P(MODE,TYPE,NAMED) \ + ? ((MODE) != BLKmode \ + ? (GET_MODE_SIZE (MODE) + 3) / 4 \ + : (int_size_in_bytes (TYPE) + 3) / 4) \ + : 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. */ + +#if FRAME_POINTER_REQUIRED + +/* We always have frame pointers */ + +/* Don't set up a frame pointer if it's not referenced. */ + +#define FUNCTION_PROLOGUE(FILE, SIZE) \ +{ \ + int _size = (SIZE) + current_function_pretend_args_size; \ + if (_size + current_function_args_size != 0 \ + || current_function_calls_alloca) \ + { \ + fprintf (FILE, "\tadsf $%d\n", _size); \ + if (current_function_pretend_args_size > 0) \ + fprintf (FILE, "\tsubw $%d,cfp\n", \ + current_function_pretend_args_size); \ + } \ +} + +#else /* !FRAME_POINTER_REQUIRED */ + +/* Don't set up a frame pointer if `frame_pointer_needed' tells us + there is no need. Also, don't set up a frame pointer if it's not + referenced. */ + +/* The definition used to be broken. Write a new one. */ + +#endif /* !FRAME_POINTER_REQUIRED */ + +/* Output assembler code to FILE to increment profiler label # LABELNO + for profiling a function entry. */ +#define FUNCTION_PROFILER(FILE, LABELNO) \ + fprintf (FILE, "\tmova LP%d,tr0\n\tcall mcount\n", (LABELNO)); + +/* Output assembler code to FILE to initialize this source file's + basic block profiling info, if that has not already been done. + Don't know if this works on Pyrs. */ + +#if 0 /* don't do basic_block profiling yet */ +#define FUNCTION_BLOCK_PROFILER(FILE, LABELNO) \ + fprintf (FILE, \ + "\tmtstw LPBX0,tr0\n\tbne LPI%d\n\tmova LP%d,TR0\n\tcall __bb_init_func\nLPI%d:\n", \ + LABELNO, LABELNO); + +/* Output assembler code to increment the count associated with + the basic block number BLOCKNO. Not sure how to do this on pyrs. */ +#define BLOCK_PROFILER(FILE, BLOCKNO) \ + fprintf (FILE, "\taddw", 4 * BLOCKNO) +#endif /* don't do basic_block profiling yet */ + +/* When returning from a function, the stack pointer does not matter + (as long as there is a frame pointer). */ + +/* This should return non-zero when we really set up a frame pointer. + Otherwise, GCC is directed to preserve sp by returning zero. */ +extern int current_function_pretend_args_size; +extern int current_function_args_size; +extern int current_function_calls_alloca; +#define EXIT_IGNORE_STACK \ + (get_frame_size () + current_function_pretend_args_size \ + + current_function_args_size != 0 \ + || current_function_calls_alloca) \ + +/* If the memory address ADDR is relative to the frame pointer, + correct it to be relative to the stack pointer instead. + This is for when we don't use a frame pointer. + ADDR should be a variable name. */ + +/* ---> Since we always have a frame pointer, it is safe for this + to not work. */ + +#define FIX_FRAME_POINTER_ADDRESS(ADDR,DEPTH) \ + fatal ("compiler error, Pyramid call without frame ptr!\n") + +/*** Addressing modes, and classification of registers for them. ***/ + +/* #define HAVE_POST_INCREMENT */ /* pyramid has none of these */ +/* #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. */ + +/* All registers except gr0 OK as index or base registers. */ + +#define REGNO_OK_FOR_BASE_P(regno) \ +((0 < (regno) && (regno) < FIRST_PSEUDO_REGISTER) || reg_renumber[regno] > 0) + +#define REGNO_OK_FOR_INDEX_P(regno) \ +((0 < (regno) && (regno) < FIRST_PSEUDO_REGISTER) || reg_renumber[regno] > 0) + +/* Maximum number of registers that can appear in a valid memory address. */ + +#define MAX_REGS_PER_ADDRESS 2 /* check MAX_REGS_PER_ADDRESS */ + +/* 1 if X is an rtx for a constant that is a valid address. */ + +#define CONSTANT_ADDRESS_P(X) CONSTANT_P (X) + +/* Nonzero if the constant value X is a legitimate general operand. + It is given that X satisfies CONSTANT_P or is a CONST_DOUBLE. */ + +#define LEGITIMATE_CONSTANT_P(X) 1 + +/* 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. */ + +#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) 1 +/* 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) 1 + +#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)) + +#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. + + The other macros defined here are used only in GO_IF_LEGITIMATE_ADDRESS, + except for CONSTANT_ADDRESS_P which is actually machine-independent. */ + + +/* Go to ADDR if X is indexable -- ie, neither indexed nor offset. + Note that X is indexable iff x is offset. */ +#define GO_IF_INDEXABLE_ADDRESS(X, ADDR) \ +{ register rtx xfoob = (X); \ + if ((CONSTANT_ADDRESS_P (xfoob)) \ + || (GET_CODE (xfoob) == REG && (REG_OK_FOR_BASE_P (xfoob)))) \ + goto ADDR; \ + } + + +/* Go to label ADDR if X is a valid address that doesn't use indexing. + This is so if X is either a simple address, or the contents of a register + plus an offset. + This macro also gets used in output-pyramid.h in the function that + recognizes non-indexed operands. */ + +#define GO_IF_NONINDEXED_ADDRESS(X, ADDR) \ +{ \ + if (GET_CODE (X) == REG) \ + goto ADDR; \ + GO_IF_INDEXABLE_ADDRESS (X, ADDR); \ + if (GET_CODE (X) == PLUS) \ + { /* Handle offset(reg) represented with offset on left */ \ + if (CONSTANT_ADDRESS_P (XEXP (X, 0))) \ + { if (GET_CODE (XEXP (X, 1)) == REG \ + && REG_OK_FOR_BASE_P (XEXP (X, 1))) \ + goto ADDR; \ + } \ + /* Handle offset(reg) represented with offset on right */ \ + if (CONSTANT_ADDRESS_P (XEXP (X, 1))) \ + { if (GET_CODE (XEXP (X, 0)) == REG \ + && REG_OK_FOR_BASE_P (XEXP (X, 0))) \ + goto ADDR; \ + } \ + } \ +} + +/* 1 if PROD is either a reg or a reg times a valid offset multiplier + (ie, 2, 4, or 8). + This macro's expansion uses the temporary variables xfoo0 and xfoo1 + that must be declared in the surrounding context. */ +#define INDEX_TERM_P(PROD, MODE) \ +((GET_CODE (PROD) == REG && REG_OK_FOR_BASE_P (PROD)) \ + || (GET_CODE (PROD) == MULT \ + && \ + (xfoo0 = XEXP (PROD, 0), xfoo1 = XEXP (PROD, 1), \ + ((GET_CODE (xfoo0) == CONST_INT \ + && (INTVAL (xfoo0) == 1 \ + || INTVAL (xfoo0) == 2 \ + || INTVAL (xfoo0) == 4 \ + || INTVAL (xfoo0) == 8) \ + && GET_CODE (xfoo1) == REG \ + && REG_OK_FOR_INDEX_P (xfoo1)) \ + || \ + (GET_CODE (xfoo1) == CONST_INT \ + && (INTVAL (xfoo1) == 1 \ + || INTVAL (xfoo1) == 2 \ + || INTVAL (xfoo1) == 4 \ + || INTVAL (xfoo1) == 8) \ + && GET_CODE (xfoo0) == REG \ + && REG_OK_FOR_INDEX_P (xfoo0)))))) + + +#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \ +{ register rtx xone, xtwo, xfoo0, xfoo1; \ + GO_IF_NONINDEXED_ADDRESS (X, ADDR); \ + if (TARGET_INDEX && GET_CODE (X) == PLUS) \ + { \ + /* Handle
[index] represented with index-sum outermost */\ + xone = XEXP (X, 0); \ + xtwo = XEXP (X, 1); \ + if (INDEX_TERM_P (xone, MODE)) \ + { GO_IF_INDEXABLE_ADDRESS (xtwo, ADDR); } \ + /* Handle
[index] represented with index-sum innermost */\ + if (INDEX_TERM_P (xtwo, MODE)) \ + { GO_IF_INDEXABLE_ADDRESS (xone, 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. + + --> FIXME: We haven't yet figured out what optimizations are useful + --> on Pyramids. */ + +#define LEGITIMIZE_ADDRESS(X,OLDX,MODE,WIN) {} + +/* Go to LABEL if ADDR (a legitimate address expression) + has an effect that depends on the machine mode it is used for. + There don't seem to be any such modes on pyramids. */ +#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR,LABEL) + +/*** Miscellaneous Parameters ***/ + +/* 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. + Do not define this if the table should contain absolute addresses. */ +/*#define CASE_VECTOR_PC_RELATIVE*/ + +/* 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. + It's just a guess. I have no idea of insn cost on pyrs. */ +#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 + +/* This flag, if defined, says the same insns that convert to a signed fixnum + also convert validly to an unsigned one. */ +/* This is untrue for pyramid. The cvtdw instruction generates a trap + for input operands that are out-of-range for a signed int. */ +/* #define FIXUNS_TRUNC_LIKE_FIX_TRUNC */ + +/* Define this macro if the preprocessor should silently ignore + '#sccs' directives. */ +/* #define SCCS_DIRECTIVE */ + +/* Define this macro if the preprocessor should silently ignore + '#ident' directives. */ +/* #define IDENT_DIRECTIVE */ + +/* Max number of bytes we can move from memory to memory + in one reasonably fast instruction. */ +#define MOVE_MAX 8 + +/* Define this if zero-extension is slow (more than one real instruction). */ +/* #define SLOW_ZERO_EXTEND */ + +/* number of bits in an 'int' on target machine */ +#define INT_TYPE_SIZE 32 + +/* 1 if byte access requires more than one instruction */ +#define SLOW_BYTE_ACCESS 0 + +/* Define if shifts truncate the shift count + which implies one can omit a sign-extension or zero-extension + of a shift count. */ +#define SHIFT_COUNT_TRUNCATED + +/* 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 + +/* 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. +/* #define NO_FUNCTION_CSE */ + +/* When a prototype says `char' or `short', really pass an `int'. */ +#define PROMOTE_PROTOTYPES + +/* There are no flag store insns on a pyr. */ +/* #define STORE_FLAG_VALUE */ + +/* 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 SImode + +/* 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 QImode + +/* 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) \ + case CONST_INT: \ + if (CONST_OK_FOR_LETTER_P (INTVAL (RTX),'I')) return 0; \ + case CONST: \ + case LABEL_REF: \ + case SYMBOL_REF: \ + return 2; \ + case CONST_DOUBLE: \ + return 4; + +/*** Condition Code Information ***/ + +/* Tell final.c how to eliminate redundant test instructions. */ + +/* Here we define machine-dependent flags and fields in cc_status + (see `conditions.h'). No extra ones are needed for the pyr. */ + +/* Store in cc_status the expressions + that the condition codes will describe + after execution of an instruction whose pattern is EXP. + Do not alter them if the instruction would not alter the cc's. */ + +/* This is a very simple definition of NOTICE_UPDATE_CC. + Many cases can be optimized, to improve condition code usage. + Maybe we should handle this entirely in the md, since it complicated + to describe the way pyr sets cc. */ + +#define TRULY_UNSIGNED_COMPARE_P(X) \ + (X == GEU || X == GTU || X == LEU || X == LTU) +#define CC_VALID_FOR_UNSIGNED 2 + +#define CC_STATUS_MDEP_INIT cc_status.mdep = 0 + +#define NOTICE_UPDATE_CC(EXP, INSN) \ + notice_update_cc(EXP, INSN) + +/*** Output of Assembler Code ***/ + +/* Output at beginning of assembler file. */ + +#define ASM_FILE_START(FILE) \ + fprintf (FILE, ((TARGET_UNIX_ASM)? "" : "#NO_APP\n")); + +/* Output to assembler file text saying following lines + may contain character constants, extra white space, comments, etc. */ + +#define ASM_APP_ON ((TARGET_UNIX_ASM) ? "" : "#APP\n") + +/* Output to assembler file text saying following lines + no longer contain unusual constructs. */ + +#define ASM_APP_OFF ((TARGET_UNIX_ASM) ? "" : "#NO_APP\n") + +/* 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 \ +{"gr0", "gr1", "gr2", "gr3", "gr4", "gr5", "gr6", "gr7", "gr8", \ + "gr9", "gr10", "gr11", "logpsw", "cfp", "sp", "pc", \ + "pr0", "pr1", "pr2", "pr3", "pr4", "pr5", "pr6", "pr7", \ + "pr8", "pr9", "pr10", "pr11", "pr12", "pr13", "pr14", "pr15", \ + "lr0", "lr1", "lr2", "lr3", "lr4", "lr5", "lr6", "lr7", \ + "lr8", "lr9", "lr10", "lr11", "lr12", "lr13", "lr14", "lr15", \ + "tr0", "tr1", "tr2", "tr3", "tr4", "tr5", "tr6", "tr7", \ + "tr8", "tr9", "tr10", "tr11", "tr12", "tr13", "tr14", "tr15"} + +/* How to renumber registers for dbx and gdb. */ + +#define DBX_REGISTER_NUMBER(REGNO) (REGNO) + +/* Our preference is for dbx rather than sdb. + Yours may be different. */ +#define DBX_DEBUGGING_INFO +/* #define SDB_DEBUGGING_INFO */ + +/* Don't use the `xsfoo;' construct in DBX output; this system + doesn't support it. */ + +#define DBX_NO_XREFS 1 + +/* Do not break .stabs pseudos into continuations. */ + +#define DBX_CONTIN_LENGTH 0 + +/* This is the char to use for continuation (in case we need to turn + continuation back on). */ + +#define DBX_CONTIN_CHAR '?' + +/* 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 (".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. */ + +#define ASM_OUTPUT_LABELREF(FILE,NAME) \ + fprintf (FILE, "_%s", NAME); + +/* 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) \ + 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%d", PREFIX, NUM) + +/* This is how to output an assembler line defining a `double' constant. */ + +#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \ + fprintf (FILE, "\t.double 0d%.20e\n", (VALUE)) + +/* This is how to output an assembler line defining a `float' constant. */ + +#define ASM_OUTPUT_FLOAT(FILE,VALUE) \ + fprintf (FILE, "\t.float 0f%.20e\n", (VALUE)) + +/* This is how to output an assembler line defining an `int' constant. */ + +#define ASM_OUTPUT_INT(FILE,VALUE) \ +( fprintf (FILE, "\t.word "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +/* Likewise for `char' and `short' constants. */ + +#define ASM_OUTPUT_SHORT(FILE,VALUE) \ +( fprintf (FILE, "\t.half "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +#define ASM_OUTPUT_CHAR(FILE,VALUE) \ +( fprintf (FILE, "\t.byte "), \ + 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.byte 0x%x\n", (VALUE)) + +/* This is how to output an insn to push a register on the stack. + It need not be very fast code. */ + +#define ASM_OUTPUT_REG_PUSH(FILE,REGNO) \ + fprintf (FILE, "\tsubw $4,sp\n\tmovw %s,(sp)\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, "\tmovw (sp),%s\n\taddw $4,sp\n", reg_names[REGNO]) + +/* 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))) + +/* This is how to output an element of a case-vector that is absolute. */ + +#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \ + fprintf (FILE, "\t.word L%d\n", VALUE) + +/* This is how to output an element of a case-vector that is relative. */ + + +#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, VALUE, REL) \ + fprintf (FILE, "\t.word L%d-L%d\n", VALUE, REL) + +/* This is how to output an assembler line + that says to advance the location counter + to a multiple of 2**LOG bytes. + + On Pyramids, .align takes only args between 2 and 5. + */ + +#define ASM_OUTPUT_ALIGN(FILE,LOG) \ + fprintf (FILE, "\t.align %d\n", (LOG) < 2 ? 2 : (LOG)) + +#define ASM_OUTPUT_SKIP(FILE,SIZE) \ + fprintf (FILE, "\t.space %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 (".comm ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%u\n", (ROUNDED))) + +/* This says how to output an assembler line + to define a local common symbol. */ + +#define ASM_OUTPUT_LOCAL(FILE, NAME, SIZE, ROUNDED) \ +( fputs (".lcomm ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%u\n", (ROUNDED))) + +/* 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 + +/* 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. + On the Pyr, we support the conventional CODE characters: + + 'f' for float insn (print a CONST_DOUBLE as a float rather than in hex) + which are never used. */ + +/* FIXME : should be more robust with CONST_DOUBLE. */ + +#define PRINT_OPERAND(FILE, X, CODE) \ +{ if (GET_CODE (X) == REG) \ + fprintf (FILE, "%s", reg_names [REGNO (X)]); \ + \ + else if (GET_CODE (X) == MEM) \ + output_address (XEXP (X, 0)); \ + \ + else if (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) == SFmode) \ + { union { double d; int i[2]; } u; \ + union { float f; int i; } u1; \ + u.i[0] = CONST_DOUBLE_LOW (X); u.i[1] = CONST_DOUBLE_HIGH (X); \ + u1.f = u.d; \ + if (CODE == 'f') \ + fprintf (FILE, "$0f%.0e", u1.f); \ + else \ + fprintf (FILE, "$0x%x", u1.i); } \ + \ + else if (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) != DImode) \ + { union { double d; int i[2]; } u; \ + u.i[0] = CONST_DOUBLE_LOW (X); u.i[1] = CONST_DOUBLE_HIGH (X); \ + fprintf (FILE, "$0d%.20e", u.d); } \ + \ + else if (CODE == 'N') \ + switch (GET_CODE (X)) \ + { \ + case EQ: fputs ("eq", FILE); break; \ + case NE: fputs ("ne", FILE); break; \ + case GT: \ + case GTU: fputs ("gt", FILE); break; \ + case LT: \ + case LTU: fputs ("lt", FILE); break; \ + case GE: \ + case GEU: fputs ("ge", FILE); break; \ + case LE: \ + case LEU: fputs ("le", FILE); break; \ + } \ + \ + else if (CODE == 'C') \ + switch (GET_CODE (X)) \ + { \ + case EQ: fputs ("ne", FILE); break; \ + case NE: fputs ("eq", FILE); break; \ + case GT: \ + case GTU: fputs ("le", FILE); break; \ + case LT: \ + case LTU: fputs ("ge", FILE); break; \ + case GE: \ + case GEU: fputs ("lt", FILE); break; \ + case LE: \ + case LEU: fputs ("gt", FILE); break; \ + } \ + \ + else if (CODE == 'R') \ + switch (GET_CODE (X)) \ + { \ + case EQ: fputs ("eq", FILE); break; \ + case NE: fputs ("ne", FILE); break; \ + case GT: \ + case GTU: fputs ("lt", FILE); break; \ + case LT: \ + case LTU: fputs ("gt", FILE); break; \ + case GE: \ + case GEU: fputs ("le", FILE); break; \ + case LE: \ + case LEU: fputs ("ge", FILE); break; \ + } \ + \ + else { putc ('$', FILE); output_addr_const (FILE, X); } \ +} + +/* Print a memory operand whose address is ADDR, on file FILE. */ +/* This is horrendously complicated. */ +#define PRINT_OPERAND_ADDRESS(FILE, ADDR) \ +{ \ + register rtx reg1, reg2, breg, ireg; \ + register rtx addr = ADDR; \ + rtx offset, scale; \ + retry: \ + switch (GET_CODE (addr)) \ + { \ + case MEM: \ + fprintf (stderr, "bad Mem "); debug_rtx (addr); \ + addr = XEXP (addr, 0); \ + abort (); \ + case REG: \ + fprintf (FILE, "(%s)", reg_names [REGNO (addr)]); \ + break; \ + case PLUS: \ + reg1 = 0; reg2 = 0; \ + ireg = 0; breg = 0; \ + offset = 0; \ + if (CONSTANT_ADDRESS_P (XEXP (addr, 0)) \ + || GET_CODE (XEXP (addr, 0)) == MEM) \ + { \ + offset = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (CONSTANT_ADDRESS_P (XEXP (addr, 1)) \ + || GET_CODE (XEXP (addr, 1)) == MEM) \ + { \ + offset = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + if (GET_CODE (addr) != PLUS) ; \ + else if (GET_CODE (XEXP (addr, 0)) == MULT) \ + { \ + reg1 = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (GET_CODE (XEXP (addr, 1)) == MULT) \ + { \ + reg1 = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + else if (GET_CODE (XEXP (addr, 0)) == REG) \ + { \ + reg1 = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (GET_CODE (XEXP (addr, 1)) == REG) \ + { \ + 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; \ + addr = 0; \ + } \ + if (offset != 0) \ + { \ + if (addr != 0) { \ + fprintf (stderr, "\nBad addr "); debug_rtx (addr); \ + abort ();} \ + addr = offset; \ + } \ + if (reg1 != 0 && GET_CODE (reg1) == MULT) \ + { breg = reg2; ireg = reg1; } \ + else if (reg2 != 0 && GET_CODE (reg2) == MULT) \ + { breg = reg1; ireg = reg2; } \ + else if (reg2 != 0 || GET_CODE (addr) == MEM) \ + { breg = reg2; ireg = reg1; } \ + else \ + { breg = reg1; ireg = reg2; } \ + if (addr != 0) \ + output_address (offset); \ + if (breg != 0) \ + { if (GET_CODE (breg) != REG) \ + { \ + fprintf (stderr, "bad Breg"); debug_rtx (addr); \ + abort (); \ + } \ + fprintf (FILE, "(%s)", reg_names[REGNO (breg)]); } \ + if (ireg != 0) \ + { \ + if (GET_CODE (ireg) == MULT) \ + { \ + scale = XEXP (ireg, 1); \ + ireg = XEXP (ireg, 0); \ + if (GET_CODE (ireg) != REG) \ + { register rtx tem; \ + tem = ireg; ireg = scale; scale = tem; \ + } \ + if (GET_CODE (ireg) != REG) { \ + fprintf (stderr, "bad idx "); debug_rtx (addr); \ + abort (); } \ + if ((GET_CODE (scale) == CONST_INT) && (INTVAL(scale) >= 1))\ + fprintf (FILE, "[%s*0x%x]", reg_names[REGNO (ireg)], \ + INTVAL(scale)); \ + else \ + fprintf (FILE, "[%s*1]", reg_names[REGNO (ireg)]); \ + } \ + else if (GET_CODE (ireg) == REG) \ + fprintf (FILE, "[%s*1]", reg_names[REGNO (ireg)]); \ + else \ + { \ + fprintf (stderr, "Not indexed at all!"); debug_rtx (addr);\ + abort (); \ + } \ + } \ + break; \ + default: \ + output_addr_const (FILE, addr); \ + } \ +} diff --git a/gcc-1.40/config/tm-seq386.h b/gcc-1.40/config/tm-seq386.h new file mode 100644 index 0000000..615c6cf --- /dev/null +++ b/gcc-1.40/config/tm-seq386.h @@ -0,0 +1,79 @@ +/* Definitions for Sequent Intel 386. + Copyright (C) 1988 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 1, 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 "tm-i386.h" + +/* Use the BSD assembler syntax. */ + +#include "tm-bsd386.h" + +/* By default, target has a 80387. */ + +#define TARGET_DEFAULT 1 + +/* Specify predefined symbols in preprocessor. */ + +#define CPP_PREDEFINES "-Dunix -Di386 -Dsequent" + +/* Pass -Z and -ZO options to the linker. */ + +#define LINK_SPEC "%{Z*}" + +/* We don't want to output SDB debugging information. */ + +#undef SDB_DEBUGGING_INFO + +/* We want to output DBX debugging information. */ + +#define DBX_DEBUGGING_INFO + +/* gcc order is ax, dx, cx, bx, si, di, bp, sp, st, st. + * dbx order is ax, dx, cx, st(0), st(1), bx, si, di, st(2), st(3), + * st(4), st(5), st(6), st(7), sp, bp */ +#undef DBX_REGISTER_NUMBER +#define DBX_REGISTER_NUMBER(n) \ +((n) < 3 ? (n) : (n) < 6 ? (n) + 2 \ + : (n) == 6 ? 15 : (n) == 7 ? 14 : 3) + +/* Prevent anything from being allocated in the register pair cx/bx, + since that would confuse GDB. */ + +#undef HARD_REGNO_MODE_OK +#define HARD_REGNO_MODE_OK(REGNO, MODE) \ + (hard_regno_mode_ok (REGNO, MODE) \ + && ! (REGNO == 2 && GET_MODE_SIZE (MODE) > 4)) + +/* Floating-point return values come in the FP register. */ + +#define VALUE_REGNO(MODE) \ + (((MODE)==SFmode || (MODE)==DFmode) ? FIRST_FLOAT_REG : 0) + +/* 1 if N is a possible register number for a function value. */ + +#define FUNCTION_VALUE_REGNO_P(N) ((N) == 0 || (N)== FIRST_FLOAT_REG) + +/* 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, "\tmovl $LP%d,%%eax\n\tcall mcount\n", (LABELNO)); + +/* Assember pseudo-op for shared data segment. */ +#define SHARED_SECTION_ASM_OP ".shdata" diff --git a/gcc-1.40/config/tm-sequent.h b/gcc-1.40/config/tm-sequent.h new file mode 100644 index 0000000..d34c249 --- /dev/null +++ b/gcc-1.40/config/tm-sequent.h @@ -0,0 +1,110 @@ +/* Definitions of target machine for GNU compiler. SEQUENT NS32000 version. + Copyright (C) 1987 Free Software Foundation, Inc. + Contributed by Michael Tiemann (tiemann@mcc.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 1, 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. */ + +/* Two flags to control how addresses are printed in assembler insns. */ +#define SEQUENT_ADDRESS_BUG 1 +#define SEQUENT_BASE_REGS + +#include "tm-ns32k.h" + +/* This is BSD, so it wants DBX format. */ +#define DBX_DEBUGGING_INFO + +/* Sequent has some changes in the format of DBX symbols. */ +#define DBX_NO_XREFS 1 + +/* Don't split DBX symbols into continuations. */ +#define DBX_CONTIN_LENGTH 0 + +#define TARGET_DEFAULT 1 + +/* Print subsidiary information on the compiler version in use. */ +#undef TARGET_VERSION +#define TARGET_VERSION fprintf (stderr, " (32000, Sequent syntax)"); + +#undef CPP_PREDEFINES +#define CPP_PREDEFINES "-Dns32000 -Dsequent -Dunix" + +/* This is how to align the code that follows an unconditional branch. + Don't define it, since it confuses the assembler (we hear). */ + +#undef ASM_OUTPUT_ALIGN_CODE + +/* Assember pseudo-op for shared data segment. */ +#define SHARED_SECTION_ASM_OP ".shdata" + +/* Control how stack adjust insns are output. */ +#define SEQUENT_ADJUST_STACK + +/* %$ means print the prefix for an immediate operand. + On the sequent, no prefix is used for such. */ + +#undef PRINT_OPERAND +#define PRINT_OPERAND(FILE, X, CODE) \ +{ if (CODE == '$') ; \ + else if (CODE == '?'); \ + else if (GET_CODE (X) == REG) \ + fprintf (FILE, "%s", reg_names[REGNO (X)]); \ + else if (GET_CODE (X) == MEM) \ + { \ + rtx xfoo; \ + xfoo = XEXP (X, 0); \ + switch (GET_CODE (xfoo)) \ + { \ + case MEM: \ + if (GET_CODE (XEXP (xfoo, 0)) == REG) \ + if (REGNO (XEXP (xfoo, 0)) == STACK_POINTER_REGNUM) \ + fprintf (FILE, "0(0(sp))"); \ + else fprintf (FILE, "0(0(%s))", \ + reg_names[REGNO (XEXP (xfoo, 0))]); \ + else \ + { \ + fprintf (FILE, "0("); \ + output_address (xfoo); \ + putc (')', FILE); \ + } \ + break; \ + case REG: \ + fprintf (FILE, "0(%s)", reg_names[REGNO (xfoo)]); \ + break; \ + case PRE_DEC: \ + case POST_INC: \ + fprintf (FILE, "tos"); \ + break; \ + case CONST_INT: \ + fprintf (FILE, "@%d", INTVAL (xfoo)); \ + break; \ + default: \ + output_address (xfoo); \ + break; \ + } \ + } \ + else if (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) != DImode) \ + if (GET_MODE (X) == DFmode) \ + { union { double d; int i[2]; } u; \ + u.i[0] = CONST_DOUBLE_LOW (X); u.i[1] = CONST_DOUBLE_HIGH (X); \ + fprintf (FILE, "0d%.20e", u.d); } \ + else { union { double d; int i[2]; } u; \ + u.i[0] = CONST_DOUBLE_LOW (X); u.i[1] = CONST_DOUBLE_HIGH (X); \ + fprintf (FILE, "0f%.20e", u.d); } \ + else output_addr_const (FILE, X); } + +#undef PRINT_OPERAND_ADDRESS +#define PRINT_OPERAND_ADDRESS(FILE, ADDR) print_operand_address(FILE, ADDR) diff --git a/gcc-1.40/config/tm-sparc.h b/gcc-1.40/config/tm-sparc.h new file mode 100644 index 0000000..6924a17 --- /dev/null +++ b/gcc-1.40/config/tm-sparc.h @@ -0,0 +1,1435 @@ +/* Definitions of target machine for GNU compiler, for Sun SPARC. + Copyright (C) 1988 Free Software Foundation, Inc. + Contributed by Michael Tiemann (tiemann@mcc.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 1, 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. */ + +/* Note that some other tm- files include this one and then override + many of the definitions that relate to assembler syntax. */ + +/* Specify library to handle `-a' basic block profiling. */ + +#define LIB_SPEC "%{a:/usr/lib/bb_link.o} \ +%{!p:%{!pg:-lc}}%{p:-lc_p}%{pg:-lc_p} " + +/* Provide required defaults for linker -e and -d switches. + Also, it is hard to debug with shared libraries, + so don't use them if going to debug. */ + +#define LINK_SPEC "%{!e*:-e start} -dc -dp %{g:-Bstatic} %{static:-Bstatic} %{Bstatic}" + +/* Special flags to the Sun-4 assembler when using pipe for input. */ + +#define ASM_SPEC " %{pipe:-} " + +/* Prevent error on `-dalign', `-sun4' and `-target sun4' options. */ + +#define CC1_SPEC "%{dalign:} %{sun4:} %{target:}" + +/* These compiler options take an argument. We ignore -target for now. */ + +#define WORD_SWITCH_TAKES_ARG(STR) (!strcmp (STR, "target")) + +/* Names to predefine in the preprocessor for this target machine. */ + +#define CPP_PREDEFINES "-Dsparc -Dsun -Dunix" + +/* 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 TARGET_FPU (target_flags & 1) + +/* Nonzero if we should use FUNCTION_EPILOGUE. Otherwise, we + use fast return insns, but lose some generality. */ +#define TARGET_EPILOGUE (target_flags & 2) + +/* Nonzero if we expect to be passed through the Sun + optimizing assembler. This requires us to generate + code which we otherwise would not. For example, + calls via pointers-to-functions must be output + specially because Sun assemble does not do proper flow + analysis for this case. */ +#define TARGET_SUN_ASM (target_flags & 4) + +/* Nonzero if we should do eager peepholes for conditional branch + scheduling. */ +#define TARGET_EAGER (target_flags & 8) + +/* 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", 1}, \ + {"soft-float", -1}, \ + {"epilogue", 2}, \ + {"no-epilogue", -2}, \ + {"sun-asm", 4}, \ + {"eager", 8}, \ + { "", TARGET_DEFAULT}} + +#define TARGET_DEFAULT 3 + +/* target machine storage layout */ + +/* Define this if most significant bit is lowest numbered + in instructions that operate on numbered bit-fields. */ +#define BITS_BIG_ENDIAN + +/* Define this if most significant byte of a word is the lowest numbered. */ +/* This is true on the SPARC. */ +#define BYTES_BIG_ENDIAN + +/* Define this if most significant word of a multiword number is numbered. */ +/* For SPARC we can decide arbitrarily + since there are no machine instructions for them. */ +/* #define WORDS_BIG_ENDIAN */ + +/* number of bits in an addressible 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 32 + +/* Width of a word, in units (bytes). */ +#define UNITS_PER_WORD 4 + +/* Width in bits of a pointer. + See also the macro `Pmode' defined below. */ +#define POINTER_SIZE 32 + +/* Allocation boundary (in *bits*) for storing pointers in memory. */ +#define POINTER_BOUNDARY 32 + +/* Allocation boundary (in *bits*) for storing arguments in argument list. */ +#define PARM_BOUNDARY 32 + +/* Boundary (in *bits*) on which stack pointer should be aligned. */ +#define STACK_BOUNDARY 64 + +/* Allocation boundary (in *bits*) for the code of a function. */ +#define FUNCTION_BOUNDARY 32 + +/* Alignment of field after `int : 0' in a structure. */ +#define EMPTY_FIELD_BOUNDARY 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 64 + +/* Define this if move instructions will actually fail to work + when given unaligned data. */ +#define STRICT_ALIGNMENT + +/* 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. */ +#define MAX_TEXT_ALIGN 32 + +#define SELECT_SECTION(T) \ +{ \ + if (TREE_CODE (T) == VAR_DECL) \ + { \ + if (TREE_READONLY (T) && ! TREE_VOLATILE (T) \ + && DECL_ALIGN (T) <= MAX_TEXT_ALIGN) \ + text_section (); \ + else \ + data_section (); \ + } \ + if (*tree_code_type[(int) TREE_CODE (T)] == 'c') \ + { \ + if ((TREE_CODE (T) == STRING_CST && flag_writable_strings) \ + || TYPE_ALIGN (TREE_TYPE (T)) > MAX_TEXT_ALIGN) \ + data_section (); \ + else \ + text_section (); \ + } \ +} + +/* Use text section for a constant + unless we need more alignment than that offers. */ +#define SELECT_RTX_SECTION(MODE, X) \ +{ \ + if (GET_MODE_BITSIZE (MODE) <= MAX_TEXT_ALIGN)\ + 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 fullword registers and 32 floating point registers. */ + +#define FIRST_PSEUDO_REGISTER 64 + +/* 1 for registers that have pervasive standard uses + and are not available for the register allocator. + On SPARC, this includes all the global registers + (registers r[0] through r[7]) and the callee return + address register, r[15]. */ +#define FIXED_REGISTERS \ + {1, 1, 1, 1, 1, 1, 1, 1, \ + 0, 0, 0, 0, 0, 0, 1, 1, \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 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} + + +/* 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} + +/* 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. */ +#define HARD_REGNO_NREGS(REGNO, MODE) \ + ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD) + +/* Value is 1 if hard register REGNO can hold a value of machine-mode MODE. + On SPARC, the cpu registers can hold any mode but the float registers + can only hold SFmode or DFmode. */ +#define HARD_REGNO_MODE_OK(REGNO, MODE) \ + ((REGNO) < 32 ? ((GET_MODE_SIZE (MODE) <= 4) ? 1 : ((REGNO) & 1) == 0) : \ + ((MODE) == SFmode ? 1 : (MODE) == DFmode && ((REGNO) & 1) == 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. */ +#define MODES_TIEABLE_P(MODE1, MODE2) \ + (((MODE1) == SFmode || (MODE1) == DFmode) \ + == ((MODE2) == SFmode || (MODE2) == DFmode)) + +/* 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 greater + than the contents of the stack pointer register. */ +#define STACK_POINTER_OFFSET 92 + +/* Base register for access to local variables of the function. */ +#define FRAME_POINTER_REGNUM 30 + +/* 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. */ +#define FRAME_POINTER_REQUIRED 1 + +/* Base register for access to arguments of the function. */ +#define ARG_POINTER_REGNUM 30 + +/* Register in which static-chain is passed to a function. */ +/* ??? */ +#define STATIC_CHAIN_REGNUM 1 + + +/* Functions which return large structures get the address + to place the wanted value at offset 64 from the frame. */ +#define STRUCT_VALUE_OFFSET 64 /* Used only in other #defines in this file. */ +#define STRUCT_VALUE \ + gen_rtx (MEM, Pmode, \ + gen_rtx (PLUS, SImode, stack_pointer_rtx, \ + gen_rtx (CONST_INT, VOIDmode, STRUCT_VALUE_OFFSET))) +#define STRUCT_VALUE_INCOMING \ + gen_rtx (MEM, Pmode, \ + gen_rtx (PLUS, SImode, frame_pointer_rtx, \ + gen_rtx (CONST_INT, VOIDmode, 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 two kinds of registers, general and floating point. */ + +enum reg_class { NO_REGS, GENERAL_REGS, 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", "GENERAL_REGS", "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}, {-1, 0}, {0, -1}, {-1, -1}} + +/* 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. */ + +#define REGNO_REG_CLASS(REGNO) \ + ((REGNO) >= 32 ? FP_REGS : GENERAL_REGS) + +/* The class value for index registers, and the one for base regs. */ +#define INDEX_REG_CLASS GENERAL_REGS +#define BASE_REG_CLASS GENERAL_REGS + +/* Get reg_class from a letter such as appears in the machine description. */ + +#define REG_CLASS_FROM_LETTER(C) \ + ((C) == 'f' ? FP_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. + + For SPARC, `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 the 5-bit operand of a compare insns. */ + +#define SMALL_INT(X) ((unsigned) (INTVAL (X) + 0x1000) < 0x2000) + +#define CONST_OK_FOR_LETTER_P(VALUE, C) \ + ((C) == 'I' ? (unsigned) ((VALUE) + 0x1000) < 0x2000 \ + : (C) == 'J' ? (VALUE) == 0 \ + : (C) == 'K' ? (unsigned) (VALUE) < 0x20 \ + : 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' && CONST_DOUBLE_LOW ((VALUE)) == 0 \ + && CONST_DOUBLE_HIGH ((VALUE)) == 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. */ +#define PREFERRED_RELOAD_CLASS(X,CLASS) (CLASS) + +/* 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, + except in the FP regs, where a single reg is always enough. */ +#define CLASS_MAX_NREGS(CLASS, MODE) \ + ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD) + +/* Stack layout; function entry, exit and calling. */ + +/* 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. */ +#define STARTING_FRAME_OFFSET -16 + +/* 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. + This is 64 for the ins and locals, plus 4 for the struct-return reg + if this function isn't going to use it. */ +#define FIRST_PARM_OFFSET(FNDECL) \ + (DECL_MODE (DECL_RESULT (fndecl)) == BLKmode \ + ? STRUCT_VALUE_OFFSET : STRUCT_VALUE_OFFSET + 4) + +/* Offset from top-of-stack address to location to store the + function parameter if it can't go in a register. + Addresses for following parameters are computed relative to this one. */ +#define FIRST_PARM_CALLER_OFFSET(FNDECL) \ + (STRUCT_VALUE_OFFSET + 4 - STACK_POINTER_OFFSET) + +/* When a parameter is passed in a register, stack space is still + allocated for it. */ +#define REG_PARM_STACK_SPACE + +/* Value is 1 if returning from a function call automatically + pops the arguments described by the number-of-args field in the call. + 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. */ + +#define RETURN_POPS_ARGS(FUNTYPE) 0 + +/* Some subroutine macros specific to this machine. */ +#define BASE_RETURN_VALUE_REG(MODE) \ + ((MODE) == SFmode || (MODE) == DFmode ? 32 : 8) +#define BASE_OUTGOING_VALUE_REG(MODE) \ + ((MODE) == SFmode || (MODE) == DFmode ? 32 : 24) +#define BASE_PASSING_ARG_REG(MODE) (8) +#define BASE_INCOMING_ARG_REG(MODE) (24) + +/* 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. */ + +#define FUNCTION_VALUE(VALTYPE, FUNC) \ + gen_rtx (REG, TYPE_MODE (VALTYPE), BASE_RETURN_VALUE_REG (TYPE_MODE (VALTYPE))) + +/* But the called function leaves it in the first "input" register. */ + +#define FUNCTION_OUTGOING_VALUE(VALTYPE, FUNC) \ + gen_rtx (REG, TYPE_MODE (VALTYPE), BASE_OUTGOING_VALUE_REG (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, BASE_RETURN_VALUE_REG (MODE)) + +/* 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) + +/* 1 if N is a possible register number for function argument passing. + On SPARC, these are the "output" registers. */ + +#define FUNCTION_ARG_REGNO_P(N) ((N) < 14 && (N) > 7) + +/* 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, 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. */ + +#define CUMULATIVE_ARGS int + +/* Define the number of register that can hold parameters. + This macro is used only in other macro definitions below. */ +#define NPARM_REGS 6 + +/* 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. + + On SPARC, the offset always starts at 0: the first parm reg is always + the same reg. */ + +#define INIT_CUMULATIVE_ARGS(CUM,FNTYPE) ((CUM) = 0) + +/* 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.) */ + +#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \ + ((CUM) += ((MODE) != BLKmode \ + ? (GET_MODE_SIZE (MODE) + 3) / 4 \ + : (int_size_in_bytes (TYPE) + 3) / 4)) + +/* 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). */ + +/* On SPARC 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. */ + +#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \ +((CUM) < NPARM_REGS \ + && ((TYPE)==0 || ! TREE_ADDRESSABLE ((tree)(TYPE))) \ + && ((MODE) != BLKmode || (TYPE_ALIGN ((TYPE)) % 32 == 0)) \ + ? gen_rtx (REG, (MODE), BASE_PASSING_ARG_REG (MODE) + (CUM)) : 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) \ +((CUM) < NPARM_REGS \ + && ((TYPE)==0 || ! TREE_ADDRESSABLE ((tree)(TYPE))) \ + && ((MODE) != BLKmode || (TYPE_ALIGN ((TYPE)) % 32 == 0)) \ + ? gen_rtx (REG, (MODE), BASE_INCOMING_ARG_REG (MODE) + (CUM)) : 0) + +/* 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 the Sparc. */ + +#define FUNCTION_ARG_PARTIAL_NREGS(CUM, MODE, TYPE, NAMED) \ + (((CUM) < NPARM_REGS \ + && ((TYPE)==0 || ! TREE_ADDRESSABLE ((tree)(TYPE))) \ + && ((MODE) != BLKmode || (TYPE_ALIGN ((TYPE)) % 32 == 0)) \ + && ((CUM) \ + + ((MODE) == BLKmode \ + ? (int_size_in_bytes (TYPE) + 3) / 4 \ + : (GET_MODE_SIZE (MODE) + 3) / 4)) - NPARM_REGS > 0) \ + ? (NPARM_REGS - (CUM)) \ + : 0) + +/* Output the label for a function definition. */ + +#define ASM_DECLARE_FUNCTION_NAME(FILE, NAME, DECL) \ +{ \ + extern tree double_type_node, float_type_node; \ + if (TREE_TYPE (DECL) == float_type_node) \ + fprintf (FILE, "\t.proc 6\n"); \ + else if (TREE_TYPE (DECL) == double_type_node) \ + fprintf (FILE, "\t.proc 7\n"); \ + else if (TREE_TYPE (DECL) == void_type_node) \ + fprintf (FILE, "\t.proc 0\n"); \ + else fprintf (FILE, "\t.proc 1\n"); \ + ASM_OUTPUT_LABEL (FILE, NAME); \ +} + +/* 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. Currently we do this only if it touches + the "output" registers. The "local" and "input" registers + are off limits. It might be better to allow one such register + to go to the stack, but I doubt it. */ + +#define FUNCTION_PROLOGUE(FILE, SIZE) \ +{ \ + extern char call_used_regs[]; \ + extern int current_function_pretend_args_size; \ + extern int frame_pointer_needed; \ + int fsize = (((SIZE) + 7 - STARTING_FRAME_OFFSET) & -8); \ + int actual_fsize; \ + int n_fregs = 0, i; \ + int n_iregs = 64; \ + for (i = 32; i < FIRST_PSEUDO_REGISTER; i++) \ + if (regs_ever_live[i] && ! call_used_regs[i]) \ + n_fregs++; \ + for (i = 16; i < 32; i++) \ + if (regs_ever_live[i]) { n_iregs = 96; break; } \ + fprintf (FILE, "\t!#PROLOGUE# 0\n"); \ + actual_fsize = fsize + n_iregs + (n_fregs*4+7 & -8); \ + fsize += current_function_pretend_args_size+7 & -8; \ + actual_fsize += current_function_pretend_args_size+7 & -8; \ + if (actual_fsize < 4096) \ + fprintf (FILE, "\tsave %%sp,-%d,%%sp\n", actual_fsize); \ + else \ + { \ + fprintf (FILE, "\tsethi %%hi(0x%x),%%g1\n\tadd %%g1,%%lo(0x%x),%%g1\n", \ + -actual_fsize, -actual_fsize); \ + fprintf (FILE, "\tsave %%sp,%%g1,%%sp\n"); \ + } \ + fprintf (FILE, "\t!#PROLOGUE# 1\n"); \ + if (n_fregs) \ + { \ + for (i = 32, n_fregs = 0; i < FIRST_PSEUDO_REGISTER; i++) \ + if (regs_ever_live[i] && ! call_used_regs[i]) \ + { \ + if (regs_ever_live[i+1] && ! call_used_regs[i+1]) \ + fprintf (FILE, "\tstd %s,[%%sp+0x%x]\n", \ + reg_names[i], n_iregs + 4 * n_fregs), \ + n_fregs += 2, i += 1; \ + else \ + fprintf (FILE, "\tstf %s,[%%sp+0x%x]\n", \ + reg_names[i], n_iregs + 4 * n_fregs++); \ + } \ + } \ + if (regs_ever_live[32]) \ + fprintf (FILE, "\tst %s,[%%fp-16]\n\tst %s,[%%fp-12]\n", \ + reg_names[0], reg_names[0]); \ +} + +/* Output assembler code to FILE to increment profiler label # LABELNO + for profiling a function entry. */ + +#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. */ + +#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\tadd %%o0,%%lo(LPBX0),%%o0\n\tcall ___bb_init_func\n\tnop\nLPY%d:\n", \ + (LABELNO), (LABELNO)) + +/* Output assembler code to FILE to increment the entry-count for + the BLOCKNO'th basic block in this source file. */ + +#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. */ \ +} + +/* 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 may_call_alloca; +extern int current_function_pretend_args_size; + +#define EXIT_IGNORE_STACK \ + (get_frame_size () != 0 \ + || may_call_alloca || current_function_pretend_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) \ +{ \ + extern char call_used_regs[]; \ + extern int may_call_alloca; \ + extern int current_function_pretend_args_size; \ + extern int max_pending_stack_adjust; \ + extern int frame_pointer_needed; \ + int fsize = (((SIZE) + 7 - STARTING_FRAME_OFFSET) & -8); \ + int actual_fsize; \ + int n_fregs = 0, i; \ + int n_iregs = 64; \ + for (i = 32, n_fregs = 0; i < FIRST_PSEUDO_REGISTER; i++) \ + if (regs_ever_live[i] && ! call_used_regs[i]) \ + n_fregs++; \ + for (i = 16; i < 32; i++) \ + if (regs_ever_live[i]) { n_iregs = 96; break; } \ + actual_fsize = fsize + n_iregs + (n_fregs*4+7 & -8); \ + actual_fsize += current_function_pretend_args_size+7 & -8; \ + fsize += current_function_pretend_args_size+7 & -8; \ + if (n_fregs) \ + { \ + char *base; \ + int offset; \ + if (fsize < 4096) \ + { base = "%fp"; offset = n_iregs - actual_fsize; } \ + else \ + { base = "%g1"; offset = n_iregs; \ + if (fsize < 4096) \ + fprintf (FILE, "sethi %%hi(0x%x),%%g1\n\tadd %%g1,%%lo(0x%x),%%g1\n\tadd %%fp,%%g1,%%g1\n", -actual_fsize, -actual_fsize);\ + } \ + for (i = 32, n_fregs = 0; i < FIRST_PSEUDO_REGISTER; i++) \ + 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_fregs, \ + reg_names[i]), \ + n_fregs += 2, i += 1; \ + else \ + fprintf (FILE, "\tldf [%s%+d],%s\n", \ + base, offset + 4 * n_fregs++, \ + reg_names[i]); \ + } \ + } \ + fprintf (FILE, "\tret\n\trestore\n"); \ +} + +/* If the memory address ADDR is relative to the frame pointer, + correct it to be relative to the stack pointer instead. + This is for when we don't use a frame pointer. + ADDR should be a variable name. */ + +#define FIX_FRAME_POINTER_ADDRESS(ADDR,DEPTH) \ +{ int offset = -1; \ + rtx regs = stack_pointer_rtx; \ + if (ADDR == frame_pointer_rtx) \ + offset = 0; \ + else if (GET_CODE (ADDR) == PLUS && XEXP (ADDR, 0) == frame_pointer_rtx \ + && GET_CODE (XEXP (ADDR, 1)) == CONST_INT) \ + offset = INTVAL (XEXP (ADDR, 1)); \ + else if (GET_CODE (ADDR) == PLUS && XEXP (ADDR, 0) == frame_pointer_rtx) \ + { rtx other_reg = XEXP (ADDR, 1); \ + offset = 0; \ + regs = gen_rtx (PLUS, Pmode, stack_pointer_rtx, other_reg); } \ + else if (GET_CODE (ADDR) == PLUS && XEXP (ADDR, 1) == frame_pointer_rtx) \ + { rtx other_reg = XEXP (ADDR, 0); \ + offset = 0; \ + regs = gen_rtx (PLUS, Pmode, stack_pointer_rtx, other_reg); } \ + if (offset >= 0) \ + { int regno; \ + extern char call_used_regs[]; \ + for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + offset += 4; \ + offset -= 4; \ + ADDR = plus_constant (regs, offset + (DEPTH)); } } + +/* 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] < 32) +#define REGNO_OK_FOR_BASE_P(REGNO) \ +((REGNO) < 32 || (unsigned) reg_renumber[REGNO] < 32) +#define REGNO_OK_FOR_FP_P(REGNO) \ +(((REGNO) ^ 0x20) < 32 || (unsigned) (reg_renumber[REGNO] ^ 0x20) < 32) + +/* 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))) + +/* 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. */ + +#define CONSTANT_ADDRESS_P(X) CONSTANT_P (X) + +/* Nonzero if the constant value X is a legitimate general operand. + It is given that X satisfies CONSTANT_P or is a CONST_DOUBLE. + + Anything but a CONST_DOUBLE can be made to work. */ + +#define LEGITIMATE_CONSTANT_P(X) \ + (GET_CODE (X) != CONST_DOUBLE) + +/* 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. */ + +#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 >= 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 >= 32) + +#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)) + +#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. + But we can treat a SYMBOL_REF as legitimate if it is part of this + function's constant-pool, because such addresses can actually + be output as REG+SMALLINT. + + Try making SYMBOL_REF (and other things which are CONSTANT_ADDRESS_P) + a legitimate address, regardless. Because the only insns which can use + memory are load or store insns, the added hair in the machine description + is not that bad. It should also speed up the compiler by halving the number + of insns it must manage for each (MEM (SYMBOL_REF ...)) involved. */ + +#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \ +{ if (GET_CODE (X) == REG) \ + { if (REG_OK_FOR_BASE_P (X)) goto ADDR; } \ + else if (GET_CODE (X) == PLUS) \ + { \ + if (GET_CODE (XEXP (X, 0)) == REG \ + && REG_OK_FOR_BASE_P (XEXP (X, 0))) \ + { \ + if (GET_CODE (XEXP (X, 1)) == REG \ + && REG_OK_FOR_INDEX_P (XEXP (X, 1))) \ + goto ADDR; \ + if (GET_CODE (XEXP (X, 1)) == CONST_INT \ + && INTVAL (XEXP (X, 1)) >= -0x1000 \ + && INTVAL (XEXP (X, 1)) < 0x1000) \ + goto ADDR; \ + } \ + else if (GET_CODE (XEXP (X, 1)) == REG \ + && REG_OK_FOR_BASE_P (XEXP (X, 1))) \ + { \ + if (GET_CODE (XEXP (X, 0)) == REG \ + && REG_OK_FOR_INDEX_P (XEXP (X, 0))) \ + goto ADDR; \ + if (GET_CODE (XEXP (X, 0)) == CONST_INT \ + && INTVAL (XEXP (X, 0)) >= -0x1000 \ + && INTVAL (XEXP (X, 0)) < 0x1000) \ + goto ADDR; \ + } \ + } \ + else if (CONSTANT_ADDRESS_P (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. */ + +#define LEGITIMIZE_ADDRESS(X,OLDX,MODE,WIN) \ +{ if (GET_CODE (X) == PLUS && CONSTANT_ADDRESS_P (XEXP (X, 1))) \ + (X) = gen_rtx (PLUS, SImode, XEXP (X, 0), \ + copy_to_mode_reg (SImode, XEXP (X, 1))); \ + if (GET_CODE (X) == PLUS && CONSTANT_ADDRESS_P (XEXP (X, 0))) \ + (X) = gen_rtx (PLUS, SImode, XEXP (X, 1), \ + copy_to_mode_reg (SImode, XEXP (X, 0))); \ + if (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 0)) == MULT) \ + (X) = gen_rtx (PLUS, SImode, XEXP (X, 1), \ + force_operand (XEXP (X, 0), 0)); \ + if (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 1)) == MULT) \ + (X) = gen_rtx (PLUS, SImode, XEXP (X, 0), \ + force_operand (XEXP (X, 1), 0)); \ + if (GET_CODE (x) == SYMBOL_REF) \ + (X) = copy_to_reg (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) + +/* 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. + Do not define this if the table should contain absolute addresses. */ +/* #define CASE_VECTOR_PC_RELATIVE */ + +/* 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 4 + +/* Nonzero if access to memory by bytes is slow and undesirable. */ +#define SLOW_BYTE_ACCESS 0 + +/* 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 if shifts truncate the shift count + which implies one can omit a sign-extension or zero-extension + of a shift count. */ +#define SHIFT_COUNT_TRUNCATED + +/* 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 SImode + +/* 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 + +/* 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" +#define MULSI3_LIBCALL "*.mul" +#define UMULSI3_LIBCALL "*.umul" + +/* 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) \ + case CONST_INT: \ + if (INTVAL (RTX) < 0x1000 && INTVAL (RTX) >= -0x1000) return 0; \ + case CONST: \ + case LABEL_REF: \ + case SYMBOL_REF: \ + return 2; \ + case CONST_DOUBLE: \ + return 4; + +/* Tell final.c how to eliminate redundant test instructions. */ + +/* Here we define machine-dependent flags and fields in cc_status + (see `conditions.h'). */ + +/* This holds the value sourcing %hi(%g1). We keep this info + around so that mem/mem ops, such as increment and decrement, + etc, can be performed reasonably. */ +#define CC_STATUS_MDEP rtx + +/* Nonzero if the results of the previous comparison are + in the floating point condition code register. */ + +#define CC_IN_FCCR 04000 + +/* Nonzero if the results of the previous comparison are + int the coprocessor's condition code register. */ + +#define CC_IN_CCCR 010000 + +/* Nonzero if we know (easily) that floating point register f0 + (f1) contains the value 0. */ +#define CC_F0_IS_0 020000 +#define CC_F1_IS_0 040000 + +/* Nonzero if we know the value of %hi(%g1). */ +#define CC_KNOW_HI_G1 0100000 + +#define CC_STATUS_MDEP_INIT (cc_status.mdep = 0) + +/* Store in cc_status the expressions + that the condition codes will describe + after execution of an instruction whose pattern is EXP. + Do not alter them if the instruction would not alter the cc's. */ + +#define NOTICE_UPDATE_CC(EXP, INSN) \ +{ if (GET_CODE (EXP) == SET) \ + { if (SET_DEST (EXP) == cc0_rtx) \ + { cc_status.flags = 0; \ + cc_status.value1 = SET_DEST (EXP); \ + cc_status.value2 = SET_SRC (EXP); } \ + else if (GET_CODE (SET_SRC (EXP)) == CALL) \ + { CC_STATUS_INIT; } \ + else if (GET_CODE (SET_DEST (EXP)) == REG) \ + { 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; \ + } \ + else if (GET_CODE (SET_DEST (EXP)) == MEM) \ + { rtx x = cc_status.mdep; int know = cc_status.flags & CC_KNOW_HI_G1; \ + CC_STATUS_INIT; \ + if (x && know) \ + { cc_status.mdep = x; cc_status.flags |= CC_KNOW_HI_G1; } \ + } \ + } \ + else if (GET_CODE (EXP) == PARALLEL \ + && GET_CODE (XVECEXP (EXP, 0, 0)) == SET) \ + { if (SET_DEST (XVECEXP (EXP, 0, 0)) == cc0_rtx) \ + { cc_status.flags = 0; \ + cc_status.value1 = SET_DEST (XVECEXP (EXP, 0, 0)); \ + cc_status.value2 = SET_SRC (XVECEXP (EXP, 0, 0)); \ + } \ + else if (GET_CODE (SET_SRC (XVECEXP (EXP, 0, 0))) == CALL) \ + { /* all bets are off */ CC_STATUS_INIT; } \ + else if (GET_CODE (SET_DEST (XVECEXP (EXP, 0, 0))) == REG) \ + { if (cc_status.value1 \ + && reg_overlap_mentioned_p (SET_DEST (XVECEXP (EXP, 0, 0)), cc_status.value1)) \ + cc_status.value1 = 0; \ + if (cc_status.value2 \ + && reg_overlap_mentioned_p (SET_DEST (XVECEXP (EXP, 0, 0)), cc_status.value2)) \ + cc_status.value2 = 0; \ + } \ + else if (GET_CODE (SET_DEST (XVECEXP (EXP, 0, 0))) == MEM) \ + { rtx x = cc_status.mdep; int know = cc_status.flags & CC_KNOW_HI_G1; \ + CC_STATUS_INIT; \ + if (x && know) \ + { cc_status.mdep = x; cc_status.flags |= CC_KNOW_HI_G1; } \ + } \ + } \ + else if (GET_CODE (EXP) == PARALLEL) \ + /* insn-peep has changed this insn beyond recognition + by NOTICE_UPDATE_CC. However, we know it is either + a call or a branch with a delay slot filled, so we can + give up on knowing condition codes in any case. */ \ + { CC_STATUS_INIT; } \ + else if (GET_CODE (EXP) == CALL) \ + { /* all bets are off */ CC_STATUS_INIT; } \ +} + +#define OUTPUT_JUMP(NORMAL, NO_OV, FLOAT) \ +{ if (cc_prev_status.flags & CC_IN_FCCR) \ + return FLOAT; \ + if (cc_prev_status.flags & CC_NO_OVERFLOW) \ + return NO_OV; \ + return NORMAL; } + +/* Control the assembler format that we output. */ + +/* Output at beginning of assembler file. */ + +#define ASM_FILE_START(file) + +/* 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 "" + +/* 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"} \ + +/* How to renumber registers for dbx and gdb. */ + +#define DBX_REGISTER_NUMBER(REGNO) (REGNO) + +/* On Sun 4, this limit is 2048. We use 1500 to be safe, + since the length can run past this up to a continuation point. */ +#define DBX_CONTIN_LENGTH 1500 + +/* 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 (".global ", 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. */ + +#define ASM_OUTPUT_LABELREF(FILE,NAME) \ + fprintf (FILE, "_%s", NAME) + +/* 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) \ + 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%d", PREFIX, NUM) + +/* This is how to output an assembler line defining a `double' constant. */ + +#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \ + (isinf ((VALUE)) \ + ? fprintf (FILE, "\t.double 0r%s99e999\n", ((VALUE) > 0 ? "" : "-")) \ + : fprintf (FILE, "\t.double 0r%.20e\n", (VALUE))) + +/* This is how to output an assembler line defining a `float' constant. */ + +#define ASM_OUTPUT_FLOAT(FILE,VALUE) \ + (isinf ((VALUE)) \ + ? fprintf (FILE, "\t.single 0r%s99e999\n", ((VALUE) > 0 ? "" : "-")) \ + : fprintf (FILE, "\t.single 0r%.20e\n", (VALUE))) + +/* This is how to output an assembler line defining an `int' constant. */ + +#define ASM_OUTPUT_INT(FILE,VALUE) \ +( fprintf (FILE, "\t.word "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +/* Likewise for `char' and `short' constants. */ + +#define ASM_OUTPUT_SHORT(FILE,VALUE) \ +( fprintf (FILE, "\t.half "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +#define ASM_OUTPUT_CHAR(FILE,VALUE) \ +( fprintf (FILE, "\t.byte "), \ + 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.byte 0x%x\n", (VALUE)) + +/* This is how to output an element of a case-vector that is absolute. */ + +#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \ + fprintf (FILE, "\t.word L%d\n", VALUE) + +/* This is how to output an element of a case-vector that is relative. + (SPARC does not use such vectors, + but we must define this macro anyway.) */ + +#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, VALUE, REL) \ + fprintf (FILE, "\t.word L%d-L%d\n", VALUE, REL) + +/* 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 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 (".global ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fputs ("\n.common ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%u,\"bss\"\n", (ROUNDED))) + +/* This says how to output an assembler line + to define a local common symbol. */ + +#define ASM_OUTPUT_LOCAL(FILE, NAME, SIZE, ROUNDED) \ +( fputs ("\n.reserve ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%u,\"bss\"\n", (ROUNDED))) + +/* 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 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 + +/* 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. + + On SPARC, the CODE can be `r', meaning this is a register-only operand + and an immediate zero should be represented as `r0'. + It can also be `m', meaning that X is a memory reference but print + its address as a non-memory operand. + + Codes C, N, F, I, and U are used for printing the opcodes of conditional + branches. C prints the opcode for a given condition; N the negated opcode. + F prints the negated floating point opcode (different because of nans). + I prints the opcode that ignores the overflow bit, and U its negation. */ + +#define PRINT_OPERAND(FILE, X, CODE) \ +{ if (GET_CODE (X) == REG) \ + fprintf (FILE, "%s", reg_names[REGNO (X)]); \ + else if ((CODE) == 'm') \ + output_address (XEXP (X, 0)); \ + else if (GET_CODE (X) == MEM) \ + { \ + fputc ('[', FILE); \ + output_address (XEXP (X, 0)); \ + fputc (']', FILE); \ + } \ + else if (GET_CODE (X) == CONST_DOUBLE) \ + abort (); \ + else if ((CODE) == 'r' && (X) == const0_rtx) \ + fprintf (FILE, "%%g0"); \ + else if ((CODE) == 'C') switch (GET_CODE (X)) \ + { \ + case EQ: fputs ("e", FILE); break; \ + case NE: fputs ("ne", FILE); break; \ + case GT: fputs ("g", FILE); break; \ + case GE: fputs ("ge", FILE); break; \ + case LT: fputs ("l", FILE); break; \ + case LE: fputs ("le", FILE); break; \ + case GTU: fputs ("gu", FILE); break; \ + case GEU: fputs ("geu", FILE); break; \ + case LTU: fputs ("lu", FILE); break; \ + case LEU: fputs ("leu", FILE); break; \ + } \ + else if ((CODE) == 'I') switch (GET_CODE (X)) \ + { \ + case EQ: fputs ("e", FILE); break; \ + case NE: fputs ("ne", FILE); break; \ + case GE: fputs ("pos", FILE); break; \ + case LT: fputs ("neg", FILE); break; \ + default: \ + abort (); \ + } \ + else if ((CODE) == 'U') switch (GET_CODE (X)) \ + { \ + case EQ: fputs ("ne", FILE); break; \ + case NE: fputs ("e", FILE); break; \ + case GE: fputs ("neg", FILE); break; \ + case LT: fputs ("pos", FILE); break; \ + default: \ + abort (); \ + } \ + else if ((CODE) == 'N') switch (GET_CODE (X)) \ + { \ + case EQ: fputs ("ne", FILE); break; \ + case NE: fputs ("e", FILE); break; \ + case GT: fputs ("le", FILE); break; \ + case GE: fputs ("l", FILE); break; \ + case LT: fputs ("ge", FILE); break; \ + case LE: fputs ("g", FILE); break; \ + case GTU: fputs ("leu", FILE); break; \ + case GEU: fputs ("lu", FILE); break; \ + case LTU: fputs ("geu", FILE); break; \ + case LEU: fputs ("gu", FILE); break; \ + } \ + else if ((CODE) == 'F') switch (GET_CODE (X)) \ + { \ + case EQ: fputs ("ne", FILE); break; \ + case NE: fputs ("e", FILE); break; \ + case GT: fputs ("ule", FILE); break; \ + case GE: fputs ("ul", FILE); break; \ + case LT: fputs ("uge", FILE); break; \ + case LE: fputs ("ug", FILE); break; \ + default: abort (); \ + } \ + else { output_addr_const (FILE, X); }} + +/* 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) \ + { \ + fprintf (FILE, "%s", reg_names[REGNO (addr)]); \ + } \ + 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); \ + fprintf (FILE, "%s", reg_names[REGNO (base)]); \ + if (index == 0) \ + fprintf (FILE, "%+d", offset); \ + else \ + fprintf (FILE, "+%s", reg_names[REGNO (index)]); \ + } \ + else \ + { \ + output_addr_const (FILE, addr); \ + } \ +} + diff --git a/gcc-1.40/config/tm-spur.h b/gcc-1.40/config/tm-spur.h new file mode 100644 index 0000000..485b07f --- /dev/null +++ b/gcc-1.40/config/tm-spur.h @@ -0,0 +1,1033 @@ +/* Definitions of target machine for GNU compiler, for SPUR chip. + Copyright (C) 1988 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 1, 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. */ + + +/* Note that some other tm- files include this one and then override + many of the definitions that relate to assembler syntax. */ + + +/* Names to predefine in the preprocessor for this target machine. */ + +#define CPP_PREDEFINES "-Dspur" + +/* Print subsidiary information on the compiler version in use. */ +#define TARGET_VERSION fprintf (stderr, " (spur)"); + +/* Run-time compilation parameters selecting different hardware subsets. + + On the SPUR, we don't yet need any. */ + +extern int target_flags; + +/* Nonzero if we should generate code to use the fpu. */ +#define TARGET_FPU (target_flags & 1) + +/* Nonzero if we should expand constant shifts into series of shift + instructions. */ +#define TARGET_EXPAND_SHIFTS (target_flags & 2) + +/* Nonzero if we should generate long jumps for compares. */ +#define TARGET_LONG_JUMPS (target_flags & 4) + +/* 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", 1}, \ + {"soft-float", -1}, \ + {"expand-shifts", 2}, \ + {"lib-shifts", -2}, \ + {"long-jumps", 4}, \ + {"short-jumps", -4}, \ + { "", TARGET_DEFAULT}} + +#define TARGET_DEFAULT 0 + +/* target machine storage layout */ + +/* Define this if most significant bit is lowest numbered + in instructions that operate on numbered bit-fields. + This is a moot question on the SPUR due to the lack of bit-field insns. */ +/* #define BITS_BIG_ENDIAN */ + +/* Define this if most significant byte of a word is the lowest numbered. */ +/* That is not true on SPUR. */ +/* #define BYTES_BIG_ENDIAN */ + +/* Define this if most significant word of a multiword number is numbered. */ +/* For SPUR we can decide arbitrarily + since there are no machine instructions for them. */ +/* #define WORDS_BIG_ENDIAN */ + +/* number of bits in an addressible 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 32 + +/* Width of a word, in units (bytes). */ +#define UNITS_PER_WORD 4 + +/* Width in bits of a pointer. + See also the macro `Pmode' defined below. */ +#define POINTER_SIZE 32 + +/* Allocation boundary (in *bits*) for storing pointers in memory. */ +#define POINTER_BOUNDARY 32 + +/* Allocation boundary (in *bits*) for storing arguments in argument list. */ +#define PARM_BOUNDARY 64 + +/* Boundary (in *bits*) on which stack pointer should be aligned. */ +#define STACK_BOUNDARY 64 + +/* Allocation boundary (in *bits*) for the code of a function. */ +#define FUNCTION_BOUNDARY 32 + +/* Alignment of field after `int : 0' in a structure. */ +#define EMPTY_FIELD_BOUNDARY 32 + +/* Every structure's size must be a multiple of this. */ +#define STRUCTURE_SIZE_BOUNDARY 32 + +/* No data type wants to be aligned rounder than this. */ +#define BIGGEST_ALIGNMENT 64 + +/* Define this if move instructions will actually fail to work + when given unaligned data. */ +#define STRICT_ALIGNMENT + +/* 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. + + SPUR has 32 fullword registers and 15 floating point registers. */ + +#define FIRST_PSEUDO_REGISTER 47 + +/* 1 for registers that have pervasive standard uses + and are not available for the register allocator. + On SPUR, this includes all the global registers + and the callee return address register. */ +#define FIXED_REGISTERS \ + {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \ + 1, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, \ + 1, 0, 0, 0, 0, 0, \ + 1, 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, 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, 0, 0, 0, 0, 0, 0, 0, 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 SPUR, ordinary registers hold 32 bits worth; + a single floating point register is always enough for + anything that can be stored in them at all. */ +#define HARD_REGNO_NREGS(REGNO, MODE) \ + ((REGNO) >= 32 ? 1 \ + : ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)) + +/* Value is 1 if hard register REGNO can hold a value of machine-mode MODE. + On SPUR, the cpu registers can hold any mode but the float registers + can hold only SFmode or DFmode. And they can't hold anything if use + of hardware floating point is disabled. */ +#define HARD_REGNO_MODE_OK(REGNO, MODE) \ + (((REGNO) < 32 && (GET_MODE_SIZE (MODE) <= 4 || (REGNO) < 31)) \ + || (TARGET_FPU && ((MODE) == SFmode || (MODE) == DFmode))) + +/* 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) == SFmode || (MODE1) == DFmode) \ + == ((MODE2) == SFmode || (MODE2) == DFmode)) + +/* Specify the registers used for certain standard purposes. + The values of these macros are register numbers. */ + +/* SPUR 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 4 + +/* Base register for access to local variables of the function. */ +#define FRAME_POINTER_REGNUM 25 + +/* 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. */ +#define FRAME_POINTER_REQUIRED 1 + +/* Base register for access to arguments of the function. */ +#define ARG_POINTER_REGNUM 25 + +/* Register in which static-chain is passed to a function. */ +/* ??? */ +#define STATIC_CHAIN_REGNUM 8 + +/* Register in which address to store a structure value + is passed to a function. */ +#define STRUCT_VALUE_REGNUM 27 +#define STRUCT_VALUE_INCOMING_REGNUM 11 + +/* 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 68000 has two kinds of registers, hence four classes. */ + +enum reg_class { NO_REGS, GENERAL_REGS, 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", "GENERAL_REGS", "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}, {-1, 0}, {0, 0x7fff}, {-1, 0x7fff}} + +/* 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. */ + +#define REGNO_REG_CLASS(REGNO) \ + ((REGNO) >= 32 ? FP_REGS : GENERAL_REGS) + +/* The class value for index registers, and the one for base regs. */ +#define INDEX_REG_CLASS GENERAL_REGS +#define BASE_REG_CLASS GENERAL_REGS + +/* Get reg_class from a letter such as appears in the machine description. */ + +#define REG_CLASS_FROM_LETTER(C) \ + ((C) == 'f' ? FP_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. + + For SPUR, `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 the 5-bit operand of a compare insns. */ + +#define CONST_OK_FOR_LETTER_P(VALUE, C) \ + ((C) == 'I' ? (unsigned) ((VALUE) + 0x2000) < 0x4000 \ + : (C) == 'J' ? (VALUE) == 0 \ + : (C) == 'K' ? (unsigned) (VALUE) < 0x20 \ + : 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' && CONST_DOUBLE_LOW ((VALUE)) == 0 \ + && CONST_DOUBLE_HIGH ((VALUE)) == 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. */ +#define PREFERRED_RELOAD_CLASS(X,CLASS) (CLASS) + +/* Return the maximum number of consecutive registers + needed to represent mode MODE in a register of class CLASS. */ +/* On SPUR, this is the size of MODE in words, + except in the FP regs, where a single reg is always enough. */ +#define CLASS_MAX_NREGS(CLASS, MODE) \ + ((CLASS) == FP_REGS ? 1 \ + : ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)) + +/* Stack layout; function entry, exit and calling. */ + +/* 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. */ +#define STARTING_FRAME_OFFSET 0 + +/* If we generate an insn to push BYTES bytes, + this says how many the stack pointer really advances by. + On SPUR, don't define this because there are no push insns. */ +/* #define PUSH_ROUNDING(BYTES) */ + +/* Offset of first parameter from the argument pointer register value. */ +#define FIRST_PARM_OFFSET(FNDECL) 0 + +/* Value is 1 if returning from a function call automatically + pops the arguments described by the number-of-args field in the call. + 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. */ + +#define RETURN_POPS_ARGS(FUNTYPE) 0 + +/* 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 SPUR the value is found in the second "output" register. */ + +#define FUNCTION_VALUE(VALTYPE, FUNC) \ + gen_rtx (REG, TYPE_MODE (VALTYPE), 27) + +/* But the called function leaves it in the second "input" register. */ + +#define FUNCTION_OUTGOING_VALUE(VALTYPE, FUNC) \ + gen_rtx (REG, TYPE_MODE (VALTYPE), 11) + +/* 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, 27) + +/* 1 if N is a possible register number for a function value + as seen by the caller. + On SPUR, the first "output" reg is the only register thus used. */ + +#define FUNCTION_VALUE_REGNO_P(N) ((N) == 27) + +/* 1 if N is a possible register number for function argument passing. + On SPUR, these are the "output" registers. */ + +#define FUNCTION_ARG_REGNO_P(N) ((N) < 32 && (N) > 26) + +/* 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 SPUR, 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 5 or more means all following args should go on the stack. */ + +#define CUMULATIVE_ARGS int + +/* 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. + + On SPUR, the offset normally starts at 0, but starts at 4 bytes + when the function gets a structure-value-address as an + invisible first argument. */ + +#define INIT_CUMULATIVE_ARGS(CUM,FNTYPE) \ + ((CUM) = ((FNTYPE) != 0 && aggregate_value_p ((FNTYPE)))) + +/* 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.) */ + +#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \ + ((CUM) += ((MODE) != BLKmode \ + ? (GET_MODE_SIZE (MODE) + 3) / 4 \ + : (int_size_in_bytes (TYPE) + 3) / 4)) + +/* 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). */ + +/* On SPUR the first five words of args are normally in registers + and the rest are pushed. But any arg that won't entirely fit in regs + is pushed. Also, any non-word-aligned structure is pushed. */ + +#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \ +(5 >= ((CUM) \ + + ((MODE) == BLKmode \ + ? (int_size_in_bytes (TYPE) + 3) / 4 \ + : (GET_MODE_SIZE (MODE) + 3) / 4)) \ + && ((MODE) != BLKmode || (TYPE_ALIGN ((TYPE)) % 32 == 0)) \ + ? gen_rtx (REG, (MODE), 27 + (CUM)) \ + : 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) \ +(5 >= ((CUM) \ + + ((MODE) == BLKmode \ + ? (int_size_in_bytes (TYPE) + 3) / 4 \ + : (GET_MODE_SIZE (MODE) + 3) / 4)) \ + && ((MODE) != BLKmode || (TYPE_ALIGN ((TYPE)) % 32 == 0)) \ + ? gen_rtx (REG, (MODE), 11 + (CUM)) \ + : 0) + +/* 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. */ + +#define FUNCTION_ARG_PARTIAL_NREGS(CUM, MODE, TYPE, NAMED) 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 spur, 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. */ + +#define FUNCTION_PROLOGUE(FILE, SIZE) \ +{ \ + extern char call_used_regs[]; \ + extern int current_function_pretend_args_size; \ + int fsize = ((SIZE) + 7) & ~7; \ + int nregs, i, fp_used = 0; \ + for (i = 32, nregs = 0; i < FIRST_PSEUDO_REGISTER; i++) \ + { \ + if (regs_ever_live[i] && ! call_used_regs[i]) \ + nregs++; \ + if (regs_ever_live[i]) fp_used = 1; \ + } \ + if (fp_used) fsize += 8; \ + fprintf (FILE, "0:\trd_special r24,pc\n"); \ + fprintf (FILE, "\tand r24,r24,$~0x3\n"); \ + fprintf (FILE, "\tadd_nt r25,r4,$%d\n", \ + - current_function_pretend_args_size); \ + if (fsize + nregs != 0 || current_function_pretend_args_size > 0)\ + { \ + int n = - fsize - nregs * 16; \ + if (n >= -8192) \ + fprintf (FILE, "\tadd_nt r4,r25,$%d\n", n); \ + else \ + { \ + fprintf (FILE, "\tadd_nt r4,r25,$-8192\n"); \ + n += 8192; \ + while (n < -8192) \ + fprintf (FILE, "\tadd_nt r4,r4,$-8192\n"), n += 8192; \ + if (n != 0) \ + fprintf (FILE, "\tadd_nt r4,r4,$%d\n", n); \ + } \ + } \ + for (i = 32, nregs = 0; i < FIRST_PSEUDO_REGISTER; i++) \ + if (regs_ever_live[i] && ! call_used_regs[i]) \ + { \ + fprintf (FILE, "\tst_ext1 %s,r4,$%d\n", \ + reg_names[i], 8 * nregs++); \ + fprintf (FILE, "\tst_ext2 %s,r4,$%d\n", \ + reg_names[i], 8 * nregs++); \ + } \ +} + +/* Output assembler code to FILE to increment profiler label # LABELNO + for profiling a function entry. */ + +#define FUNCTION_PROFILER(FILE, LABELNO) \ + abort (); + +/* 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 may_call_alloca; +extern int current_function_pretend_args_size; + +#define EXIT_IGNORE_STACK \ + (get_frame_size () != 0 \ + || may_call_alloca || current_function_pretend_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. */ + +#define FUNCTION_EPILOGUE(FILE, SIZE) \ +{ \ + extern char call_used_regs[]; \ + extern int may_call_alloca; \ + extern int current_function_pretend_args_size; \ + int fsize = ((SIZE) + 7) & ~7; \ + int nregs, i, fp_used = 0; \ + for (i = 32, nregs = 0; i < FIRST_PSEUDO_REGISTER; i++) \ + { \ + if (regs_ever_live[i] && ! call_used_regs[i]) \ + nregs++; \ + if (regs_ever_live[i]) fp_used = 1; \ + } \ + if (fp_used) fsize += 8; \ + if (nregs != 0) \ + { \ + fprintf (FILE, "\tadd_nt r4,r25,$%d\n", - fsize - nregs * 16); \ + for (i = 32, nregs = 0; i < FIRST_PSEUDO_REGISTER; i++) \ + if (regs_ever_live[i] && ! call_used_regs[i]) \ + { \ + fprintf (FILE, "\tld_ext1 %s,r4,$%d\n\tnop\n", \ + reg_names[i], 8 * nregs++); \ + fprintf (FILE, "\tld_ext2 %s,r4,$%d\n\tnop\n", \ + reg_names[i], 8 * nregs++); \ + } \ + } \ + if (fsize != 0 || nregs != 0 || may_call_alloca \ + || current_function_pretend_args_size > 0) \ + fprintf (FILE, "\tadd_nt r4,r25,$%d\n", \ + current_function_pretend_args_size); \ + fprintf (FILE, "\treturn r10,$8\n\tnop\n"); \ +} + +/* If the memory address ADDR is relative to the frame pointer, + correct it to be relative to the stack pointer instead. + This is for when we don't use a frame pointer. + ADDR should be a variable name. */ + +#define FIX_FRAME_POINTER_ADDRESS(ADDR,DEPTH) abort (); + +/* 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] < 32) +#define REGNO_OK_FOR_BASE_P(REGNO) \ +((REGNO) < 32 || (unsigned) reg_renumber[REGNO] < 32) +#define REGNO_OK_FOR_FP_P(REGNO) \ +(((REGNO) ^ 0x20) < 14 || (unsigned) (reg_renumber[REGNO] ^ 0x20) < 14) + +/* 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 SPUR, 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))) + +/* 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. */ + +#define CONSTANT_ADDRESS_P(X) CONSTANT_P (X) + +/* Nonzero if the constant value X is a legitimate general operand. + It is given that X satisfies CONSTANT_P or is a CONST_DOUBLE. */ + +#define LEGITIMATE_CONSTANT_P(X) \ + ((GET_CODE (X) == CONST_INT \ + && (unsigned) (INTVAL (X) + 0x2000) < 0x4000)\ + || (GET_CODE (X) == SYMBOL_REF && (X)->unchanging)) + +/* 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. */ + +#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 >= 14) +/* 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 >= 14) + +#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)) + +#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 SPUR, the actual legitimate addresses must be REG+SMALLINT or REG+REG. + Actually, REG+REG is not legitimate for stores, so + it is obtained only by combination on loads. + We can treat a SYMBOL_REF as legitimate if it is part of this + function's constant-pool, because such addresses can actually + be output as REG+SMALLINT. */ + +#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \ +{ if (GET_CODE (X) == REG \ + && REG_OK_FOR_BASE_P (X)) \ + goto ADDR; \ + if (GET_CODE (X) == SYMBOL_REF && (X)->unchanging) \ + goto ADDR; \ + if (GET_CODE (X) == PLUS \ + && GET_CODE (XEXP (X, 0)) == REG \ + && REG_OK_FOR_BASE_P (XEXP (X, 0))) \ + { \ + if (GET_CODE (XEXP (X, 1)) == CONST_INT \ + && INTVAL (XEXP (X, 1)) >= -0x2000 \ + && INTVAL (XEXP (X, 1)) < 0x2000) \ + 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 SPUR, change REG+N into REG+REG, and REG+(X*Y) into REG+REG. */ + +#define LEGITIMIZE_ADDRESS(X,OLDX,MODE,WIN) \ +{ if (GET_CODE (X) == PLUS && CONSTANT_ADDRESS_P (XEXP (X, 1))) \ + (X) = gen_rtx (PLUS, SImode, XEXP (X, 0), \ + copy_to_mode_reg (SImode, XEXP (X, 1))); \ + if (GET_CODE (X) == PLUS && CONSTANT_ADDRESS_P (XEXP (X, 0))) \ + (X) = gen_rtx (PLUS, SImode, XEXP (X, 1), \ + copy_to_mode_reg (SImode, XEXP (X, 0))); \ + if (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 0)) == MULT) \ + (X) = gen_rtx (PLUS, SImode, XEXP (X, 1), \ + force_operand (XEXP (X, 0), 0)); \ + if (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 1)) == MULT) \ + (X) = gen_rtx (PLUS, SImode, XEXP (X, 0), \ + force_operand (XEXP (X, 1), 0)); \ + 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 SPUR this is never true. */ + +#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR,LABEL) + +/* 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. + Do not define this if the table should contain absolute addresses. */ +/* #define CASE_VECTOR_PC_RELATIVE */ + +/* 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 0 + +/* Max number of bytes we can move from memory to memory + in one reasonably fast instruction. */ +#define MOVE_MAX 4 + +/* Nonzero if access to memory by bytes is slow and undesirable. */ +#define SLOW_BYTE_ACCESS 1 + +/* This is BSD, so it wants DBX format. */ +#define DBX_DEBUGGING_INFO + +/* Do not break .stabs pseudos into continuations. */ +#define DBX_CONTIN_LENGTH 0 + +/* Don't try to use the `x' type-cross-reference character in DBX data. + Also has the consequence of putting each struct, union or enum + into a separate .stabs, containing only cross-refs to the others. */ +#define DBX_NO_XREFS + +/* 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 SImode + +/* 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 + +/* 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) \ + case CONST_INT: \ + if (INTVAL (RTX) < 0x2000 && INTVAL (RTX) >= -0x2000) return 1; \ + case CONST: \ + case LABEL_REF: \ + case SYMBOL_REF: \ + return 2; \ + case CONST_DOUBLE: \ + return 4; + +/* Tell final.c how to eliminate redundant test instructions. */ + +/* Here we define machine-dependent flags and fields in cc_status + (see `conditions.h'). */ + +/* (None are needed on SPUR.) */ + +/* Store in cc_status the expressions + that the condition codes will describe + after execution of an instruction whose pattern is EXP. + Do not alter them if the instruction would not alter the cc's. */ + +/* The SPUR does not really have a condition code. */ + +#define NOTICE_UPDATE_CC(EXP, INSN) \ +{ CC_STATUS_INIT; } + +/* Control the assembler format that we output. */ + +/* Output at beginning of assembler file. */ + +#define ASM_FILE_START(FILE) + +/* 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 "" + +/* 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 \ +{"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", \ + "r10", "r11", "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19", \ + "r20", "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", \ + "r30", "r31", \ + "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9", \ + "f10", "f11", "f12", "f13", "f14" } + +/* How to renumber registers for dbx and gdb. */ + +#define DBX_REGISTER_NUMBER(REGNO) (REGNO) + +/* 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 (".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. */ + +#define ASM_OUTPUT_LABELREF(FILE,NAME) \ + fprintf (FILE, "_%s", NAME) + +/* 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) \ + 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%d", PREFIX, NUM) + +/* This is how to output an assembler line defining a `double' constant. */ + +#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \ + fprintf (FILE, "\t.double %.20e\n", (VALUE)) + +/* This is how to output an assembler line defining a `float' constant. */ + +#define ASM_OUTPUT_FLOAT(FILE,VALUE) \ + fprintf (FILE, "\t.single %.12e\n", (VALUE)) + +/* This is how to output an assembler line defining an `int' constant. */ + +#define ASM_OUTPUT_INT(FILE,VALUE) \ +( fprintf (FILE, "\t.long "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +/* Likewise for `char' and `short' constants. */ + +#define ASM_OUTPUT_SHORT(FILE,VALUE) \ +( fprintf (FILE, "\t.word "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +#define ASM_OUTPUT_CHAR(FILE,VALUE) \ +( fprintf (FILE, "\t.byte "), \ + 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.byte 0x%x\n", (VALUE)) + +/* This is how to output code to push a register on the stack. + It need not be very fast code. */ + +#define ASM_OUTPUT_REG_PUSH(FILE,REGNO) \ + fprintf (FILE, "\tadd_nt r4,r4,$-4\n\tst_32 %s,r4,$0\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, "\tld_32 %s,r4,$0\n\tadd_nt r4,r4,$4\n", reg_names[REGNO]) + +/* This is how to output an element of a case-vector that is absolute. */ + +#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \ + fprintf (FILE, "\t.long L%d\n", VALUE) + +/* This is how to output an element of a case-vector that is relative. + (SPUR does not use such vectors, + but we must define this macro anyway.) */ + +#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, VALUE, REL) \ + fprintf (FILE, "\t.word L%d-L%d\n", VALUE, REL) + +/* 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", (LOG)) + +#define ASM_OUTPUT_SKIP(FILE,SIZE) \ + fprintf (FILE, "\t.space %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 (".comm ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%u\n", (ROUNDED))) + +/* This says how to output an assembler line + to define a local common symbol. */ + +#define ASM_OUTPUT_LOCAL(FILE, NAME, SIZE, ROUNDED) \ +( fputs (".lcomm ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%u\n", (ROUNDED))) + +/* 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 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 + +/* 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. + + On SPUR, the CODE can be `r', meaning this is a register-only operand + and an immediate zero should be represented as `r0'. */ + +#define PRINT_OPERAND(FILE, X, CODE) \ +{ if (GET_CODE (X) == REG) \ + fprintf (FILE, "%s", reg_names[REGNO (X)]); \ + else if (GET_CODE (X) == MEM) \ + output_address (XEXP (X, 0)); \ + else if (GET_CODE (X) == CONST_DOUBLE) \ + abort (); \ + else if ((CODE) == 'r' && (X) == const0_rtx) \ + fprintf (FILE, "r0"); \ + else { putc ('$', FILE); output_addr_const (FILE, X); }} + +/* 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) \ + { \ + fprintf (FILE, "%s,$0", reg_names[REGNO (addr)]); \ + } \ + 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); \ + fprintf (FILE, "%s,", reg_names[REGNO (base)]); \ + if (index == 0) \ + fprintf (FILE, "$%d", offset); \ + else \ + fprintf (FILE, "%s,", reg_names[REGNO (index)]); \ + } \ + else \ + { \ + fprintf (FILE, "r24,$("); \ + output_addr_const (FILE, addr); \ + fprintf (FILE, "-0b)"); \ + } \ +} diff --git a/gcc-1.40/config/tm-sun2.h b/gcc-1.40/config/tm-sun2.h new file mode 100644 index 0000000..6ae8d86 --- /dev/null +++ b/gcc-1.40/config/tm-sun2.h @@ -0,0 +1,67 @@ +/* Definitions of target machine for GNU compiler. Sun 68010 version. + Copyright (C) 1987, 1988 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 1, 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 "tm-m68k.h" + +/* See tm-m68k.h. 0 means 68000 with no 68881. */ + +#define TARGET_DEFAULT 0 + +/* Define __HAVE_68881 in preprocessor only if -m68881 is specified. + This will control the use of inline 68881 insns in certain macros. + Also inform the program which CPU this is for. */ + +#define CPP_SPEC "%{m68881:-D__HAVE_68881__} \ +%{!ansi:%{m68020:-Dmc68020}%{mc68020:-Dmc68020}%{!mc68020:%{!m68020:-Dmc68010}}}" + +/* -m68020 requires special flags to the assembler. */ + +#define ASM_SPEC \ + "%{m68020:-mc68020}%{mc68020:-mc68020}%{!mc68020:%{!m68020:-mc68010}}" + +/* Names to predefine in the preprocessor for this target machine. */ + +#define CPP_PREDEFINES "-Dmc68000 -Dsun -Dunix" + +/* Prevent error on `-sun2' and `-target sun2' options. */ + +#define CC1_SPEC "%{sun2:} %{target:}" + +/* These compiler options take an argument. We ignore -target for now. */ + +#define WORD_SWITCH_TAKES_ARG(STR) (!strcmp (STR, "target")) + +/* Specify what to link with. */ + +#define LIB_SPEC "%{!p:%{!pg:-lc}}%{p:-lc_p}%{pg:-lc_p} \ +%{a:/usr/lib/bb_link.o -lc} " + +/* Alignment of field after `int : 0' in a structure. */ + +#undef EMPTY_FIELD_BOUNDARY +#define EMPTY_FIELD_BOUNDARY 16 + +/* Every structure or union's size must be a multiple of 2 bytes. */ + +#define STRUCTURE_SIZE_BOUNDARY 16 + +/* This is BSD, so it wants DBX format. */ + +#define DBX_DEBUGGING_INFO diff --git a/gcc-1.40/config/tm-sun2os4.h b/gcc-1.40/config/tm-sun2os4.h new file mode 100644 index 0000000..17b4c49 --- /dev/null +++ b/gcc-1.40/config/tm-sun2os4.h @@ -0,0 +1,57 @@ +/* Definitions of target machine for GNU compiler. For Sun 2 running Sunos 4. + Copyright (C) 1987, 1988, 1991 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 1, 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 "tm-sun2.h" + +#undef LINK_SPEC +#define LINK_SPEC "%{!e*:-e start} -dc -dp %{g:-Bstatic} %{static:-Bstatic} %{-Bstatic}" + +#undef ASM_OUTPUT_DOUBLE +#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \ + (isinf ((VALUE)) \ + ? fprintf (FILE, "\t.double 0r%s99e999\n", ((VALUE) > 0 ? "" : "-")) \ + : double_is_minus_zero ((VALUE)) \ + ? fprintf (FILE, "\t.long 0x80000000,0\n") \ + : fprintf (FILE, "\t.double 0r%.20e\n", (VALUE))) + +/* This is how to output an assembler line defining a `float' constant. */ + +#undef ASM_OUTPUT_FLOAT +#define ASM_OUTPUT_FLOAT(FILE,VALUE) \ + (isinf ((VALUE)) \ + ? fprintf (FILE, "\t.single 0r%s99e999\n", ((VALUE) > 0 ? "" : "-")) \ + : double_is_minus_zero ((VALUE)) \ + ? fprintf (FILE, "\t.long 0x80000000\n") \ + : fprintf (FILE, "\t.single 0r%.20e\n", (VALUE))) + +#undef ASM_OUTPUT_FLOAT_OPERAND +#define ASM_OUTPUT_FLOAT_OPERAND(FILE,VALUE) \ + (isinf ((VALUE)) \ + ? fprintf (FILE, "#0r%s99e999", ((VALUE) > 0 ? "" : "-")) \ + : double_is_minus_zero ((VALUE)) \ + ? fprintf (FILE, "#0r-0.0") \ + : fprintf (FILE, "#0r%.9g", (VALUE))) + +#undef ASM_OUTPUT_DOUBLE_OPERAND +#define ASM_OUTPUT_DOUBLE_OPERAND(FILE,VALUE) \ + (isinf ((VALUE)) \ + ? fprintf (FILE, "#0r%s99e999", ((VALUE) > 0 ? "" : "-")) \ + : double_is_minus_zero ((VALUE)) \ + ? fprintf (FILE, "#0r-0.0") \ + : fprintf (FILE, "#0r%.20g", (VALUE))) diff --git a/gcc-1.40/config/tm-sun3-nfp.h b/gcc-1.40/config/tm-sun3-nfp.h new file mode 100644 index 0000000..0a6005d --- /dev/null +++ b/gcc-1.40/config/tm-sun3-nfp.h @@ -0,0 +1,5 @@ +/* Define target machine as a Sun 3 with no 68881. */ + +#define TARGET_DEFAULT 5 + +#include "tm-sun3.h" diff --git a/gcc-1.40/config/tm-sun3.h b/gcc-1.40/config/tm-sun3.h new file mode 100644 index 0000000..90f54b0 --- /dev/null +++ b/gcc-1.40/config/tm-sun3.h @@ -0,0 +1,186 @@ +/* Definitions of target machine for GNU compiler. Sun 68000/68020 version. + Copyright (C) 1987, 1988 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 1, 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 comment is here to see if it will keep Sun's cpp from dying. */ + +#include "tm-m68k.h" + +/* See tm-m68k.h. 7 means 68020 with 68881. */ + +#ifndef TARGET_DEFAULT +#define TARGET_DEFAULT 7 +#endif + +/* Define __HAVE_FPA__ or __HAVE_68881__ in preprocessor, + according to the -m flags. + This will control the use of inline 68881 insns in certain macros. + Also inform the program which CPU this is for. */ + +#if TARGET_DEFAULT & 02 + +/* -m68881 is the default */ +#define CPP_SPEC \ +"%{!msoft-float:%{mfpa:-D__HAVE_FPA__ }%{!mfpa:-D__HAVE_68881__ }}\ +%{!ansi:%{m68000:-Dmc68010}%{mc68000:-Dmc68010}%{!mc68000:%{!m68000:-Dmc68020}}}" + +#else +#if TARGET_DEFAULT & 0100 + +/* -mfpa is the default */ +#define CPP_SPEC \ +"%{!msoft-float:%{m68881:-D__HAVE_68881__ }%{!m68881:-D__HAVE_FPA__ }}\ +%{!ansi:%{m68000:-Dmc68010}%{mc68000:-Dmc68010}%{!mc68000:%{!m68000:-Dmc68020}}}" + +#else + +/* -msoft-float is the default */ +#define CPP_SPEC \ +"%{m68881:-D__HAVE_68881__ }%{mfpa:-D__HAVE_FPA__ }\ +%{!ansi:%{m68000:-Dmc68010}%{mc68000:-Dmc68010}%{!mc68000:%{!m68000:-Dmc68020}}}" + +#endif +#endif + +/* Prevent error on `-sun3' and `-target sun3' options. */ + +#define CC1_SPEC "%{sun3:} %{target:}" + +/* These compiler options take an argument. We ignore -target for now. */ + +#define WORD_SWITCH_TAKES_ARG(STR) (!strcmp (STR, "target")) + +/* -m68000 requires special flags to the assembler. */ + +#define ASM_SPEC \ + "%{m68000:-mc68010}%{mc68000:-mc68010}%{!mc68000:%{!m68000:-mc68020}}" + +/* Names to predefine in the preprocessor for this target machine. */ + +#define CPP_PREDEFINES "-Dmc68000 -Dsun -Dunix" + +/* STARTFILE_SPEC to include sun floating point initialization + This is necessary (tr: Sun does it) for both the m68881 and the fpa + routines. + Note that includes knowledge of the default specs for gcc, ie. no + args translates to the same effect as -m68881 + I'm not sure what would happen below if people gave contradictory + arguments (eg. -msoft-float -mfpa) */ + +#if TARGET_DEFAULT & 0100 +/* -mfpa is the default */ +#define STARTFILE_SPEC \ + "%{pg:gcrt0.o%s}%{!pg:%{p:mcrt0.o%s}%{!p:crt0.o%s}} \ + %{m68881:Mcrt1.o%s} \ + %{msoft-float:Fcrt1.o%s} \ + %{!m68881:%{!msoft-float:Wcrt1.o%s}}" +#else +#if TARGET_DEFAULT & 2 +/* -m68881 is the default */ +#define STARTFILE_SPEC \ + "%{pg:gcrt0.o%s}%{!pg:%{p:mcrt0.o%s}%{!p:crt0.o%s}} \ + %{mfpa:Wcrt1.o%s} \ + %{msoft-float:Fcrt1.o%s} \ + %{!mfpa:%{!msoft-float:Mcrt1.o%s}}" +#else +/* -msoft-float is the default */ +#define STARTFILE_SPEC \ + "%{pg:gcrt0.o%s}%{!pg:%{p:mcrt0.o%s}%{!p:crt0.o%s}} \ + %{m68881:Mcrt1.o%s} \ + %{mfpa:Wcrt1.o%s} \ + %{!m68881:%{!mfpa:Fcrt1.o%s}}" +#endif +#endif + +/* Specify library to handle `-a' basic block profiling. */ + +/* Specify library to handle `-a' basic block profiling. + Control choice of libm.a (if user says -lm) + based on fp arith default and options. */ + +#if TARGET_DEFAULT & 0100 +/* -mfpa is the default */ +#define LIB_SPEC "%{!p:%{!pg:-lc}}%{p:-lc_p}%{pg:-lc_p} \ +%{a:/usr/lib/bb_link.o -lc} %{g:-lg} \ +%{msoft-float:-L/usr/lib/fsoft}%{m68881:-L/usr/lib/f68881}\ +%{!msoft_float:%{!m68881:-L/usr/lib/ffpa}}" +#else +#if TARGET_DEFAULT & 2 +/* -m68881 is the default */ +#define LIB_SPEC "%{!p:%{!pg:-lc}}%{p:-lc_p}%{pg:-lc_p} \ +%{a:/usr/lib/bb_link.o -lc} %{g:-lg} \ +%{msoft-float:-L/usr/lib/fsoft}%{!msoft-float:%{!mfpa:-L/usr/lib/f68881}}\ +%{mfpa:-L/usr/lib/ffpa}" +#else +/* -msoft-float is the default */ +#define LIB_SPEC "%{!p:%{!pg:-lc}}%{p:-lc_p}%{pg:-lc_p} \ +%{a:/usr/lib/bb_link.o -lc} %{g:-lg} \ +%{!m68881:%{!mfpa:-L/usr/lib/fsoft}}%{m68881:-L/usr/lib/f68881}\ +%{mfpa:-L/usr/lib/ffpa}" +#endif +#endif + +/* Provide required defaults for linker -e and -d switches. + Also, it is hard to debug with shared libraries, + so don't use them if going to debug. */ + +#define LINK_SPEC "%{!e*:-e start} -dc -dp %{g:-Bstatic} %{static:-Bstatic} %{-Bstatic}" + +/* Every structure or union's size must be a multiple of 2 bytes. */ + +#define STRUCTURE_SIZE_BOUNDARY 16 + +/* This is BSD, so it wants DBX format. */ + +#define DBX_DEBUGGING_INFO + +/* This is how to output an assembler line defining a `double' constant. */ + +#undef ASM_OUTPUT_DOUBLE +#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \ + (isinf ((VALUE)) \ + ? fprintf (FILE, "\t.double 0r%s99e999\n", ((VALUE) > 0 ? "" : "-")) \ + : double_is_minus_zero ((VALUE)) \ + ? fprintf (FILE, "\t.long 0x80000000,0\n") \ + : fprintf (FILE, "\t.double 0r%.20e\n", (VALUE))) + +/* This is how to output an assembler line defining a `float' constant. */ + +#undef ASM_OUTPUT_FLOAT +#define ASM_OUTPUT_FLOAT(FILE,VALUE) \ + (isinf ((VALUE)) \ + ? fprintf (FILE, "\t.single 0r%s99e999\n", ((VALUE) > 0 ? "" : "-")) \ + : double_is_minus_zero ((VALUE)) \ + ? fprintf (FILE, "\t.long 0x80000000\n") \ + : fprintf (FILE, "\t.single 0r%.20e\n", (VALUE))) + +#undef ASM_OUTPUT_FLOAT_OPERAND +#define ASM_OUTPUT_FLOAT_OPERAND(FILE,VALUE) \ + (isinf ((VALUE)) \ + ? fprintf (FILE, "#0r%s99e999", ((VALUE) > 0 ? "" : "-")) \ + : double_is_minus_zero ((VALUE)) \ + ? fprintf (FILE, "#0r-0.0") \ + : fprintf (FILE, "#0r%.9g", (VALUE))) + +#undef ASM_OUTPUT_DOUBLE_OPERAND +#define ASM_OUTPUT_DOUBLE_OPERAND(FILE,VALUE) \ + (isinf ((VALUE)) \ + ? fprintf (FILE, "#0r%s99e999", ((VALUE) > 0 ? "" : "-")) \ + : double_is_minus_zero ((VALUE)) \ + ? fprintf (FILE, "#0r-0.0") \ + : fprintf (FILE, "#0r%.20g", (VALUE))) diff --git a/gcc-1.40/config/tm-sun386.h b/gcc-1.40/config/tm-sun386.h new file mode 100644 index 0000000..0b54855 --- /dev/null +++ b/gcc-1.40/config/tm-sun386.h @@ -0,0 +1,218 @@ +/* Definitions for Sun assembler syntax for the Intel 80386. + Copyright (C) 1988 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 1, 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. */ + + +#define TARGET_VERSION fprintf (stderr, " (80386, Sun syntax)"); + +/* Define the syntax of instructions and addresses. */ + +/* Define some concatenation macros to concatenate an opcode + and one, two or three operands. In other assembler syntaxes + they may alter the order of ther operands. */ + +#ifdef __STDC__ +#define AS2(a,b,c) #a " " #b "," #c +#define AS3(a,b,c,d) #a " " #b "," #c "," #d +#define AS1(a,b) #a " " #b +#else +#define AS1(a,b) "a b" +#define AS2(a,b,c) "a b,c" +#define AS3(a,b,c,d) "a b,c,d" +#endif + +/* Output the size-letter for an opcode. + CODE is the letter used in an operand spec (L, B, W, S or Q). + CH is the corresponding lower case letter + (except if CODE is L then CH is `l'). */ +#define PUT_OP_SIZE(CODE,CH,FILE) putc (CH,(FILE)) + +/* Opcode suffix for fullword insn. */ +#define L_SIZE "l" + +/* Prefix for register names in this syntax. */ +#define RP "%" + +/* Prefix for immediate operands in this syntax. */ +#define IP "$" + +/* Prefix for internally generated assembler labels. */ +#define LPREFIX ".L" + +/* Output the prefix for an immediate operand, or for an offset operand. */ +#define PRINT_IMMED_PREFIX(FILE) fputs ("$", (FILE)) +#define PRINT_OFFSET_PREFIX(FILE) fputs ("$", (FILE)) + +/* Indirect call instructions should use `*'. */ +#define USE_STAR 1 + +/* Prefix for a memory-operand X. */ +#define PRINT_PTR(X, FILE) + +/* Delimiters that surround base reg and index reg. */ +#define ADDR_BEG(FILE) putc('(', (FILE)) +#define ADDR_END(FILE) putc(')', (FILE)) + +/* Print an index register (whose rtx is IREG). */ +#define PRINT_IREG(FILE,IREG) \ + do \ + { fputs (",", (FILE)); PRINT_REG ((IREG), 0, (FILE)); } \ + while (0) + +/* Print an index scale factor SCALE. */ +#define PRINT_SCALE(FILE,SCALE) \ + if ((SCALE) != 1) fprintf ((FILE), ",%d", (SCALE)) + +/* Print a base/index combination. + BREG is the base reg rtx, IREG is the index reg rtx, + and SCALE is the index scale factor (an integer). */ + +#define PRINT_B_I_S(BREG,IREG,SCALE,FILE) \ + { ADDR_BEG (FILE); \ + if (BREG) PRINT_REG ((BREG), 0, (FILE)); \ + if ((IREG) != 0) \ + { PRINT_IREG ((FILE), (IREG)); \ + PRINT_SCALE ((FILE), (SCALE)); } \ + ADDR_END (FILE); } + +/* Define the syntax of pseudo-ops, labels and comments. */ + +/* Assembler pseudos to introduce constants of various size. */ + +#define ASM_BYTE "\t.byte\t" +#define ASM_SHORT "\t.value\t" +#define ASM_LONG "\t.long\t" +#define ASM_DOUBLE "\t.double\t" + +/* String containing the assembler's comment-starter. */ + +#define COMMENT_BEGIN "/" + +/* Output at beginning of assembler file. */ +/* The .file command should always begin the output. */ + +#undef ASM_FILE_START +#define ASM_FILE_START(FILE) \ + do { \ + extern char *version_string, *language_string; \ + { \ + int len = strlen (dump_base_name); \ + char *na = dump_base_name + len; \ + char shorter[15]; \ + /* NA gets DUMP_BASE_NAME sans directory names. */\ + while (na > dump_base_name) \ + { \ + if (na[-1] == '/') \ + break; \ + na--; \ + } \ + strncpy (shorter, na, 14); \ + shorter[14] = 0; \ + fprintf (FILE, "\t.file\t\"%s\"\n", shorter); \ + } \ + fprintf (FILE, "\t.version\t\"%s %s\"\n", \ + language_string, version_string); \ + if (optimize) ASM_FILE_START_1 (FILE); \ + } while (0) + +#define ASM_FILE_START_1(FILE) fprintf (FILE, "\t.optim\n") + +/* Output to assembler file text saying following lines + may contain character constants, extra white space, comments, etc. */ + +#define ASM_APP_ON "/APP\n" + +/* Output to assembler file text saying following lines + no longer contain unusual constructs. */ + +#define ASM_APP_OFF "/NO_APP\n" + +/* 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)) + +/* This is how to output an assembler line + that says to advance the location counter by SIZE bytes. */ + +#define ASM_OUTPUT_SKIP(FILE,SIZE) \ + fprintf ((FILE), "\t.set\t.,.+%u\n", (SIZE)) + +/* Output before read-only data. */ + +#define TEXT_SECTION_ASM_OP "\t.text" + +/* Output before writable data. */ + +#define DATA_SECTION_ASM_OP "\t.data" + +/* Define the syntax of labels and symbol definitions/declarations. */ + +/* This says how to output an assembler line + to define a global common symbol. */ + +#define ASM_OUTPUT_COMMON(FILE, NAME, SIZE, ROUNDED) \ +( fputs (".comm ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%u\n", (ROUNDED))) + +/* This says how to output an assembler line + to define a local common symbol. */ + +#define ASM_OUTPUT_LOCAL(FILE, NAME, SIZE, ROUNDED) \ +( fputs (".lcomm ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%u\n", (ROUNDED))) + +/* This is how to store into the string BUF + 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(BUF,PREFIX,NUMBER) \ + sprintf ((BUF), ".%s%d", (PREFIX), (NUMBER)) + +/* This is how to output a reference to a user-level label named NAME. */ + +#define ASM_OUTPUT_LABELREF(FILE,NAME) \ + fprintf (FILE, "%s", NAME) + +/* 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) \ + fprintf (FILE, ".%s%d:\n", PREFIX, NUM) + +/* 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) \ + (fputs ("\t.globl\t", FILE), assemble_name (FILE, NAME), fputs ("\n", FILE)) + +/* How to output an ASCII string constant. */ + +#define ASM_OUTPUT_ASCII(FILE, p, size) \ +{ int i=0; \ + while (i < size) \ + { if (i%10 == 0) { if (i!=0) fprintf (FILE, "\n"); \ + fprintf (FILE, ASM_BYTE); } \ + else fprintf (FILE, ","); \ + fprintf (FILE, "0x%x",(p[i++] & 0377)) ;} \ + fprintf (FILE, "\n"); } diff --git a/gcc-1.40/config/tm-sun386i.h b/gcc-1.40/config/tm-sun386i.h new file mode 100644 index 0000000..edcebfe --- /dev/null +++ b/gcc-1.40/config/tm-sun386i.h @@ -0,0 +1,105 @@ +/* Definitions for Intel 386 running SunOS 4.0. + Copyright (C) 1988 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 1, 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 "tm-i386.h" + +/* Use the Sun assembler syntax. */ + +#include "tm-sun386.h" + +/* By default, target has a 80387. */ + +#define TARGET_DEFAULT 1 + +/* Use crt0.o as a startup file. */ + +#define STARTFILE_SPEC \ + "%{pg:gcrt0.o%s}%{!pg:%{p:mcrt0.o%s}%{!p:crt0.o%s}}" + +#define LIB_SPEC "%{!p:%{!pg:-lc}}%{p:-lc_p}%{pg:-lc_p}\ +%{sun386:}" +/* That last item is just to prevent a spurious error. */ + +/* It is hard to debug with shared libraries, + so don't use them if going to debug. */ + +#undef LINK_SPEC +#define LINK_SPEC "%{!e*:-e _start} -dc -dp %{g:-Bstatic} %{static:-Bstatic} %{-Bstatic}" + +/* Extra switches to give the assembler. */ + +#define ASM_SPEC "-i386" + +/* Specify predefined symbols in preprocessor. */ + +#define CPP_PREDEFINES "-Dunix -Di386 -Dsun386 -Dsun" + +/* Allow #sccs in preprocessor. */ + +#define SCCS_DIRECTIVE + +/* Output #ident as a .ident. */ + +#define ASM_OUTPUT_IDENT(FILE, NAME) fprintf (FILE, "\t.ident \"%s\"\n", NAME); + +/* We don't want to output SDB debugging information. */ + +#undef SDB_DEBUGGING_INFO + +/* We want to output DBX debugging information. */ + +#define DBX_DEBUGGING_INFO + +/* Implicit library calls should use memcpy, not bcopy, etc. */ + +#define TARGET_MEM_FUNCTIONS + +/* Force structure alignment to the type used for a bitfield. */ + +#define PCC_BITFIELD_TYPE_MATTERS 1 + +/* 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. */ + +#define VALUE_REGNO(MODE) \ + (((MODE)==SFmode || (MODE)==DFmode) ? FIRST_FLOAT_REG : 0) + +/* 1 if N is a possible register number for a function value. */ + +#define FUNCTION_VALUE_REGNO_P(N) ((N) == 0 || (N)== FIRST_FLOAT_REG) + +/* This is partly guess. */ + +#undef DBX_REGISTER_NUMBER +#define DBX_REGISTER_NUMBER(n) \ + ((n) == 0 ? 11 : (n) == 1 ? 9 : (n) == 2 ? 10 : (n) == 3 ? 8 \ + : (n) == 4 ? 5 : (n) == 5 ? 4 : (n) == 6 ? 6 : (n)) + +/* Every debugger symbol must be in the text section. + Otherwise the assembler or the linker screws up. */ + +#define DEBUG_SYMS_TEXT + +/* This NOP insn makes profiling not fail. */ + +#define ASM_IDENTIFY_GCC(FILE) \ +fprintf (FILE, (profile_flag ? "gcc_compiled.:\n\tnop\n" : "gcc_compiled.:\n")) diff --git a/gcc-1.40/config/tm-sun3mach.h b/gcc-1.40/config/tm-sun3mach.h new file mode 100644 index 0000000..602da86 --- /dev/null +++ b/gcc-1.40/config/tm-sun3mach.h @@ -0,0 +1,8 @@ +#include "tm-sun3.h" + +#undef CPP_PREDEFINES +#define CPP_PREDEFINES "-Dmc68000 -Dsun -Dsun3 -Dunix -DMACH -DCMU -DMTXINU -DBIT_MSF -DBYTE_MSF" + +/* LINK_SPEC is needed only for Sunos 4. */ + +#undef LINK_SPEC diff --git a/gcc-1.40/config/tm-sun3os3.h b/gcc-1.40/config/tm-sun3os3.h new file mode 100644 index 0000000..c4afb4e --- /dev/null +++ b/gcc-1.40/config/tm-sun3os3.h @@ -0,0 +1,5 @@ +#include "tm-sun3.h" + +/* LINK_SPEC is needed only for Sunos 4. */ + +#undef LINK_SPEC diff --git a/gcc-1.40/config/tm-sun3os3nf.h b/gcc-1.40/config/tm-sun3os3nf.h new file mode 100644 index 0000000..44e57f7 --- /dev/null +++ b/gcc-1.40/config/tm-sun3os3nf.h @@ -0,0 +1,5 @@ +#include "tm-sun3-nfp.h" + +/* LINK_SPEC is needed only for Sunos 4. */ + +#undef LINK_SPEC diff --git a/gcc-1.40/config/tm-sun4os3.h b/gcc-1.40/config/tm-sun4os3.h new file mode 100644 index 0000000..a0334d9 --- /dev/null +++ b/gcc-1.40/config/tm-sun4os3.h @@ -0,0 +1,15 @@ +#include "tm-sparc.h" + +/* Define the Sun-asm flag, which is necessary for Sun 4 with os version 3. */ +#undef TARGET_DEFAULT +#define TARGET_DEFAULT 7 + +#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 + diff --git a/gcc-1.40/config/tm-tahoe.h b/gcc-1.40/config/tm-tahoe.h new file mode 100644 index 0000000..de9901f --- /dev/null +++ b/gcc-1.40/config/tm-tahoe.h @@ -0,0 +1,850 @@ +/* Definitions of target machine for GNU compiler. Tahoe version. + Copyright (C) 1989 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 1, 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. */ + +/* + * File: tm-tahoe.h + * + * This port made at the University of Buffalo by Devon Bowen, + * Dale Wiles and Kevin Zachmann. + * + * Mail bugs reports or fixes to: gcc@cs.buffalo.edu + */ + + +/* + * Run-time Target Specification + */ + +/* we want "tahoe" and "unix" auto-defined for all future compilations */ + +#define CPP_PREDEFINES "-Dtahoe -Dunix" + +/* have cc1 print that this is the tahoe version */ + +#define TARGET_VERSION printf (" (tahoe)"); + +/* this is required in all tm files to hold flags */ + +extern int target_flags; + +/* Zero if it is safe to output .dfloat and .float pseudos. */ +#define TARGET_HEX_FLOAT (target_flags & 1) + +#define TARGET_DEFAULT 1 + +#define TARGET_SWITCHES \ + { {"hex-float", 1}, \ + {"no-hex-float", -1}, \ + { "", TARGET_DEFAULT} } + + +/* + * Storage Layout + */ + +/* tahoe uses a big endian byte order */ + +#define BYTES_BIG_ENDIAN + +/* tahoe uses a big endian word order */ + +#define WORDS_BIG_ENDIAN + +/* standard byte size is usable on tahoe */ + +#define BITS_PER_UNIT 8 + +/* longs on the tahoe are 4 byte groups */ + +#define BITS_PER_WORD 32 + +/* from the last two params we get 4 bytes per word */ + +#define UNITS_PER_WORD 4 + +/* addresses are 32 bits (one word) */ + +#define POINTER_SIZE 32 + +/* pointers should align every 32 bits */ + +#define POINTER_BOUNDARY 32 + +/* all parameters line up on 32 boundaries */ + +#define PARM_BOUNDARY 32 + +/* stack should line up on 32 boundaries */ + +#define STACK_BOUNDARY 32 + +/* line functions up on 32 bits */ + +#define FUNCTION_BOUNDARY 32 + +/* the biggest alignment the tahoe needs in 32 bits */ + +#define BIGGEST_ALIGNMENT 32 + +/* we have to align after an 'int : 0' in a structure */ + +#define EMPTY_FIELD_BOUNDARY 32 + +/* structures must be made of full bytes */ + +#define STRUCTURE_SIZE_BOUNDARY 8 + +/* tahoe is picky about data alignment */ + +#define STRICT_ALIGNMENT + +/* keep things standard with pcc */ + +#define PCC_BITFIELD_TYPE_MATTERS 1 + +/* this section is borrowed from the vax version since the */ +/* formats are the same in both of the architectures */ + +#define CHECK_FLOAT_VALUE(mode, d) \ + if ((mode) == SFmode) \ + { \ + if ((d) > 1.7014117331926443e+38) \ + { error ("magnitude of constant too large for `float'"); \ + (d) = 1.7014117331926443e+38; } \ + else if ((d) < -1.7014117331926443e+38) \ + { error ("magnitude of constant too large for `float'"); \ + (d) = -1.7014117331926443e+38; } \ + else if (((d) > 0) && ((d) < 2.9387358770557188e-39)) \ + { warning ("`float' constant truncated to zero"); \ + (d) = 0.0; } \ + else if (((d) < 0) && ((d) > -2.9387358770557188e-39)) \ + { warning ("`float' constant truncated to zero"); \ + (d) = 0.0; } \ + } + + +/* + * Register Usage + */ + +/* define 15 general regs plus one for the floating point reg (FPP) */ + +#define FIRST_PSEUDO_REGISTER 17 + +/* let the compiler know what the fp, sp and pc are */ + +#define FIXED_REGISTERS {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0} + +/* lots of regs aren't guarenteed to return from a call. The FPP reg */ +/* must be included in these since it can't be saved by the reg mask */ + +#define CALL_USED_REGISTERS {1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1} + +/* The FPP can handle any type, but the others may require as many as */ +/* two regs depending on the mode needed */ + +#define HARD_REGNO_NREGS(REGNO, MODE) \ + (REGNO != 16 ? ((GET_MODE_SIZE(MODE)+UNITS_PER_WORD-1) / UNITS_PER_WORD) : 1) + +/* any mode greater than 4 bytes (doubles) can only go in an even regs */ +/* and the FPP can only hold SFmode and DFmode */ + +#define HARD_REGNO_MODE_OK(REGNO, MODE) \ + (REGNO != 16 ? (GET_MODE_SIZE (MODE) <= 4 ? 1 : (REGNO % 2 - 1)) : \ + (MODE == SFmode || MODE == DFmode)) + +/* if mode1 or mode2, but not both, are doubles then modes cannot be tied */ + +#define MODES_TIEABLE_P(MODE1, MODE2) \ + ((MODE1 == DFmode) == (MODE2 == DFmode)) + +/* the program counter is reg 15 */ + +#define PC_REGNUM 15 + +/* the stack pointer is reg 14 */ + +#define STACK_POINTER_REGNUM 14 + +/* the frame pointer is reg 13 */ + +#define FRAME_POINTER_REGNUM 13 + +/* tahoe does require an fp */ + +#define FRAME_POINTER_REQUIRED 1 + +/* since tahoe doesn't have a argument pointer, make it the fp */ + +#define ARG_POINTER_REGNUM 13 + +/* this isn't currently used since C doesn't support this feature */ + +#define STATIC_CHAIN_REGNUM 0 + +/* we'll use reg 1 for structure passing cause the destination */ +/* of the eventual movblk requires it to be there anyway. */ + +#define STRUCT_VALUE_REGNUM 1 + + +/* + * Register Classes + */ + +/* tahoe has two types of regs. GENERALY_REGS are all the regs up */ +/* to number 15. FPP_REG is the special floating point processor */ +/* register class (only one reg). */ + +enum reg_class {NO_REGS,GENERAL_REGS,FPP_REG,ALL_REGS,LIM_REG_CLASSES}; + +/* defines the number of reg classes. */ + +#define N_REG_CLASSES (int) LIM_REG_CLASSES + +/* this defines what the classes are officially named for debugging */ + +#define REG_CLASS_NAMES \ + {"NO_REGS","GENERAL_REGS","FPP_REG","ALL_REGS"} + +/* set general regs to be the first 16 regs and the fpp reg to be 17th */ + +#define REG_CLASS_CONTENTS {0,0xffff,0x10000,0x1ffff} + +/* register class for the fpp reg is FPP_REG, all others are GENERAL_REGS */ + +#define REGNO_REG_CLASS(REGNO) (REGNO == 16 ? FPP_REG : GENERAL_REGS) + +/* only gereral registers can be used as a base reg */ + +#define BASE_REG_CLASS GENERAL_REGS + +/* only gereral registers can be used to index */ + +#define INDEX_REG_CLASS GENERAL_REGS + +/* 'a' as a contraint in the md file means the FFP_REG class */ + +#define REG_CLASS_FROM_LETTER(C) (C == 'a' ? FPP_REG : NO_REGS) + +/* any general reg but the fpp can be a base reg */ + +#define REGNO_OK_FOR_BASE_P(regno) \ +((regno) < FIRST_PSEUDO_REGISTER - 1 || reg_renumber[regno] >= 0) + +/* any general reg except the pc and fpp can be an index reg */ + +#define REGNO_OK_FOR_INDEX_P(regno) \ +((regno) < FIRST_PSEUDO_REGISTER - 2 || reg_renumber[regno] >= 0) + +/* if your loading a floating point constant, it can't be done */ +/* through a register. Force it to be a memory constant. */ + +#define PREFERRED_RELOAD_CLASS(X,CLASS) \ + ((GET_CODE (X) == CONST_DOUBLE) ? NO_REGS : CLASS) + +/* for the fpp reg, all modes fit; for any others, you need two for doubles */ + +#define CLASS_MAX_NREGS(CLASS, MODE) \ + (CLASS != FPP_REG ? ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD) : 1) + +/* we don't define any special constant sizes so all should fail */ + +#define CONST_OK_FOR_LETTER_P(VALUE, C) 0 + +/* we don't define any special double sizes so all should fail */ + +#define CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C) 0 + + +/* + * Describing Stack Layout + */ + +/* tahoe stack grows from high to low memory */ + +#define STACK_GROWS_DOWNWARD + +/* Define this if longjmp restores from saved registers + rather than from what setjmp saved. */ +#define LONGJMP_RESTORE_FROM_STACK + +/* tahoe call frames grow from high to low memory on the stack */ + +#define FRAME_GROWS_DOWNWARD + +/* the tahoe fp points to the *top* of the frame instead of the */ +/* bottom, so we have to make this offset a constant large enough */ +/* to jump over the biggest frame possible. */ + +#define STARTING_FRAME_OFFSET -52 + +/* tahoe always pushes 4 bytes unless it's a double in which case */ +/* it pushes a full 8 bytes. */ + +#define PUSH_ROUNDING(BYTES) (BYTES <= 4 ? 4 : 8) + +/* the first parameter in a function is at the fp + 4 */ + +#define FIRST_PARM_OFFSET(FNDECL) 4 + +/* the tahoe return function takes care of everything on the stack */ + +#define RETURN_POPS_ARGS(FUNTYPE) 1 + +/* function values for all types are returned in register 0 */ + +#define FUNCTION_VALUE(VALTYPE, FUNC) \ + gen_rtx (REG, TYPE_MODE (VALTYPE), 0) + +/* libarary routines also return things in reg 0 */ + +#define LIBCALL_VALUE(MODE) gen_rtx (REG, MODE, 0) + +/* Tahoe doesn't return structures in a reentrant way */ + +#define PCC_STATIC_STRUCT_RETURN + +/* we only return values from a function in reg 0 */ + +#define FUNCTION_VALUE_REGNO_P(N) ((N) == 0) + +/* we never pass args through a register */ + +#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) 0 + +/* int is fine to hold the argument summary in FUNCTION_ARG */ + +#define CUMULATIVE_ARGS int + +/* we just set CUM to 0 before the FUNCTION_ARG call. No matter what */ +/* we make it, FUNCTION_ARG will return 0 anyway */ + +#define INIT_CUMULATIVE_ARGS(CUM,FNTYPE) \ + ((CUM) = 0) + +/* all modes push their size rounded to the nearest word boundary */ +/* except block which is the size of the block rounded up */ + +#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \ + ((CUM) += ((MODE) != BLKmode \ + ? (GET_MODE_SIZE (MODE) + 3) & ~3 \ + : (int_size_in_bytes (TYPE) + 3) & ~3)) + +/* this is always false since we never pass params in regs */ + +#define FUNCTION_ARG_REGNO_P(N) 0 + +/* this code calculates the register entry mask and sets up */ +/* the stack pointer for the function. The stack is set down */ +/* far enough from the fp to jump over any push regs and local */ +/* vars. This is a problem since the tahoe has the fp pointing */ +/* to the top of the frame and the compiler must know the off- */ +/* set off the fp to the local vars. */ + +#define FUNCTION_PROLOGUE(FILE, SIZE) \ +{ register int regno; \ + register int mask = 0; \ + extern char call_used_regs[]; \ + for (regno = 0; regno < FIRST_PSEUDO_REGISTER-1; regno++) \ + if (regs_ever_live[regno] && !call_used_regs[regno]) \ + mask |= 1 << regno; \ + fprintf (FILE, "\t.word 0x%x\n", mask); \ + if (SIZE != 0) fprintf (FILE, "\tsubl3 $%d,fp,sp\n", (SIZE) - STARTING_FRAME_OFFSET); } + +/* to call the profiler, push the variable value onto the stack */ +/* and call mcount like a regular function. */ + +#define FUNCTION_PROFILER(FILE, LABELNO) \ + fprintf (FILE, "\tpushl $LP%d\n\tcallf $8,mcount\n", (LABELNO)); + +/* all stack handling at the end of a function is handled by the */ +/* return command. */ + +#define EXIT_IGNORE_STACK 1 + +/* this never gets executed since the system knows it always gets */ +/* an fp to work with. It just prints a friendly message since the */ +/* person must be playing with the tm file defs */ + +#define FIX_FRAME_POINTER_ADDRESS(ADDR,DEPTH) \ + { abort(); } + + +/* + * Library Subroutine Names + */ + +/* udiv is a valid C library routine in libc.a, so we call that */ + +#define UDIVSI3_LIBCALL "*udiv" + +/* urem is a valid C library routine in libc.a, so we call that */ + +#define UMODSI3_LIBCALL "*urem" + + +/* + * Addressing Modes + */ + +/* constant addresses can be treated exactly the same as normal constants */ + +#define CONSTANT_ADDRESS_P(X) CONSTANT_P (X) + +/* we can have as many as two regs in any given address */ + +#define MAX_REGS_PER_ADDRESS 2 + +/* The following is all the code for GO_IF_LEGITIMATE_ADDRESS */ +/* most of this taken directly from the vax tm file since the */ +/* tahoe and vax addressing modes are nearly identicle. */ + +/* Is x an indirectable address? */ + +#define INDIRECTABLE_ADDRESS_P(X) \ + (CONSTANT_ADDRESS_P (X) \ + || (GET_CODE (X) == REG && REG_OK_FOR_BASE_P (X)) \ + || (GET_CODE (X) == PLUS \ + && GET_CODE (XEXP (X, 0)) == REG \ + && REG_OK_FOR_BASE_P (XEXP (X, 0)) \ + && CONSTANT_ADDRESS_P (XEXP (X, 1)))) + +/* If x is a non-indexed-address, go to ADDR. */ + +#define GO_IF_NONINDEXED_ADDRESS(X, ADDR) \ +{ register rtx xfoob = (X); \ + if (GET_CODE (xfoob) == REG) goto ADDR; \ + if (INDIRECTABLE_ADDRESS_P (xfoob)) goto ADDR; \ + xfoob = XEXP (X, 0); \ + if (GET_CODE (X) == MEM && INDIRECTABLE_ADDRESS_P (xfoob)) \ + goto ADDR; \ + if ((GET_CODE (X) == PRE_DEC || GET_CODE (X) == POST_INC) \ + && GET_CODE (xfoob) == REG && REGNO (xfoob) == 14) \ + goto ADDR; } + +/* Is PROD an index term in mode MODE. */ + +#define INDEX_TERM_P(PROD, MODE) \ +(GET_MODE_SIZE (MODE) == 1 \ + ? (GET_CODE (PROD) == REG && REG_OK_FOR_BASE_P (PROD)) \ + : (GET_CODE (PROD) == MULT \ + && \ + (xfoo0 = XEXP (PROD, 0), xfoo1 = XEXP (PROD, 1), \ + ((GET_CODE (xfoo0) == CONST_INT \ + && INTVAL (xfoo0) == GET_MODE_SIZE (MODE) \ + && GET_CODE (xfoo1) == REG \ + && REG_OK_FOR_INDEX_P (xfoo1)) \ + || \ + (GET_CODE (xfoo1) == CONST_INT \ + && INTVAL (xfoo1) == GET_MODE_SIZE (MODE) \ + && GET_CODE (xfoo0) == REG \ + && REG_OK_FOR_INDEX_P (xfoo0)))))) + +/* Is the addition to the index a reg? */ + +#define GO_IF_REG_PLUS_INDEX(X, MODE, ADDR) \ +{ register rtx xfooa; \ + if (GET_CODE (X) == PLUS) \ + { if (GET_CODE (XEXP (X, 0)) == REG \ + && REG_OK_FOR_BASE_P (XEXP (X, 0)) \ + && (xfooa = XEXP (X, 1), \ + INDEX_TERM_P (xfooa, MODE))) \ + goto ADDR; \ + if (GET_CODE (XEXP (X, 1)) == REG \ + && REG_OK_FOR_BASE_P (XEXP (X, 1)) \ + && (xfooa = XEXP (X, 0), \ + INDEX_TERM_P (xfooa, MODE))) \ + goto ADDR; } } + +/* Is the rtx X a valid memoy address for operand of mode MODE? */ +/* If it is, go to ADDR */ + +#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \ +{ register rtx xfoo, xfoo0, xfoo1; \ + GO_IF_NONINDEXED_ADDRESS (X, ADDR); \ + if (GET_CODE (X) == PLUS) \ + { xfoo = XEXP (X, 0); \ + if (INDEX_TERM_P (xfoo, MODE)) \ + { GO_IF_NONINDEXED_ADDRESS (XEXP (X, 1), ADDR); } \ + xfoo = XEXP (X, 1); \ + if (INDEX_TERM_P (xfoo, MODE)) \ + { GO_IF_NONINDEXED_ADDRESS (XEXP (X, 0), ADDR); } \ + if (CONSTANT_ADDRESS_P (XEXP (X, 0))) \ + { if (GET_CODE (XEXP (X, 1)) == REG \ + && REG_OK_FOR_BASE_P (XEXP (X, 1))) \ + goto ADDR; \ + GO_IF_REG_PLUS_INDEX (XEXP (X, 1), MODE, ADDR); } \ + if (CONSTANT_ADDRESS_P (XEXP (X, 1))) \ + { if (GET_CODE (XEXP (X, 0)) == REG \ + && REG_OK_FOR_BASE_P (XEXP (X, 0))) \ + goto ADDR; \ + GO_IF_REG_PLUS_INDEX (XEXP (X, 0), MODE, ADDR); } } } + +/* Register 16 can never be used for index or base */ + +#ifndef REG_OK_STRICT +#define REG_OK_FOR_INDEX_P(X) (REGNO(X) != 16) +#define REG_OK_FOR_BASE_P(X) (REGNO(X) != 16) +#else +#define REG_OK_FOR_INDEX_P(X) REGNO_OK_FOR_INDEX_P (REGNO (X)) +#define REG_OK_FOR_BASE_P(X) REGNO_OK_FOR_BASE_P (REGNO (X)) +#endif + +/* Addressing is too simple to allow optimizing here */ + +#define LEGITIMIZE_ADDRESS(X,OLDX,MODE,WIN) {} + +/* Post_inc and pre_dec always adds 4 */ + +#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR,LABEL) \ + { if (GET_CODE(ADDR) == POST_INC || GET_CODE(ADDR) == PRE_DEC) \ + goto LABEL; \ + if (GET_CODE (ADDR) == PLUS) \ + { if (CONSTANT_ADDRESS_P (XEXP (ADDR, 0)) \ + && GET_CODE (XEXP (ADDR, 1)) == REG); \ + else if (CONSTANT_ADDRESS_P (XEXP (ADDR, 1)) \ + && GET_CODE (XEXP (ADDR, 0)) == REG); \ + else goto LABEL; }} + +/* Double's are not legitimate as immediate operands */ + +#define LEGITIMATE_CONSTANT_P(X) \ + (GET_CODE (X) != CONST_DOUBLE) + + +/* + * Miscellaneous Parameters + */ + +/* the elements in the case jump table are all words */ + +#define CASE_VECTOR_MODE HImode + +/* each of the table elements in a case are relative to the jump addess */ + +#define CASE_VECTOR_PC_RELATIVE + +/* tahoe case instructions just fall through to the next instruction */ +/* if not satisfied. It doesn't support a default action */ + +#define CASE_DROPS_THROUGH + +/* the standard answer is given here and work ok */ + +#define IMPLICIT_FIX_EXPR FIX_ROUND_EXPR + +/* in a general div case, it's easiest to use TRUNC_DIV_EXPR */ + +#define EASY_DIV_EXPR TRUNC_DIV_EXPR + +/* the standard seems to be leaving char's as signed so we left it */ +/* this way even though we think they should be unsigned! */ + +#define DEFAULT_SIGNED_CHAR 1 + +/* the most we can move without cutting down speed is 4 bytes */ + +#define MOVE_MAX 4 + +/* our int is 32 bits */ + +#define INT_TYPE_SIZE 32 + +/* byte access isn't really slower than anything else */ + +#define SLOW_BYTE_ACCESS 0 + +/* zero extension is more than one instruction so try to avoid it */ + +#define SLOW_ZERO_EXTEND + +/* any bits higher than the low 4 are ignored in the shift count */ +/* so don't bother zero extending or sign extending them */ + +#define SHIFT_COUNT_TRUNCATED + +/* we don't need to officially convert from one fixed type to another */ +/* in order to use it as that type. We can just assume it's the same */ + +#define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) 1 + +/* pass chars as ints */ + +#define PROMOTE_PROTOTYPES + +/* pointers can be represented by an si mode expression */ + +#define Pmode SImode + +/* function addresses are made by specifying a byte address */ + +#define FUNCTION_MODE QImode + +/* all the costs here were borrowed from the vax version of the */ +/* tm file. They're pretty much the same in the tahoe */ + +#define CONST_COSTS(RTX,CODE) \ + case CONST_INT: \ + if (RTX == const0_rtx) return 0; \ + if ((unsigned) INTVAL (RTX) < 077) return 1; \ + case CONST: \ + case LABEL_REF: \ + case SYMBOL_REF: \ + return 3; \ + case CONST_DOUBLE: \ + return 5; + + +/* + * Condition Code Information + */ + +/* Condition codes still break in one case that we haven't tracked */ +/* down yet, so we have to leave them like this for now. */ + +#define NOTICE_UPDATE_CC(EXP, INSN) \ +{ if (GET_CODE(EXP) == SET && GET_CODE(SET_DEST(EXP)) == CC0) { \ + cc_status.flags = 0; \ + cc_status.value1 = SET_DEST(EXP); \ + cc_status.value2 = SET_SRC(EXP); \ + } else \ + CC_STATUS_INIT; } + + +/* + * Output of Assembler Code + */ + +/* start the assembly by turning off APP */ + +#define ASM_FILE_START(FILE) fprintf (FILE, "#NO_APP\n\n"); + +/* the instruction that turns on the APP for the gnu assembler */ + +#define ASM_APP_ON "#APP\n" + +/* the instruction that turns off the APP for the gnu assembler */ + +#define ASM_APP_OFF "#NO_APP\n" + +/* what to output before read-only data. */ + +#define TEXT_SECTION_ASM_OP ".text" + +/* what to output before writable data. */ + +#define DATA_SECTION_ASM_OP ".data" + +/* this is what we call each of the regs. notice that the FPP reg is */ +/* called "ac". This should never get used due to the way we've set */ +/* up FPP instructions in the md file. But we call it "ac" here to */ +/* fill the list. */ + +#define REGISTER_NAMES \ +{"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", \ + "r9", "r10", "r11", "r12", "fp", "sp", "pc", "ac"} + +/* registers are called the same thing in dbx anything else */ + +#define DBX_REGISTER_NUMBER(REGNO) (REGNO) + +/* allow generation of dbx info in the assembly */ + +#define DBX_DEBUGGING_INFO + +/* our dbx doesn't support this */ + +#define DBX_NO_XREFS + +/* we don't want symbols broken up */ + +#define DBX_CONTIN_LENGTH 0 + +/* this'll really never be used, but we'll leave it at this */ + +#define DBX_CONTIN_CHAR '?' + +/* labels are the label followed by a colon and a newline */ +/* must be a statement, so surround it in a null loop */ + +#define ASM_OUTPUT_LABEL(FILE,NAME) \ + do { assemble_name (FILE, NAME); fputs (":\n", FILE); } while (0) + +/* use the .globl directive to make labels global for the linker */ + +#define ASM_GLOBALIZE_LABEL(FILE,NAME) \ + do { fputs (".globl ", FILE); assemble_name (FILE, NAME); fputs ("\n", FILE);} while (0) + +/* output a label by appending an underscore to it */ + +#define ASM_OUTPUT_LABELREF(FILE,NAME) \ + fprintf (FILE, "_%s", NAME) + +/* use the standard format for printing internal labels */ + +#define ASM_OUTPUT_INTERNAL_LABEL(FILE,PREFIX,NUM) \ + fprintf (FILE, "%s%d:\n", PREFIX, NUM) + +/* a * is used for label indirection in unix assembly */ + +#define ASM_GENERATE_INTERNAL_LABEL(LABEL,PREFIX,NUM) \ + sprintf (LABEL, "*%s%d", PREFIX, NUM) + +/* outputing a double is easy cause we only have one kind */ + +#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \ +{ \ + union { int i[2]; double d;} temp; \ + temp.d = (VALUE); \ + if (TARGET_HEX_FLOAT) \ + fprintf ((FILE), "\t.long 0x%x,0x%x # %.20e\n", \ + temp.i[0], temp.i[1], temp.d); \ + else \ + fprintf (FILE, "\t.dfloat 0d%.20e\n", temp.d); \ +} + +/* This is how to output an assembler line defining a `float' constant. */ + +#define ASM_OUTPUT_FLOAT(FILE,VALUE) \ +{ \ + union { int i; float f;} temp; \ + temp.f = (float) (VALUE); \ + if (TARGET_HEX_FLOAT) \ + fprintf ((FILE), "\t.long 0x%x # %.20e\n", \ + temp.i, temp.f); \ + else \ + fprintf (FILE, "\t.float 0f%.20e\n", temp.f); \ +} + +/* This is how to output an assembler line defining an `int' constant. */ + +#define ASM_OUTPUT_INT(FILE,VALUE) \ +( fprintf (FILE, "\t.long "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +/* Likewise for `char' and `short' constants. */ + +#define ASM_OUTPUT_SHORT(FILE,VALUE) \ +( fprintf (FILE, "\t.word "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +#define ASM_OUTPUT_CHAR(FILE,VALUE) \ +( fprintf (FILE, "\t.byte "), \ + 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.byte 0x%x\n", (VALUE)) + +/* this is the insn to push a register onto the stack */ + +#define ASM_OUTPUT_REG_PUSH(FILE,REGNO) \ + fprintf (FILE, "\tpushl %s\n", reg_names[REGNO]) + +/* this is the insn to pop a register from the stack */ + +#define ASM_OUTPUT_REG_POP(FILE,REGNO) \ + fprintf (FILE, "\tmovl (sp)+,%s\n", reg_names[REGNO]) + +/* this is required even thought tahoe doesn't support it */ +/* cause the C code expects it to be defined */ + +#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \ + fprintf (FILE, "\t.long L%d\n", VALUE) + +/* This is how to output an element of a case-vector that is relative. */ + +#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, VALUE, REL) \ + fprintf (FILE, "\t.word L%d-L%d\n", VALUE, REL) + +/* This aligns the assembler output */ + +#define ASM_OUTPUT_ALIGN(FILE,LOG) \ + LOG ? fprintf (FILE, "\t.align %d\n", (LOG)) : 0 + +/* This is how to skip over some space */ + +#define ASM_OUTPUT_SKIP(FILE,SIZE) \ + fprintf (FILE, "\t.space %u\n", (SIZE)) + +/* This defines common variables across files */ + +#define ASM_OUTPUT_COMMON(FILE, NAME, SIZE, ROUNDED) \ +( fputs (".comm ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%u\n", (ROUNDED))) + +/* This defines a common varible in the local file */ + +#define ASM_OUTPUT_LOCAL(FILE, NAME, SIZE, ROUNDED) \ +( fputs (".lcomm ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%u\n", (ROUNDED))) + +/* code to generate a label */ + +#define ASM_FORMAT_PRIVATE_NAME(OUTPUT, NAME, LABELNO) \ +( (OUTPUT) = (char *) alloca (strlen ((NAME)) + 10), \ + sprintf ((OUTPUT), "%s.%d", (NAME), (LABELNO))) + +/* parenthesis for expressions in the assembly */ + +#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 + +/* Print an operand. Some difference from the vax code, + since the tahoe can't support immediate floats and doubles. + + %@ means print the proper alignment operand for aligning after a casesi. + This depends on the assembler syntax. + This is 1 for our assembler, since .align is logarithmic. */ + +#define PRINT_OPERAND_PUNCT_VALID_P(CODE) \ + ((CODE) == '@') + +#define PRINT_OPERAND(FILE, X, CODE) \ +{ if (CODE == '@') \ + putc ('1', FILE); \ + else if (GET_CODE (X) == REG) \ + fprintf (FILE, "%s", reg_names[REGNO (X)]); \ + else if (GET_CODE (X) == MEM) \ + output_address (XEXP (X, 0)); \ + else { putc ('$', FILE); output_addr_const (FILE, X); }} + +/* When the operand is an address, call print_operand_address to */ +/* do the work from output-tahoe.c. */ + +#define PRINT_OPERAND_ADDRESS(FILE, ADDR) \ + print_operand_address (FILE, ADDR) + diff --git a/gcc-1.40/config/tm-tower-as.h b/gcc-1.40/config/tm-tower-as.h new file mode 100644 index 0000000..1edf4dd --- /dev/null +++ b/gcc-1.40/config/tm-tower-as.h @@ -0,0 +1,616 @@ +/* Definitions of target machine for GNU compiler. + Copyright (C) 1990 Free Software Foundation, Inc. + + Written by Robert Andersson, International Systems, Oslo, Norway. + Send bug reports, questions and improvements to ra@intsys.no. + + For NCR Tower 32/4x0 and 32/6x0 running System V Release 3. + This file outputs assembler source suitable for the native Tower as + and with sdb debugging symbols. See tm-tower.h for more comments. + + This file was based on tm-m68k.h, tm-hp9k320.h and tm-3b1.h + as of the 1.37.1 version. + + +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 1, 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 "tm-tower.h" + + +/* Define __HAVE_68881 in preprocessor only if -m68881 is specified. + This will control the use of inline 68881 insns in certain macros. + Also, define special define used to identify the Tower assembler. */ + +#define CPP_SPEC "-D__TOWER_ASM__ %{m68881:-D__HAVE_68881__}" + +/* The startfiles and libraries depend on the -p and -m68881 options. + The Tower does not support the -pg option. */ + +#define STARTFILE_SPEC \ +"%{p:%{m68881:/usr/lib/fp/mcrt1.o}%{!m68881:/lib/mcrt1.o}} \ + %{!p:%{m68881:/usr/lib/fp/crt1.o}%{!m68881:/lib/crt1.o}}" + +/* These four macros control how m68k.md is expanded. */ + +#define MOTOROLA +#define SGS +#define SONY_ASM +#define HPUX_ASM + +/* Turn on SDB debugging info. */ + +#define SDB_DEBUGGING_INFO + +/* This is only useful if gdb is changed, but doesn't harm anyway. */ + +#define ASM_IDENTIFY_GCC(FILE) \ + fprintf (FILE, "gcc_compiled%%:\n") + +/* All the ASM_OUTPUT macros need to conform to the Tower as syntax. */ + +#define ASM_OUTPUT_SOURCE_FILENAME(FILE, FILENAME) \ + fprintf (FILE, "\tfile\t\"%s\"\n", FILENAME) + +#define ASM_OUTPUT_SOURCE_LINE(FILE, LINENO) \ + fprintf (FILE, "\tln\t%d\n", \ + (sdb_begin_function_line \ + ? last_linenum - sdb_begin_function_line : 1)) + +#define ASM_OUTPUT_IDENT(FILE, NAME) \ + fprintf (FILE, "\tident\t\"%s\" \n", NAME) + +#define ASM_OUTPUT_ASCII(FILE,PTR,LEN) \ + { register int sp = 0, lp = 0; \ + fprintf (FILE, "\tbyte\t"); \ + loop: \ + if (PTR[sp] > ' ' && ! (PTR[sp] & 0x80) && PTR[sp] != '\\') \ + { lp += 3; \ + fprintf (FILE, "'%c", PTR[sp]); } \ + else \ + { lp += 5; \ + fprintf (FILE, "0x%x", PTR[sp]); } \ + if (++sp < LEN) \ + { if (lp > 60) \ + { lp = 0; \ + fprintf (FILE, "\n\tbyte\t"); } \ + else \ + putc (',', FILE); \ + goto loop; } \ + putc ('\n', FILE); } + +/* Translate Motorola opcodes such as `jbeq' + into SGS/Tower opcodes such as `beq.w'. + Change `move' to `mov'. + Change `cmpm' to `cmp'. + Change `divsl' to `tdivs'. + Change `divul' to `tdivu'. + Change `ftst' to `ftest'. + Change `fmove' to `fmov'. */ + +#define ASM_OUTPUT_OPCODE(FILE, PTR) \ +{ if ((PTR)[0] == 'j' && (PTR)[1] == 'b') \ + { ++(PTR); \ + while (*(PTR) != ' ') \ + { putc (*(PTR), (FILE)); ++(PTR); } \ + fprintf ((FILE), ".w"); } \ + else if ((PTR)[0] == 'm' && (PTR)[1] == 'o' \ + && (PTR)[2] == 'v' && (PTR)[3] == 'e') \ + { fprintf ((FILE), "mov"); (PTR) += 4; } \ + else if ((PTR)[0] == 'c' && (PTR)[1] == 'm' \ + && (PTR)[2] == 'p' && (PTR)[3] == 'm') \ + { fprintf ((FILE), "cmp"); (PTR) += 4; } \ + else if ((PTR)[0] == 'd' && (PTR)[1] == 'i' \ + && (PTR)[2] == 'v' && (PTR)[3] == 's' \ + && (PTR)[4] == 'l') \ + { fprintf ((FILE), "tdivs"); (PTR) += 5; } \ + else if ((PTR)[0] == 'd' && (PTR)[1] == 'i' \ + && (PTR)[2] == 'v' && (PTR)[3] == 'u' \ + && (PTR)[4] == 'l') \ + { fprintf ((FILE), "tdivu"); (PTR) += 5; } \ + else if ((PTR)[0] == 'f' && (PTR)[1] == 't' \ + && (PTR)[2] == 's' && (PTR)[3] == 't') \ + { fprintf ((FILE), "ftest"); (PTR) += 4; } \ + else if ((PTR)[0] == 'f' && (PTR)[1] == 'm' \ + && (PTR)[2] == 'o' && (PTR)[3] == 'v' \ + && (PTR)[4] == 'e') \ + { fprintf ((FILE), "fmov"); (PTR) += 5; } \ +} + + + +/* Override parts of tm-m68k.h to fit the Tower assembler. + This section needs to track changes done to tm-m68k.h in the future. */ + +#undef TARGET_VERSION +#define TARGET_VERSION fprintf (stderr, " (68k, Motorola/SGS/Tower32 syntax)"); + +#undef BLOCK_PROFILER +#undef FUNCTION_BLOCK_PROFILER +#undef FUNCTION_PROFILER +#define FUNCTION_PROFILER(FILE, LABEL_NO) \ + fprintf (FILE, "\tmov.l &LP%%%d,%%a0\n\tjsr mcount%%\n", (LABEL_NO)) + +/* The prologue is identical to the one in tm-m68k.h except that the + assembler syntax is different. */ + +#undef FUNCTION_PROLOGUE +#define FUNCTION_PROLOGUE(FILE, SIZE) \ +{ register int regno; \ + register int mask = 0; \ + extern char call_used_regs[]; \ + int fsize = ((SIZE) + 3) & -4; \ + if (frame_pointer_needed) \ + { if (TARGET_68020 || fsize < 0x8000) \ + fprintf (FILE, "\tlink %%a6,&%d\n", -fsize); \ + else \ + fprintf (FILE, "\tlink %%a6,&0\n\tsub.l &%d,%%sp\n", fsize); } \ + for (regno = 24; regno < 56; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + fprintf(FILE, "\tfpmoved %s,-(%%sp)\n", \ + reg_names[regno]); \ + for (regno = 16; regno < 24; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + mask |= 1 << (regno - 16); \ + if ((mask & 0xff) != 0) \ + fprintf (FILE, "\tfmovm &0x%x,-(%%sp)\n", mask & 0xff); \ + mask = 0; \ + for (regno = 0; regno < 16; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + mask |= 1 << (15 - regno); \ + if (frame_pointer_needed) \ + mask &= ~ (1 << (15-FRAME_POINTER_REGNUM)); \ + if (exact_log2 (mask) >= 0) \ + fprintf (FILE, "\tmov.l %s,-(%%sp)\n", reg_names[15 - exact_log2 (mask)]); \ + else if (mask) fprintf (FILE, "\tmovm.l &0x%x,-(%%sp)\n", mask); } + +/* The epilogue is identical to the one in tm-m68k.h except that: + a) The assembler syntax is different. + b) Pointers are returned both in %d0 and %a0. + c) FUNCTION_EXTRA_EPILOGUE is not needed. */ + +#undef FUNCTION_EPILOGUE +#define FUNCTION_EPILOGUE(FILE, SIZE) \ +{ register int regno; \ + register int mask, fmask; \ + register int nregs; \ + int offset, foffset, fpoffset; \ + extern char call_used_regs[]; \ + extern int current_function_pops_args; \ + extern int current_function_args_size; \ + extern int current_function_returns_pointer; \ + int fsize = ((SIZE) + 3) & -4; \ + int big = 0; \ + nregs = 0; fmask = 0; fpoffset = 0; \ + for (regno = 24 ; regno < 56 ; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + nregs++; \ + fpoffset = nregs*8; \ + nregs = 0; \ + for (regno = 16; regno < 24; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + { nregs++; fmask |= 1 << (23 - regno); } \ + foffset = fpoffset + nregs * 12; \ + nregs = 0; mask = 0; \ + if (frame_pointer_needed) regs_ever_live[FRAME_POINTER_REGNUM] = 0; \ + for (regno = 0; regno < 16; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + { nregs++; mask |= 1 << regno; } \ + offset = foffset + nregs * 4; \ + if (offset + fsize >= 0x8000 \ + && frame_pointer_needed \ + && (mask || fmask || fpoffset)) \ + { fprintf (FILE, "\tmov.l &%d,%%a0\n", -fsize); \ + fsize = 0, big = 1; } \ + if (exact_log2 (mask) >= 0) { \ + if (big) \ + fprintf (FILE, "\tmov.l -%d(%%a6,%%a0.l),%s\n", \ + offset + fsize, reg_names[exact_log2 (mask)]); \ + else if (! frame_pointer_needed) \ + fprintf (FILE, "\tmov.l (%%sp)+,%s\n", \ + reg_names[exact_log2 (mask)]); \ + else \ + fprintf (FILE, "\tmov.l -%d(%%a6),%s\n", \ + offset + fsize, reg_names[exact_log2 (mask)]); } \ + else if (mask) { \ + if (big) \ + fprintf (FILE, "\tmovm.l -%d(%%a6,%%a0.l),&0x%x\n", \ + offset + fsize, mask); \ + else if (! frame_pointer_needed) \ + fprintf (FILE, "\tmovm.l (%%sp)+,&0x%x\n", mask); \ + else \ + fprintf (FILE, "\tmovm.l -%d(%%a6),&0x%x\n", \ + offset + fsize, mask); } \ + if (fmask) { \ + if (big) \ + fprintf (FILE, "\tfmovm -%d(%%a6,%%a0.l),&0x%x\n", \ + foffset + fsize, fmask); \ + else if (! frame_pointer_needed) \ + fprintf (FILE, "\tfmovm (%%sp)+,&0x%x\n", fmask); \ + else \ + fprintf (FILE, "\tfmovm -%d(%%a6),&0x%x\n", \ + foffset + fsize, fmask); } \ + if (fpoffset != 0) \ + for (regno = 55; regno >= 24; regno--) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) { \ + if (big) \ + fprintf(FILE, "\tfpmoved -%d(%%a6,%%a0.l),%s\n", \ + fpoffset + fsize, reg_names[regno]); \ + else if (! frame_pointer_needed) \ + fprintf(FILE, "\tfpmoved (%%sp)+,%s\n", \ + reg_names[regno]); \ + else \ + fprintf(FILE, "\tfpmoved -%d(%%a6),%s\n", \ + fpoffset + fsize, reg_names[regno]); \ + fpoffset -= 8; \ + } \ + if (current_function_returns_pointer) \ + fprintf (FILE, "\tmov.l %%d0,%%a0\n"); \ + if (frame_pointer_needed) \ + fprintf (FILE, "\tunlk %%a6\n"); \ + if (current_function_pops_args && current_function_args_size) \ + fprintf (FILE, "\trtd &%d\n", current_function_args_size); \ + else fprintf (FILE, "\trts\n"); } + +/* This is how to output an insn to push a register on the stack. + It need not be very fast code. */ + +#undef ASM_OUTPUT_REG_PUSH +#define ASM_OUTPUT_REG_PUSH(FILE,REGNO) \ + fprintf (FILE, "\tmov.l %s,-(%%sp)\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. */ + +#undef ASM_OUTPUT_REG_POP +#define ASM_OUTPUT_REG_POP(FILE,REGNO) \ + fprintf (FILE, "\tmov.l (%%sp)+,%s\n", reg_names[REGNO]) + +#undef ASM_FILE_START +#define ASM_FILE_START(FILE) \ +( fprintf (FILE, "#NO_APP\n"), \ + sdbout_filename ((FILE), main_input_filename)) + +#undef TEXT_SECTION_ASM_OP +#define TEXT_SECTION_ASM_OP "\ttext" + +#undef DATA_SECTION_ASM_OP +#define DATA_SECTION_ASM_OP "\tdata" + +/* This says how to output an assembler line to define a global common symbol. + We use SIZE rather than ROUNDED, as this is what the native cc does. */ + +#undef ASM_OUTPUT_COMMON +#define ASM_OUTPUT_COMMON(FILE, NAME, SIZE, ROUNDED) \ +( fputs ("\tcomm ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%u\n", ((SIZE) == 0) ? (ROUNDED) : (SIZE))) + +/* This says how to output an assembler line to define a local common symbol. + We use SIZE rather than ROUNDED, as this is what the native cc does. */ + +#undef ASM_OUTPUT_LOCAL +#define ASM_OUTPUT_LOCAL(FILE, NAME, SIZE, ROUNDED) \ +( fputs ("\tlcomm ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%u\n", ((SIZE) == 0) ? (ROUNDED) : (SIZE))) + +/* 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. */ + +#undef ASM_FORMAT_PRIVATE_NAME +#define ASM_FORMAT_PRIVATE_NAME(OUTPUT, NAME, LABELNO) \ +( (OUTPUT) = (char *) alloca (strlen ((NAME)) + 11), \ + sprintf ((OUTPUT), "%s%%%%%d", (NAME), (LABELNO))) + +/* This is how to output a command to make the user-level label named NAME + defined for reference from other files. */ + +#undef ASM_GLOBALIZE_LABEL +#define ASM_GLOBALIZE_LABEL(FILE,NAME) \ +do { fputs ("\tglobal ", FILE); \ + assemble_name (FILE, NAME); \ + fputs ("\n", FILE); \ + } while (0) + +#undef ASM_GENERATE_INTERNAL_LABEL +#define ASM_GENERATE_INTERNAL_LABEL(LABEL, PREFIX, NUM) \ + sprintf ((LABEL), "%s%%%d", (PREFIX), (NUM)) + +#undef ASM_OUTPUT_INTERNAL_LABEL +#define ASM_OUTPUT_INTERNAL_LABEL(FILE,PREFIX,NUM) \ + fprintf ((FILE), "%s%%%d:\n", (PREFIX), (NUM)) + +#undef ASM_OUTPUT_CASE_LABEL +#define ASM_OUTPUT_CASE_LABEL(FILE,PREFIX,NUM,TABLE) \ + fprintf (FILE, "\tswbeg &%d\n%s%%%d:\n", \ + XVECLEN (PATTERN (TABLE), 1), (PREFIX), (NUM)); \ + +#undef ASM_OUTPUT_DOUBLE +#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \ +do { union { double d; long l[2]; } tem; \ + tem.d = (VALUE); \ + fprintf(FILE, "\tlong 0x%x,0x%x\n", tem.l[0], tem.l[1]); \ + } while (0) + +#undef ASM_OUTPUT_FLOAT +#define ASM_OUTPUT_FLOAT(FILE,VALUE) \ +do { union { float f; long l;} tem; \ + tem.f = (VALUE); \ + fprintf (FILE, "\tlong 0x%x\n", tem.l); \ + } while (0) + +/* This is how to output an assembler line defining an `int' constant. */ + +#undef ASM_OUTPUT_INT +#define ASM_OUTPUT_INT(FILE,VALUE) \ +( fprintf (FILE, "\tlong "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +/* Likewise for `char' and `short' constants. */ + +#undef ASM_OUTPUT_SHORT +#define ASM_OUTPUT_SHORT(FILE,VALUE) \ +( fprintf (FILE, "\tshort "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +#undef ASM_OUTPUT_CHAR +#define ASM_OUTPUT_CHAR(FILE,VALUE) \ +( fprintf (FILE, "\tbyte "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +/* This is how to output an assembler line for a numeric constant byte. */ + +#undef ASM_OUTPUT_BYTE +#define ASM_OUTPUT_BYTE(FILE,VALUE) \ + fprintf (FILE, "\tbyte 0x%x\n", (VALUE)) + +#undef ASM_OUTPUT_ADDR_VEC_ELT +#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \ + fprintf (FILE, "\tlong L%%%d\n", (VALUE)) + +#undef ASM_OUTPUT_ADDR_DIFF_ELT +#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, VALUE, REL) \ + fprintf (FILE, "\tshort L%%%d-L%%%d\n", (VALUE), (REL)) + +#undef ASM_OUTPUT_ALIGN +#define ASM_OUTPUT_ALIGN(FILE,LOG) \ + if ((LOG) == 1) \ + fprintf (FILE, "\teven\n"); \ + else if ((LOG) != 0) \ + abort (); + +#undef ASM_OUTPUT_SKIP +#define ASM_OUTPUT_SKIP(FILE,SIZE) \ + fprintf (FILE, "\tspace %u\n", (SIZE)) + +#undef PRINT_OPERAND +#define PRINT_OPERAND(FILE, X, CODE) \ +{ if (CODE == '.') fprintf (FILE, "."); \ + else if (CODE == '#') fprintf (FILE, "&"); \ + else if (CODE == '-') fprintf (FILE, "-(%%sp)"); \ + else if (CODE == '+') fprintf (FILE, "(%%sp)+"); \ + else if (CODE == '@') fprintf (FILE, "(%%sp)"); \ + else if (CODE == '!') fprintf (FILE, "%%cc"); \ + else if (GET_CODE (X) == REG) \ + fprintf (FILE, "%s", reg_names[REGNO (X)]); \ + else if (GET_CODE (X) == MEM) \ + output_address (XEXP (X, 0)); \ + else if (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) == SFmode) \ + { union { double d; int i[2]; } u; \ + union { float f; int i; } u1; \ + u.i[0] = CONST_DOUBLE_LOW (X); u.i[1] = CONST_DOUBLE_HIGH (X); \ + u1.f = u.d; \ + fprintf (FILE, "&0x%x", u1.i); } \ + else if (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) == DFmode) \ + fprintf (FILE, "&0x%x%08x", CONST_DOUBLE_LOW (X), CONST_DOUBLE_HIGH (X));\ + else { putc ('&', FILE); output_addr_const (FILE, X); }} + +/* Note that this contains a kludge that knows that the only reason + we have an address (plus (label_ref...) (reg...)) + is in the insn before a tablejump, and we know that the table is + exactly 10 bytes away. */ + +#undef PRINT_OPERAND_ADDRESS +#define PRINT_OPERAND_ADDRESS(FILE, ADDR) \ +{ register rtx reg1, reg2, breg, ireg; \ + register rtx addr = ADDR; \ + rtx offset; \ + switch (GET_CODE (addr)) \ + { \ + case REG: \ + fprintf (FILE, "(%s)", reg_names[REGNO (addr)]); \ + break; \ + case PRE_DEC: \ + fprintf (FILE, "-(%s)", reg_names[REGNO (XEXP (addr, 0))]); \ + break; \ + case POST_INC: \ + fprintf (FILE, "(%s)+", reg_names[REGNO (XEXP (addr, 0))]); \ + break; \ + case PLUS: \ + reg1 = 0; reg2 = 0; \ + ireg = 0; breg = 0; \ + offset = 0; \ + if (CONSTANT_ADDRESS_P (XEXP (addr, 0))) \ + { \ + offset = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (CONSTANT_ADDRESS_P (XEXP (addr, 1))) \ + { \ + offset = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + if (GET_CODE (addr) != PLUS) ; \ + else if (GET_CODE (XEXP (addr, 0)) == SIGN_EXTEND) \ + { \ + reg1 = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (GET_CODE (XEXP (addr, 1)) == SIGN_EXTEND) \ + { \ + reg1 = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + else if (GET_CODE (XEXP (addr, 0)) == MULT) \ + { \ + reg1 = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (GET_CODE (XEXP (addr, 1)) == MULT) \ + { \ + reg1 = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + else if (GET_CODE (XEXP (addr, 0)) == REG) \ + { \ + reg1 = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (GET_CODE (XEXP (addr, 1)) == REG) \ + { \ + reg1 = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + if (GET_CODE (addr) == REG || GET_CODE (addr) == MULT \ + || GET_CODE (addr) == SIGN_EXTEND) \ + { if (reg1 == 0) reg1 = addr; else reg2 = addr; addr = 0; } \ +/* for OLD_INDEXING \ + else if (GET_CODE (addr) == PLUS) \ + { \ + if (GET_CODE (XEXP (addr, 0)) == REG) \ + { \ + reg2 = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (GET_CODE (XEXP (addr, 1)) == REG) \ + { \ + reg2 = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + } \ + */ \ + if (offset != 0) { if (addr != 0) abort (); addr = offset; } \ + if ((reg1 && (GET_CODE (reg1) == SIGN_EXTEND \ + || GET_CODE (reg1) == MULT)) \ + || (reg2 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg2)))) \ + { breg = reg2; ireg = reg1; } \ + else if (reg1 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg1))) \ + { breg = reg1; ireg = reg2; } \ + if (ireg != 0 && breg == 0 && GET_CODE (addr) == LABEL_REF) \ + { int scale = 1; \ + if (GET_CODE (ireg) == MULT) \ + { scale = INTVAL (XEXP (ireg, 1)); \ + ireg = XEXP (ireg, 0); } \ + if (GET_CODE (ireg) == SIGN_EXTEND) \ + fprintf (FILE, "10(%%pc,%s.w", \ + reg_names[REGNO (XEXP (ireg, 0))]); \ + else \ + fprintf (FILE, "10(%%pc,%s.l", \ + reg_names[REGNO (ireg)]); \ + if (scale != 1) fprintf (FILE, "*%d", scale); \ + putc (')', FILE); \ + break; } \ + if (ireg != 0 || breg != 0) \ + { int scale = 1; \ + if (breg == 0) \ + abort (); \ + if (addr != 0) \ + output_addr_const (FILE, addr); \ + fprintf (FILE, "(%s", reg_names[REGNO (breg)]); \ + if (ireg != 0) \ + putc (',', FILE); \ + if (ireg != 0 && GET_CODE (ireg) == MULT) \ + { scale = INTVAL (XEXP (ireg, 1)); \ + ireg = XEXP (ireg, 0); } \ + if (ireg != 0 && GET_CODE (ireg) == SIGN_EXTEND) \ + fprintf (FILE, "%s.w", reg_names[REGNO (XEXP (ireg, 0))]); \ + else if (ireg != 0) \ + fprintf (FILE, "%s.l", reg_names[REGNO (ireg)]); \ + if (scale != 1) fprintf (FILE, "*%d", scale); \ + putc (')', FILE); \ + break; \ + } \ + else if (reg1 != 0 && GET_CODE (addr) == LABEL_REF) \ + { fprintf (FILE, "10(%%pc,%s.w)", \ + reg_names[REGNO (reg1)]); \ + break; } \ + default: \ + output_addr_const (FILE, addr); \ + }} + + + +/* Override usual definitions of SDB output macros. + These definitions differ only in the absence of the period + at the beginning of the name of the directive + and in the use of `~' as the symbol for the current location. */ + +#define PUT_SDB_SCL(a) fprintf(asm_out_file, "\tscl\t%d;", (a)) +#define PUT_SDB_INT_VAL(a) fprintf (asm_out_file, "\tval\t%d;", (a)) +#define PUT_SDB_VAL(a) \ +( fputs ("\tval\t", asm_out_file), \ + output_addr_const (asm_out_file, (a)), \ + fputc (';', asm_out_file)) + +#define PUT_SDB_DEF(a) \ +do { fprintf (asm_out_file, "\tdef\t"); \ + ASM_OUTPUT_LABELREF (asm_out_file, a); \ + fprintf (asm_out_file, ";"); } while (0) + +#define PUT_SDB_PLAIN_DEF(a) fprintf(asm_out_file,"\tdef\t~%s;",a) +#define PUT_SDB_ENDEF fputs("\tendef\n", asm_out_file) +#define PUT_SDB_TYPE(a) fprintf(asm_out_file, "\ttype\t0%o;", a) +#define PUT_SDB_SIZE(a) fprintf(asm_out_file, "\tsize\t%d;", a) +#define PUT_SDB_START_DIM fprintf(asm_out_file, "\tdim\t") + +#define PUT_SDB_TAG(a) \ +do { fprintf (asm_out_file, "\ttag\t"); \ + ASM_OUTPUT_LABELREF (asm_out_file, a); \ + fprintf (asm_out_file, ";"); } while (0) + +#define PUT_SDB_BLOCK_START(LINE) \ + fprintf (asm_out_file, \ + "\tdef\t~bb;\tval\t~;\tscl\t100;\tline\t%d;\tendef\n", \ + (LINE)) + +#define PUT_SDB_BLOCK_END(LINE) \ + fprintf (asm_out_file, \ + "\tdef\t~eb;\tval\t~;\tscl\t100;\tline\t%d;\tendef\n", \ + (LINE)) + +#define PUT_SDB_FUNCTION_START(LINE) \ + fprintf (asm_out_file, \ + "\tdef\t~bf;\tval\t~;\tscl\t101;\tline\t%d;\tendef\n", \ + (LINE)) + +#define PUT_SDB_FUNCTION_END(LINE) \ + fprintf (asm_out_file, \ + "\tdef\t~ef;\tval\t~;\tscl\t101;\tline\t%d;\tendef\n", \ + (LINE)) + +#define PUT_SDB_EPILOGUE_END(NAME) \ + fprintf (asm_out_file, \ + "\tdef\t%s;\tval\t~;\tscl\t-1;\tendef\n", \ + (NAME)) + +#define SDB_GENERATE_FAKE(BUFFER, NUMBER) \ + sprintf ((BUFFER), "~%dfake", (NUMBER)); diff --git a/gcc-1.40/config/tm-tower.h b/gcc-1.40/config/tm-tower.h new file mode 100644 index 0000000..68e74a6 --- /dev/null +++ b/gcc-1.40/config/tm-tower.h @@ -0,0 +1,100 @@ +/* Definitions of target machine for GNU compiler. + Copyright (C) 1990 Free Software Foundation, Inc. + + Written by Robert Andersson, International Systems, Oslo, Norway. + Please send bug reports, questions and improvements to ra@intsys.no. + + For NCR Tower 32/4x0 and 32/6x0 running System V Release 3. + I don't have access to 200/700/800/850 machines, so I don't know if it + works on those as well. It shouldn't be far from it however. + The hardware floating point support is completely untested, as I do + not have access to a machine with a 6888x FPU in it. + It does not work on the System V Release 2 based OS releases. Making it + work will not be easy, due to the silly way in which stack expansion is + implemented in the OS. + + This file is included in both tm-tower-as.h and tm-tower-gc.h, and contains + definitions common to both of them. Do *NOT* include this file directly. + + +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 1, 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 "tm-m68k.h" + + +/* See tm-m68k.h. 5 means 68020 with no 68881. */ + +#define TARGET_DEFAULT 5 + +/* Names to predefine in the preprocessor for this target machine. */ + +#ifdef tower32_200 +#define CPP_PREDEFINES "-Dunix -Dtower32 -Dtower32_200" +#endif +#ifdef tower32_600 +#define CPP_PREDEFINES "-Dunix -Dtower32 -Dtower32_600" +#endif +#ifdef tower32_700 +#define CPP_PREDEFINES "-Dunix -Dtower32 -Dtower32_700" +#endif +#ifdef tower32_800 +#define CPP_PREDEFINES "-Dunix -Dtower32 -Dtower32_800" +#endif +#ifdef tower32_850 +#define CPP_PREDEFINES "-Dunix -Dtower32 -Dtower32_850" +#endif + +/* The startfiles and libraries depend on the -p and -m68881 options. + The Tower does not support the -pg option. */ + +#define LINK_SPEC \ +"%{p:%{m68881:-L/usr/lib/fp/libp} -L/usr/lib/libp} \ + %{m68881:-L/usr/lib/fp}" + +#define LIB_SPEC "-lc %{m68881:/usr/lib/fp/crtn.o}%{!m68881:/lib/crtn.o}" + +/* Use mem* functions, recognize #ident lines. */ + +#define TARGET_MEM_FUNCTIONS +#define IDENT_DIRECTIVE + +/* This is only used in g++, don't prepend underscore. */ + +#define NO_UNDERSCORES + +/* Every structure and union's size must be a multiple of two bytes. */ + +#define STRUCTURE_SIZE_BOUNDARY 16 + +/* All register names should have a leading % character. */ + +#undef REGISTER_NAMES +#define REGISTER_NAMES \ +{"%d0", "%d1", "%d2", "%d3", "%d4", "%d5", "%d6", "%d7", \ + "%a0", "%a1", "%a2", "%a3", "%a4", "%a5", "%a6", "%sp", \ + "%fp0", "%fp1", "%fp2", "%fp3", "%fp4", "%fp5", "%fp6", "%fp7", \ + "%fpa0", "%fpa1", "%fpa2", "%fpa3", "%fpa4", "%fpa5", "%fpa6", "%fpa7", \ + "%fpa8", "%fpa9", "%fpa10", "%fpa11", "%fpa12", "%fpa13", "%fpa14", "%fpa15",\ + "%fpa16","%fpa17", "%fpa18", "%fpa19", "%fpa20", "%fpa21", "%fpa22","%fpa23",\ + "%fpa24","%fpa25", "%fpa26", "%fpa27", "%fpa28", "%fpa29", "%fpa30","%fpa31"} + +/* We do not want leading underscores. */ + +#undef ASM_OUTPUT_LABELREF +#define ASM_OUTPUT_LABELREF(FILE,NAME) \ + fprintf (FILE, "%s", NAME) diff --git a/gcc-1.40/config/tm-ultrix.h b/gcc-1.40/config/tm-ultrix.h new file mode 100644 index 0000000..025dc0d --- /dev/null +++ b/gcc-1.40/config/tm-ultrix.h @@ -0,0 +1,7 @@ +#include "tm-vax.h" + +#undef CPP_PREDEFINES +#define CPP_PREDEFINES "-Dultrix -Dbsd4_2 -Dvax -Dunix -D__vax" + +/* By default, allow $ to be part of an identifier. */ +#define DOLLARS_IN_IDENTIFIERS 1 diff --git a/gcc-1.40/config/tm-vax.h b/gcc-1.40/config/tm-vax.h new file mode 100644 index 0000000..f92af96 --- /dev/null +++ b/gcc-1.40/config/tm-vax.h @@ -0,0 +1,1080 @@ +/* Definitions of target machine for GNU compiler. Vax version. + Copyright (C) 1987, 1988 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 1, 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. */ + + +/* Names to predefine in the preprocessor for this target machine. */ + +#define CPP_PREDEFINES "-Dvax -Dunix" + +/* Print subsidiary information on the compiler version in use. */ + +#define TARGET_VERSION fprintf (stderr, " (vax)"); + +/* Run-time compilation parameters selecting different hardware subsets. */ + +extern int target_flags; + +/* Macros used in the machine description to test the flags. */ + +/* Nonzero if compiling code that Unix assembler can assemble. */ +#define TARGET_UNIX_ASM (target_flags & 1) + +/* Nonzero if compiling with VAX-11 "C" style structure alignment */ +#define TARGET_VAXC_ALIGNMENT (target_flags & 2) + +/* Nonzero if compiling with `G'-format floating point */ +#define TARGET_G_FLOAT (target_flags & 4) + +/* 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 \ + { {"unix", 1}, \ + {"gnu", -1}, \ + {"vaxc-alignment", 2}, \ + {"g", 4}, \ + {"g-float", 4}, \ + {"d", -4}, \ + {"d-float", -4}, \ + { "", TARGET_DEFAULT}} + +/* Default target_flags if no switches specified. */ + +#ifndef TARGET_DEFAULT +#define TARGET_DEFAULT 1 +#endif + +/* Target machine storage layout */ + +/* Define this if most significant bit is lowest numbered + in instructions that operate on numbered bit-fields. + This is not true on the vax. */ +/* #define BITS_BIG_ENDIAN */ + +/* Define this if most significant byte of a word is the lowest numbered. */ +/* That is not true on the vax. */ +/* #define BYTES_BIG_ENDIAN */ + +/* Define this if most significant word of a multiword number is numbered. */ +/* This is not true on the vax. */ +/* #define WORDS_BIG_ENDIAN */ + +/* Number of bits in an addressible 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 32 + +/* Width of a word, in units (bytes). */ +#define UNITS_PER_WORD 4 + +/* Width in bits of a pointer. + See also the macro `Pmode' defined below. */ +#define POINTER_SIZE 32 + +/* Allocation boundary (in *bits*) for storing pointers in memory. */ +#define POINTER_BOUNDARY (TARGET_VAXC_ALIGNMENT ? 8 : 32) + +/* Allocation boundary (in *bits*) for storing arguments in argument list. */ +#define PARM_BOUNDARY 32 + +/* Allocation boundary (in *bits*) for the code of a function. */ +#define FUNCTION_BOUNDARY 16 + +/* Alignment of field after `int : 0' in a structure. */ +#define EMPTY_FIELD_BOUNDARY (TARGET_VAXC_ALIGNMENT ? 8 : 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 (! TARGET_VAXC_ALIGNMENT) + +/* No data type wants to be aligned rounder than this. */ +#define BIGGEST_ALIGNMENT (TARGET_VAXC_ALIGNMENT ? 8 : 32) + +/* Define this if move instructions will actually fail to work + when given unaligned data. */ +/* #define STRICT_ALIGNMENT */ + +/* 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. */ +#define FIRST_PSEUDO_REGISTER 16 + +/* 1 for registers that have pervasive standard uses + and are not available for the register allocator. + On the vax, these are the AP, FP, SP and PC. */ +#define FIXED_REGISTERS {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1} + +/* 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, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1} + +/* 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 the vax, all registers are one word long. */ +#define HARD_REGNO_NREGS(REGNO, MODE) \ + ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD) + +/* Value is 1 if hard register REGNO can hold a value of machine-mode MODE. + On the vax, all registers can hold all modes. */ +#define HARD_REGNO_MODE_OK(REGNO, MODE) 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) 1 + +/* Specify the registers used for certain standard purposes. + The values of these macros are register numbers. */ + +/* Vax pc is overloaded on a register. */ +#define PC_REGNUM 15 + +/* Register to use for pushing function arguments. */ +#define STACK_POINTER_REGNUM 14 + +/* Base register for access to local variables of the function. */ +#define FRAME_POINTER_REGNUM 13 + +/* 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. */ +#define FRAME_POINTER_REQUIRED 1 + +/* Base register for access to arguments of the function. */ +#define ARG_POINTER_REGNUM 12 + +/* Register in which static-chain is passed to a function. */ +#define STATIC_CHAIN_REGNUM 0 + +/* Register in which address to store a structure value + is passed to a function. */ +#define STRUCT_VALUE_REGNUM 1 + +/* 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 vax has only one kind of registers, so NO_REGS and ALL_REGS + are the only classes. */ + +enum reg_class { NO_REGS, ALL_REGS, LIM_REG_CLASSES }; + +#define N_REG_CLASSES (int) LIM_REG_CLASSES + +/* Since GENERAL_REGS is the same class as ALL_REGS, + don't give it a different class number; just make it an alias. */ + +#define GENERAL_REGS ALL_REGS + +/* Give names of register classes as strings for dump file. */ + +#define REG_CLASS_NAMES \ + {"NO_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, 0xffff} + +/* 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. */ + +#define REGNO_REG_CLASS(REGNO) ALL_REGS + +/* The class value for index registers, and the one for base regs. */ + +#define INDEX_REG_CLASS ALL_REGS +#define BASE_REG_CLASS ALL_REGS + +/* Get reg_class from a letter such as appears in the machine description. */ + +#define REG_CLASS_FROM_LETTER(C) 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. */ + +#define CONST_OK_FOR_LETTER_P(VALUE, C) 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) 1 + +/* 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. */ + +#define PREFERRED_RELOAD_CLASS(X,CLASS) (CLASS) + +/* Return the maximum number of consecutive registers + needed to represent mode MODE in a register of class CLASS. */ +/* On the vax, this is always the size of MODE in words, + since all registers are the same size. */ +#define CLASS_MAX_NREGS(CLASS, MODE) \ + ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD) + +/* Stack layout; function entry, exit and calling. */ + +/* Define this if pushing a word on the stack + makes the stack pointer a smaller address. */ +#define STACK_GROWS_DOWNWARD + +/* Define this if longjmp restores from saved registers + rather than from what setjmp saved. */ +#define LONGJMP_RESTORE_FROM_STACK + +/* 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. */ +#define STARTING_FRAME_OFFSET 0 + +/* If we generate an insn to push BYTES bytes, + this says how many the stack pointer really advances by. + On the vax, -(sp) pushes only the bytes of the operands. */ +#define PUSH_ROUNDING(BYTES) (BYTES) + +/* Offset of first parameter from the argument pointer register value. */ +#define FIRST_PARM_OFFSET(FNDECL) 4 + +/* Value is 1 if returning from a function call automatically + pops the arguments described by the number-of-args field in the call. + 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. + + On the Vax, the RET insn always pops all the args for any function. */ + +#define RETURN_POPS_ARGS(FUNTYPE) 1 + +/* 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 the Vax the return value is in R0 regardless. */ + +#define FUNCTION_VALUE(VALTYPE, FUNC) \ + gen_rtx (REG, TYPE_MODE (VALTYPE), 0) + +/* Define how to find the value returned by a library function + assuming the value has mode MODE. */ + +/* On the Vax the return value is in R0 regardless. */ + +#define LIBCALL_VALUE(MODE) gen_rtx (REG, MODE, 0) + +/* Define this if PCC uses the nonreentrant convention for returning + structure and union values. */ + +#define PCC_STATIC_STRUCT_RETURN + +/* 1 if N is a possible register number for a function value. + On the Vax, R0 is the only register thus used. */ + +#define FUNCTION_VALUE_REGNO_P(N) ((N) == 0) + +/* 1 if N is a possible register number for function argument passing. + On the Vax, no registers are used in this way. */ + +#define FUNCTION_ARG_REGNO_P(N) 0 + +/* 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 the vax, this is a single integer, which is a number of bytes + of arguments scanned so far. */ + +#define CUMULATIVE_ARGS int + +/* 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. + + On the vax, the offset starts at 0. */ + +#define INIT_CUMULATIVE_ARGS(CUM,FNTYPE) \ + ((CUM) = 0) + +/* 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.) */ + +#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \ + ((CUM) += ((MODE) != BLKmode \ + ? (GET_MODE_SIZE (MODE) + 3) & ~3 \ + : (int_size_in_bytes (TYPE) + 3) & ~3)) + +/* Define where to put the arguments 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). */ + +/* On the vax all args are pushed. */ + +#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) 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. */ + +#define FUNCTION_PROLOGUE(FILE, SIZE) \ +{ register int regno; \ + register int mask = 0; \ + extern char call_used_regs[]; \ + for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) \ + if (regs_ever_live[regno] && !call_used_regs[regno]) \ + mask |= 1 << regno; \ + fprintf (FILE, "\t.word 0x%x\n", mask); \ + MAYBE_VMS_FUNCTION_PROLOGUE(FILE) \ + if ((SIZE) >= 64) fprintf (FILE, "\tmovab %d(sp),sp\n", -SIZE);\ + else if (SIZE) fprintf (FILE, "\tsubl2 $%d,sp\n", (SIZE)); } + +/* tm-vms.h redefines this. */ +#define MAYBE_VMS_FUNCTION_PROLOGUE(FILE) + +/* Output assembler code to FILE to increment profiler label # LABELNO + for profiling a function entry. */ + +#define FUNCTION_PROFILER(FILE, LABELNO) \ + fprintf (FILE, "\tmovab LP%d,r0\n\tjsb mcount\n", (LABELNO)); + +/* Output assembler code to FILE to initialize this source file's + basic block profiling info, if that has not already been done. */ + +#define FUNCTION_BLOCK_PROFILER(FILE, LABELNO) \ + fprintf (FILE, "\ttstl LPBX0\n\tjneq LPI%d\n\tpushal LPBX0\n\tcalls $1,__bb_init_func\nLPI%d:\n", \ + LABELNO, LABELNO); + +/* Output assembler code to FILE to increment the entry-count for + the BLOCKNO'th basic block in this source file. This is a real pain in the + sphincter on a VAX, since we do not want to change any of the bits in the + processor status word. The way it is done here, it is pushed onto the stack + before any flags have changed, and then the stack is fixed up to account for + the fact that the instruction to restore the flags only reads a word. + It may seem a bit clumsy, but at least it works. +*/ + +#define BLOCK_PROFILER(FILE, BLOCKNO) \ + fprintf (FILE, "\tmovpsl -(sp)\n\tmovw (sp),2(sp)\n\taddl2 $2,sp\n\taddl2 $1,LPBX2+%d\n\tbicpsw $255\n\tbispsw (sp)+\n", \ + 4 * BLOCKNO) + +/* 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. */ + +#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. */ + +/* #define FUNCTION_EPILOGUE(FILE, SIZE) */ + +/* If the memory address ADDR is relative to the frame pointer, + correct it to be relative to the stack pointer instead. + This is for when we don't use a frame pointer. + ADDR should be a variable name. */ + +#define FIX_FRAME_POINTER_ADDRESS(ADDR,DEPTH) abort (); + +/* 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) < FIRST_PSEUDO_REGISTER || reg_renumber[regno] >= 0) +#define REGNO_OK_FOR_BASE_P(regno) \ +((regno) < FIRST_PSEUDO_REGISTER || reg_renumber[regno] >= 0) + +/* Maximum number of registers that can appear in a valid memory address. */ + +#define MAX_REGS_PER_ADDRESS 2 + +/* 1 if X is an rtx for a constant that is a valid address. */ + +#define CONSTANT_ADDRESS_P(X) (CONSTANT_P (X) && LEGITIMATE_CONSTANT_P (X)) + +/* Nonzero if the constant value X is a legitimate general operand. + It is given that X satisfies CONSTANT_P or is a CONST_DOUBLE. */ + +#ifdef NO_EXTERNAL_INDIRECT_ADDRESS +#define LEGITIMATE_CONSTANT_P(X) \ + (! (GET_CODE ((X)) == CONST \ + && GET_CODE (XEXP ((X), 0)) == PLUS \ + && GET_CODE (XEXP (XEXP ((X), 0), 0)) == SYMBOL_REF \ + && EXTERNAL_SYMBOL_P (XEXP (XEXP ((X), 0), 0)))) +#else +#define LEGITIMATE_CONSTANT_P(X) 1 +#endif + +/* 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. */ + +#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) 1 +/* 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) 1 + +#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)) + +#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. + + The other macros defined here are used only in GO_IF_LEGITIMATE_ADDRESS, + except for CONSTANT_ADDRESS_P which is actually machine-independent. */ + +/* 1 if X is an address that we could indirect through. */ +#ifdef NO_EXTERNAL_INDIRECT_ADDRESS +#define INDIRECTABLE_CONSTANT_ADDRESS_P(X) \ + (GET_CODE (X) == LABEL_REF \ + || (GET_CODE (X) == SYMBOL_REF && !EXTERNAL_SYMBOL_P (X)) \ + || (GET_CODE (X) == CONST && LEGITIMATE_CONSTANT_P(X)) \ + || GET_CODE (X) == CONST_INT) + +#define INDIRECTABLE_ADDRESS_P(X) \ + (INDIRECTABLE_CONSTANT_ADDRESS_P (X) \ + || (GET_CODE (X) == REG && REG_OK_FOR_BASE_P (X)) \ + || (GET_CODE (X) == PLUS \ + && GET_CODE (XEXP (X, 0)) == REG \ + && REG_OK_FOR_BASE_P (XEXP (X, 0)) \ + && INDIRECTABLE_CONSTANT_ADDRESS_P (XEXP (X, 1)))) +#else +#define INDIRECTABLE_CONSTANT_ADDRESS_P(X) CONSTANT_ADDRESS_P(X) +#define INDIRECTABLE_ADDRESS_P(X) \ + (CONSTANT_ADDRESS_P (X) \ + || (GET_CODE (X) == REG && REG_OK_FOR_BASE_P (X)) \ + || (GET_CODE (X) == PLUS \ + && GET_CODE (XEXP (X, 0)) == REG \ + && REG_OK_FOR_BASE_P (XEXP (X, 0)) \ + && CONSTANT_ADDRESS_P (XEXP (X, 1)))) +#endif + +/* Non-zero if this is a valid address without indexing or indirection. */ +#define NONINDIRECT_ADDRESS_P(X) \ + (CONSTANT_ADDRESS_P (X) \ + || (GET_CODE (X) == REG && REG_OK_FOR_BASE_P (X)) \ + || (GET_CODE (X) == PLUS \ + && GET_CODE (XEXP (X, 0)) == REG \ + && REG_OK_FOR_BASE_P (XEXP (X, 0)) \ + && CONSTANT_ADDRESS_P (XEXP (X, 1)))) + +/* Go to ADDR if X is a valid address not using indexing. + (This much is the easy part.) */ +#define GO_IF_NONINDEXED_ADDRESS(X, ADDR) \ +{ register rtx xfoob = (X); \ + if (GET_CODE (xfoob) == REG) goto ADDR; \ + if (NONINDIRECT_ADDRESS_P (xfoob)) goto ADDR; \ + xfoob = XEXP (X, 0); \ + if (GET_CODE (X) == MEM && INDIRECTABLE_ADDRESS_P (xfoob)) \ + goto ADDR; \ + if ((GET_CODE (X) == PRE_DEC || GET_CODE (X) == POST_INC) \ + && GET_CODE (xfoob) == REG && REG_OK_FOR_BASE_P (xfoob)) \ + goto ADDR; } + +/* 1 if PROD is either a reg times size of mode MODE + or just a reg, if MODE is just one byte. + This macro's expansion uses the temporary variables xfoo0 and xfoo1 + that must be declared in the surrounding context. */ +#define INDEX_TERM_P(PROD, MODE) \ +(GET_MODE_SIZE (MODE) == 1 \ + ? (GET_CODE (PROD) == REG && REG_OK_FOR_BASE_P (PROD)) \ + : (GET_CODE (PROD) == MULT \ + && \ + (xfoo0 = XEXP (PROD, 0), xfoo1 = XEXP (PROD, 1), \ + ((GET_CODE (xfoo0) == CONST_INT \ + && INTVAL (xfoo0) == GET_MODE_SIZE (MODE) \ + && GET_CODE (xfoo1) == REG \ + && REG_OK_FOR_INDEX_P (xfoo1)) \ + || \ + (GET_CODE (xfoo1) == CONST_INT \ + && INTVAL (xfoo1) == GET_MODE_SIZE (MODE) \ + && GET_CODE (xfoo0) == REG \ + && REG_OK_FOR_INDEX_P (xfoo0)))))) + +/* Go to ADDR if X is the sum of a register + and a valid index term for mode MODE. */ +#define GO_IF_REG_PLUS_INDEX(X, MODE, ADDR) \ +{ register rtx xfooa; \ + if (GET_CODE (X) == PLUS) \ + { if (GET_CODE (XEXP (X, 0)) == REG \ + && REG_OK_FOR_BASE_P (XEXP (X, 0)) \ + && (xfooa = XEXP (X, 1), \ + INDEX_TERM_P (xfooa, MODE))) \ + goto ADDR; \ + if (GET_CODE (XEXP (X, 1)) == REG \ + && REG_OK_FOR_BASE_P (XEXP (X, 1)) \ + && (xfooa = XEXP (X, 0), \ + INDEX_TERM_P (xfooa, MODE))) \ + goto ADDR; } } + +#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \ +{ register rtx xfoo, xfoo0, xfoo1; \ + GO_IF_NONINDEXED_ADDRESS (X, ADDR); \ + if (GET_CODE (X) == PLUS) \ + { /* Handle
[index] represented with index-sum outermost */\ + xfoo = XEXP (X, 0); \ + if (INDEX_TERM_P (xfoo, MODE)) \ + { GO_IF_NONINDEXED_ADDRESS (XEXP (X, 1), ADDR); } \ + xfoo = XEXP (X, 1); \ + if (INDEX_TERM_P (xfoo, MODE)) \ + { GO_IF_NONINDEXED_ADDRESS (XEXP (X, 0), ADDR); } \ + /* Handle offset(reg)[index] with offset added outermost */ \ + if (INDIRECTABLE_CONSTANT_ADDRESS_P (XEXP (X, 0))) \ + { if (GET_CODE (XEXP (X, 1)) == REG \ + && REG_OK_FOR_BASE_P (XEXP (X, 1))) \ + goto ADDR; \ + GO_IF_REG_PLUS_INDEX (XEXP (X, 1), MODE, ADDR); } \ + if (INDIRECTABLE_CONSTANT_ADDRESS_P (XEXP (X, 1))) \ + { if (GET_CODE (XEXP (X, 0)) == REG \ + && REG_OK_FOR_BASE_P (XEXP (X, 0))) \ + goto ADDR; \ + GO_IF_REG_PLUS_INDEX (XEXP (X, 0), MODE, 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. + + For the vax, nothing needs to be done. */ + +#define LEGITIMIZE_ADDRESS(X,OLDX,MODE,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 VAX, the predecrement and postincrement address depend thus + (the amount of decrement or increment being the length of the operand) + and all indexed address depend thus (because the index scale factor + is the length of the operand). */ +#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR,LABEL) \ + { if (GET_CODE (ADDR) == POST_INC || GET_CODE (ADDR) == PRE_DEC) \ + goto LABEL; \ + if (GET_CODE (ADDR) == PLUS) \ + { if (CONSTANT_ADDRESS_P (XEXP (ADDR, 0)) \ + && GET_CODE (XEXP (ADDR, 1)) == REG); \ + else if (CONSTANT_ADDRESS_P (XEXP (ADDR, 1)) \ + && GET_CODE (XEXP (ADDR, 0)) == REG); \ + else goto LABEL; }} + +/* Specify the machine mode that this machine uses + for the index in the tablejump instruction. */ +#define CASE_VECTOR_MODE HImode + +/* Define this if the case 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 this if the case instruction drops through after the table + when the index is out of range. Don't define it if the case insn + jumps to the default label instead. */ +#define CASE_DROPS_THROUGH + +/* 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 + +/* This flag, if defined, says the same insns that convert to a signed fixnum + also convert validly to an unsigned one. */ +#define FIXUNS_TRUNC_LIKE_FIX_TRUNC + +/* Max number of bytes we can move from memory to memory + in one reasonably fast instruction. */ +#define MOVE_MAX 8 + +/* Define this if zero-extension is slow (more than one real instruction). */ +/* #define SLOW_ZERO_EXTEND */ + +/* Nonzero if access to memory by bytes is slow and undesirable. */ +#define SLOW_BYTE_ACCESS 0 + +/* Define if shifts truncate the shift count + which implies one can omit a sign-extension or zero-extension + of a shift count. */ +/* #define SHIFT_COUNT_TRUNCATED */ + +/* Shift counts can be negative. */ +#define NEGATIVE_SHIFT_COUNTS 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 SImode + +/* 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 QImode + +/* 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) \ + case CONST_INT: \ + /* Constant zero is super cheap due to clr instruction. */ \ + if (RTX == const0_rtx) return 0; \ + if ((unsigned) INTVAL (RTX) < 077) return 1; \ + case CONST: \ + case LABEL_REF: \ + case SYMBOL_REF: \ + return 3; \ + case CONST_DOUBLE: \ + return 5; + +/* + * We can use the BSD C library routines for the gnulib calls that are + * still generated, since that's what they boil down to anyways. + */ + +#define UDIVSI3_LIBCALL "*udiv" +#define UMODSI3_LIBCALL "*urem" + +/* Check a `double' value for validity for a particular machine mode. */ + +/* note that it is very hard to accidently create a number that fits in a + double but not in a float, since their ranges are almost the same */ +#define CHECK_FLOAT_VALUE(mode, d) \ + if ((mode) == SFmode) \ + { \ + if ((d) > 1.7014117331926444e+38) \ + { error ("magnitude of constant too large for `float'"); \ + (d) = 1.7014117331926444e+38; } \ + else if ((d) < -1.7014117331926444e+38) \ + { error ("magnitude of constant too large for `float'"); \ + (d) = -1.7014117331926444e+38; } \ + else if (((d) > 0) && ((d) < 2.9387358770557188e-39)) \ + { warning ("`float' constant truncated to zero"); \ + (d) = 0.0; } \ + else if (((d) < 0) && ((d) > -2.9387358770557188e-39)) \ + { warning ("`float' constant truncated to zero"); \ + (d) = 0.0; } \ + } + +/* For future reference: + D Float: 9 bit, sign magnitude, excess 128 binary exponent + normalized 56 bit fraction, redundant bit not represented + approximately 16 decimal digits of precision + + The values to use if we trust decimal to binary conversions: +#define MAX_D_FLOAT 1.7014118346046923e+38 +#define MIN_D_FLOAT .29387358770557188e-38 + + G float: 12 bit, sign magnitude, excess 1024 binary exponent + normalized 53 bit fraction, redundant bit not represented + approximately 15 decimal digits precision + + The values to use if we trust decimal to binary conversions: +#define MAX_G_FLOAT .898846567431157e+308 +#define MIN_G_FLOAT .556268464626800e-308 +*/ + +/* Tell final.c how to eliminate redundant test instructions. */ + +/* Here we define machine-dependent flags and fields in cc_status + (see `conditions.h'). No extra ones are needed for the vax. */ + +/* Store in cc_status the expressions + that the condition codes will describe + after execution of an instruction whose pattern is EXP. + Do not alter them if the instruction would not alter the cc's. */ + +#define NOTICE_UPDATE_CC(EXP, INSN) \ +{ if (GET_CODE (EXP) == SET) \ + { if (GET_CODE (SET_SRC (EXP)) == CALL) \ + CC_STATUS_INIT; \ + else if (GET_CODE (SET_DEST (EXP)) != PC) \ + { cc_status.flags = 0; \ + cc_status.value1 = SET_DEST (EXP); \ + cc_status.value2 = SET_SRC (EXP); } } \ + else if (GET_CODE (EXP) == PARALLEL \ + && GET_CODE (XVECEXP (EXP, 0, 0)) == SET \ + && GET_CODE (SET_DEST (XVECEXP (EXP, 0, 0))) != PC) \ + { cc_status.flags = 0; \ + cc_status.value1 = SET_DEST (XVECEXP (EXP, 0, 0)); \ + cc_status.value2 = SET_SRC (XVECEXP (EXP, 0, 0)); } \ + /* PARALLELs whose first element sets the PC are aob, sob insns. \ + They do change the cc's. So drop through and forget the cc's. */ \ + else CC_STATUS_INIT; \ + if (cc_status.value1 && GET_CODE (cc_status.value1) == REG \ + && cc_status.value2 \ + && reg_overlap_mentioned_p (cc_status.value1, cc_status.value2)) \ + cc_status.value2 = 0; \ + if (cc_status.value1 && GET_CODE (cc_status.value1) == MEM \ + && cc_status.value2 \ + && GET_CODE (cc_status.value2) == MEM) \ + cc_status.value2 = 0; } +/* Actual condition, one line up, should be that value2's address + depends on value1, but that is too much of a pain. */ + +#define OUTPUT_JUMP(NORMAL, FLOAT, NO_OV) \ +{ if (cc_status.flags & CC_NO_OVERFLOW) \ + return NO_OV; \ + return NORMAL; } + +/* Control the assembler format that we output. */ + +/* Output at beginning of assembler file. */ + +#define ASM_FILE_START(FILE) fprintf (FILE, "#NO_APP\n"); + +/* Output to assembler file text saying following lines + may contain character constants, extra white space, comments, etc. */ + +#define ASM_APP_ON "#APP\n" + +/* Output to assembler file text saying following lines + no longer contain unusual constructs. */ + +#define ASM_APP_OFF "#NO_APP\n" + +/* 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 \ +{"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", \ + "r9", "r10", "r11", "ap", "fp", "sp", "pc"} + +/* This is BSD, so it wants DBX format. */ + +#define DBX_DEBUGGING_INFO + +/* How to renumber registers for dbx and gdb. + Vax needs no change in the numeration. */ + +#define DBX_REGISTER_NUMBER(REGNO) (REGNO) + +/* Do not break .stabs pseudos into continuations. */ + +#define DBX_CONTIN_LENGTH 0 + +/* This is the char to use for continuation (in case we need to turn + continuation back on). */ + +#define DBX_CONTIN_CHAR '?' + +/* Don't use the `xsfoo;' construct in DBX output; this system + doesn't support it. */ + +#define DBX_NO_XREFS + +/* Output the .stabs for a C `static' variable in the data section. */ +#define DBX_STATIC_STAB_DATA_SECTION + +/* Vax specific: which type character is used for type double? */ + +#define ASM_DOUBLE_CHAR (TARGET_G_FLOAT ? 'g' : 'd') + +/* 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 (".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. */ + +#define ASM_OUTPUT_LABELREF(FILE,NAME) \ + fprintf (FILE, "_%s", NAME) + +/* 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) \ + 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%d", PREFIX, NUM) + +/* This is how to output an assembler line defining a `double' constant. + It is .dfloat or .gfloat, depending. */ + +#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \ + fprintf (FILE, "\t.%cfloat 0%c%.20e\n", ASM_DOUBLE_CHAR, \ + ASM_DOUBLE_CHAR, (VALUE)) + +/* This is how to output an assembler line defining a `float' constant. */ + +#define ASM_OUTPUT_FLOAT(FILE,VALUE) \ + fprintf (FILE, "\t.float 0f%.20e\n", (VALUE)) + +/* This is how to output an assembler line defining an `int' constant. */ + +#define ASM_OUTPUT_INT(FILE,VALUE) \ +( fprintf (FILE, "\t.long "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +/* Likewise for `char' and `short' constants. */ + +#define ASM_OUTPUT_SHORT(FILE,VALUE) \ +( fprintf (FILE, "\t.word "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +#define ASM_OUTPUT_CHAR(FILE,VALUE) \ +( fprintf (FILE, "\t.byte "), \ + 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.byte 0x%x\n", (VALUE)) + +/* This is how to output an insn to push a register on the stack. + It need not be very fast code. */ + +#define ASM_OUTPUT_REG_PUSH(FILE,REGNO) \ + fprintf (FILE, "\tpushl %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, "\tmovl (sp)+,%s\n", reg_names[REGNO]) + +/* This is how to output an element of a case-vector that is absolute. + (The Vax does not use such vectors, + but we must define this macro anyway.) */ + +#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \ + fprintf (FILE, "\t.long L%d\n", VALUE) + +/* This is how to output an element of a case-vector that is relative. */ + +#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, VALUE, REL) \ + fprintf (FILE, "\t.word L%d-L%d\n", VALUE, REL) + +/* 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) \ + fprintf (FILE, "\t.align %d\n", (LOG)) + +/* This is how to output an assembler line + that says to advance the location counter by SIZE bytes. */ + +#define ASM_OUTPUT_SKIP(FILE,SIZE) \ + fprintf (FILE, "\t.space %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 (".comm ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%u\n", (ROUNDED))) + +/* This says how to output an assembler line + to define a local common symbol. */ + +#define ASM_OUTPUT_LOCAL(FILE, NAME, SIZE, ROUNDED) \ +( fputs (".lcomm ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%d\n", (ROUNDED))) + +/* 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 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 + +/* Print an instruction operand X on file FILE. + CODE is the code from the %-spec that requested printing this operand; + if `%z3' was used to print operand 3, then CODE is 'z'. + On the Vax, the only code used is `#', indicating that either + `d' or `g' should be printed, depending on whether we're using dfloat + or gfloat. */ + +#define PRINT_OPERAND_PUNCT_VALID_P(CODE) \ + ((CODE) == '#') + +#define PRINT_OPERAND(FILE, X, CODE) \ +{ if (CODE == '#') fputc (ASM_DOUBLE_CHAR, FILE); \ + else if (GET_CODE (X) == REG) \ + fprintf (FILE, "%s", reg_names[REGNO (X)]); \ + else if (GET_CODE (X) == MEM) \ + output_address (XEXP (X, 0)); \ + else if (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) != DImode) \ + { union { double d; int i[2]; } u; \ + u.i[0] = CONST_DOUBLE_LOW (X); u.i[1] = CONST_DOUBLE_HIGH (X); \ + fprintf (FILE, "$0%c%.20e", ASM_DOUBLE_CHAR, u.d); } \ + else { putc ('$', FILE); output_addr_const (FILE, X); }} + +/* Print a memory operand whose address is X, on file FILE. + This uses a function in output-vax.c. */ + +#define PRINT_OPERAND_ADDRESS(FILE, ADDR) \ + print_operand_address (FILE, ADDR) diff --git a/gcc-1.40/config/tm-vaxv.h b/gcc-1.40/config/tm-vaxv.h new file mode 100644 index 0000000..78fbf05 --- /dev/null +++ b/gcc-1.40/config/tm-vaxv.h @@ -0,0 +1,62 @@ +/* Definitions of target machine for GNU compiler. Vax sysV version. + Copyright (C) 1988 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 1, 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 "tm-vax.h" + +/* Cope with these under SysV */ + +#define SCCS_DIRECTIVE + +/* Output #ident as a .ident. */ + +#define ASM_OUTPUT_IDENT(FILE, NAME) fprintf (FILE, "\t.ident \"%s\"\n", NAME); + +#undef DBX_DEBUGGING_INFO +#define SDB_DEBUGGING_INFO + +/* The .file command should always begin the output. */ +#undef ASM_FILE_START +#define ASM_FILE_START(FILE) sdbout_filename ((FILE), main_input_filename) + +#undef ASM_OUTPUT_ALIGN +#define ASM_OUTPUT_ALIGN(FILE,LOG) \ + fprintf(FILE, "\t.align %d\n", 1 << (LOG)) + +#undef ASM_OUTPUT_LOCAL +#define ASM_OUTPUT_LOCAL(FILE,NAME,SIZE,ROUNDED) \ +( data_section (), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ":\n\t.space %u\n", (ROUNDED))) + +#define ASM_OUTPUT_ASCII(FILE,PTR,LEN) \ +{ \ + char *s; \ + int i; \ + for (i = 0, s = (PTR); i < (LEN); s++, i++) \ + { \ + if ((i % 8) == 0) \ + fputs ("\n\t.byte\t", (FILE)); \ + fprintf ((FILE), "%s0x%x", (i%8?",":""), (unsigned)*s); \ + } \ + fputs ("\n", (FILE)); \ +} + +#undef ASM_OUTPUT_DOUBLE +#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \ + fprintf (FILE, "\t.double 0d%.20e\n", (VALUE)) diff --git a/gcc-1.40/config/tm-vms.h b/gcc-1.40/config/tm-vms.h new file mode 100644 index 0000000..2e91a73 --- /dev/null +++ b/gcc-1.40/config/tm-vms.h @@ -0,0 +1,117 @@ +/* Output variables, constants and external declarations, for GNU compiler. + Copyright (C) 1988 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 1, 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. */ + +#define NO_EXTERNAL_INDIRECT_ADDRESS /* Alter some macro definitions. */ +#include "tm-vax.h" + +#undef CPP_PREDEFINES +#undef TARGET_VERSION +#undef TARGET_DEFAULT +#undef CALL_USED_REGISTERS +#undef MAYBE_VMS_FUNCTION_PROLOGUE + +/* Predefine this in CPP because VMS limits the size of command options + and GNU CPP is not used on VMS except with GNU C. */ +#define CPP_PREDEFINES "-Dvax -Dvms -DVMS -D__GNU__ -D__GNUC__" + +/* By default, allow $ to be part of an identifier. */ +#define DOLLARS_IN_IDENTIFIERS 1 + +#define TARGET_DEFAULT 1 +#define TARGET_VERSION fprintf (stderr, " (vax vms)"); + +#define CALL_USED_REGISTERS {1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1} + +#define __MAIN_NAME " main (" +/* + * The MAYBE_VMS_FUNCTION_PROLOGUE macro works for both gcc and g++. It + * first checks to see if the current routine is "main", which will only + * happen for GCC, and add the jsb if it is. If is not the case then try and + * see if __MAIN_NAME is part of current_function_name, which will only happen + * if we are running g++, and add the jsb if it is. In gcc there should never + * be a space in the function name, and in g++ there is always a "(" in the + * function name, thus there should never be any confusion. + */ +#define MAYBE_VMS_FUNCTION_PROLOGUE(FILE) \ +{ extern char *current_function_name; \ + if (!strcmp ("main", current_function_name)) \ + fprintf(FILE, "\tjsb _c$main_args\n"); \ + else { \ + char *p = current_function_name; \ + while (*p != '\0') \ + if (*p == *__MAIN_NAME) \ + if (strncmp(p, __MAIN_NAME, (sizeof __MAIN_NAME)-1) == 0) {\ + fprintf(FILE, "\tjsb _c$main_args\n");\ + break; \ + } else \ + p++; \ + else \ + p++; \ + }; \ +} + +#define ASM_OUTPUT_EXTERNAL(FILE,DECL,NAME) \ +{ if (DECL_INITIAL (DECL) == 0 && TREE_CODE (DECL) != FUNCTION_DECL) \ + { \ + if (TREE_READONLY (decl) && ! TREE_VOLATILE (decl)) \ + const_section (); \ + else \ + data_section (); \ + fputs (".comm ", (FILE)); \ + assemble_name ((FILE), (NAME)); \ + fprintf ((FILE), ",0\n"); \ + } \ +} + +#define NO_DOLLAR_IN_LABEL + +#define EXTRA_SECTIONS in_const + +#define EXTRA_SECTION_FUNCTIONS \ +const_section () \ +{ \ + if (in_section != in_const) { \ + fprintf(asm_out_file,".const\n"); \ + in_section = in_const; \ + } \ +} + +#define SELECT_SECTION(T) \ +{ \ + if (TREE_CODE (T) == VAR_DECL) \ + { \ + if (TREE_READONLY (T) && ! TREE_VOLATILE (T)) \ + { \ + if (TREE_PUBLIC (T)) \ + const_section (); \ + else \ + text_section (); \ + } \ + else \ + data_section (); \ + } \ + if (*tree_code_type[(int) TREE_CODE (T)] == 'c') \ + { \ + if ((TREE_CODE (T) == STRING_CST && flag_writable_strings)) \ + data_section (); \ + else \ + text_section (); \ + } \ +} + diff --git a/gcc-1.40/config/vax.md b/gcc-1.40/config/vax.md new file mode 100644 index 0000000..ae8611c --- /dev/null +++ b/gcc-1.40/config/vax.md @@ -0,0 +1,2166 @@ + +;;- Machine description for GNU compiler +;;- Vax Version +;; Copyright (C) 1987, 1988 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 1, 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. + + +;;- Instruction patterns. When multiple patterns apply, +;;- the first one in the file is chosen. +;;- +;;- See file "rtl.def" for documentation on define_insn, match_*, et. al. +;;- +;;- cpp macro #define NOTICE_UPDATE_CC in file tm.h handles condition code +;;- updates for most instructions. + +; tstsi is first test insn so that it is the one to match +; a constant argument. + +(define_insn "tstsi" + [(set (cc0) + (match_operand:SI 0 "general_operand" "g"))] + "" + "tstl %0") + +(define_insn "tsthi" + [(set (cc0) + (match_operand:HI 0 "general_operand" "g"))] + "" + "tstw %0") + +(define_insn "tstqi" + [(set (cc0) + (match_operand:QI 0 "general_operand" "g"))] + "" + "tstb %0") + +(define_insn "tstdf" + [(set (cc0) + (match_operand:DF 0 "general_operand" "gF"))] + "" + "tst%# %0") + +(define_insn "tstsf" + [(set (cc0) + (match_operand:SF 0 "general_operand" "gF"))] + "" + "tstf %0") + +;; Put cmpsi first among compare insns so it matches two CONST_INT operands. + +(define_insn "cmpsi" + [(set (cc0) + (compare (match_operand:SI 0 "general_operand" "g") + (match_operand:SI 1 "general_operand" "g")))] + "" + "cmpl %0,%1") + +(define_insn "cmphi" + [(set (cc0) + (compare (match_operand:HI 0 "general_operand" "g") + (match_operand:HI 1 "general_operand" "g")))] + "" + "cmpw %0,%1") + +(define_insn "cmpqi" + [(set (cc0) + (compare (match_operand:QI 0 "general_operand" "g") + (match_operand:QI 1 "general_operand" "g")))] + "" + "cmpb %0,%1") + +(define_insn "cmpdf" + [(set (cc0) + (compare (match_operand:DF 0 "general_operand" "gF") + (match_operand:DF 1 "general_operand" "gF")))] + "" + "cmp%# %0,%1") + +(define_insn "cmpsf" + [(set (cc0) + (compare (match_operand:SF 0 "general_operand" "gF") + (match_operand:SF 1 "general_operand" "gF")))] + "" + "cmpf %0,%1") + +(define_insn "" + [(set (cc0) + (and:SI (match_operand:SI 0 "general_operand" "g") + (match_operand:SI 1 "general_operand" "g")))] + "" + "bitl %0,%1") + +(define_insn "" + [(set (cc0) + (and:HI (match_operand:HI 0 "general_operand" "g") + (match_operand:HI 1 "general_operand" "g")))] + "" + "bitw %0,%1") + +(define_insn "" + [(set (cc0) + (and:QI (match_operand:QI 0 "general_operand" "g") + (match_operand:QI 1 "general_operand" "g")))] + "" + "bitb %0,%1") + +(define_insn "movdf" + [(set (match_operand:DF 0 "general_operand" "=g") + (match_operand:DF 1 "general_operand" "gF"))] + "" + "* +{ + if (operands[1] == dconst0_rtx) + return \"clr%# %0\"; + return \"mov%# %1,%0\"; +}") + +(define_insn "movsf" + [(set (match_operand:SF 0 "general_operand" "=g") + (match_operand:SF 1 "general_operand" "gF"))] + "" + "* +{ + if (operands[1] == fconst0_rtx) + return \"clrf %0\"; + return \"movf %1,%0\"; +}") + +;; Some vaxes don't support this instruction. +;;(define_insn "movti" +;; [(set (match_operand:TI 0 "general_operand" "=g") +;; (match_operand:TI 1 "general_operand" "g"))] +;; "" +;; "movh %1,%0") + +(define_insn "movdi" + [(set (match_operand:DI 0 "general_operand" "=g") + (match_operand:DI 1 "general_operand" "g"))] + "" + "movq %1,%0") + +;; This handles constants which are not legitimate +;; for the sake of shared libraries on VMS. +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=g") + (match_operand:SI 1 "" "i"))] + "CONSTANT_P (operands[1]) && ! LEGITIMATE_CONSTANT_P (operands[1])" + "* +{ + operands[2] = XEXP (XEXP (operands[1], 0), 0); + operands[1] = XEXP (XEXP (operands[1], 0), 1); + return \"movl %2,%0\;addl2 %1,%0\"; +}") + +(define_insn "movsi" + [(set (match_operand:SI 0 "general_operand" "=g") + (match_operand:SI 1 "supergeneral_operand" "g"))] + "" + "* +{ + rtx link; + 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. */ + && ! XEXP (link, 0)->volatil + && GET_CODE (XEXP (link, 0)) != NOTE + /* Make sure cross jumping didn't happen here. */ + && no_labels_between_p (XEXP (link, 0), insn)) + /* Fastest way to change a 0 to a 1. */ + return \"incl %0\"; + if (GET_CODE (operands[1]) == SYMBOL_REF || GET_CODE (operands[1]) == CONST) + { + if (push_operand (operands[0], SImode)) + return \"pushab %a1\"; + return \"movab %a1,%0\"; + } + /* this is slower than a movl, except when pushing an operand */ + if (operands[1] == const0_rtx) + return \"clrl %0\"; + if (GET_CODE (operands[1]) == CONST_INT + && (unsigned) INTVAL (operands[1]) >= 64) + { + int i = INTVAL (operands[1]); + if ((unsigned)(~i) < 64) + { + operands[1] = gen_rtx (CONST_INT, VOIDmode, ~i); + return \"mcoml %1,%0\"; + } + if ((unsigned)i < 127) + { + operands[1] = gen_rtx (CONST_INT, VOIDmode, 63); + operands[2] = gen_rtx (CONST_INT, VOIDmode, i-63); + return \"addl3 %2,%1,%0\"; + } + /* trading speed for space */ + if ((unsigned)i < 0x100) + return \"movzbl %1,%0\"; + if (i >= -0x80 && i < 0) + return \"cvtbl %1,%0\"; + if ((unsigned)i < 0x10000) + return \"movzwl %1,%0\"; + if (i >= -0x8000 && i < 0) + return \"cvtwl %1,%0\"; + } + if (push_operand (operands[0], SImode)) + return \"pushl %1\"; + return \"movl %1,%0\"; +}") + +(define_insn "movhi" + [(set (match_operand:HI 0 "general_operand" "=g") + (match_operand:HI 1 "general_operand" "g"))] + "" + "* +{ + rtx link; + 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. */ + && ! XEXP (link, 0)->volatil + && GET_CODE (XEXP (link, 0)) != NOTE + /* Make sure cross jumping didn't happen here. */ + && no_labels_between_p (XEXP (link, 0), insn)) + /* Fastest way to change a 0 to a 1. */ + return \"incw %0\"; + if (operands[1] == const0_rtx) + return \"clrw %0\"; + if (GET_CODE (operands[1]) == CONST_INT + && (unsigned) INTVAL (operands[1]) >= 64) + { + int i = INTVAL (operands[1]); + if ((unsigned)((~i) & 0xffff) < 64) + { + operands[1] = gen_rtx (CONST_INT, VOIDmode, (~i) & 0xffff); + return \"mcomw %1,%0\"; + } + if ((unsigned)(i & 0xffff) < 127) + { + operands[1] = gen_rtx (CONST_INT, VOIDmode, 63); + operands[2] = gen_rtx (CONST_INT, VOIDmode, (i-63) & 0xffff); + return \"addw3 %2,%1,%0\"; + } + /* this is a lot slower, and only saves 1 measly byte! */ + /* if ((unsigned)i < 0x100) + return \"movzbw %1,%0\"; */ + /* if (i >= -0x80 && i < 0) + return \"cvtbw %1,%0\"; */ + } + return \"movw %1,%0\"; +}") + +(define_insn "movqi" + [(set (match_operand:QI 0 "general_operand" "=g") + (match_operand:QI 1 "general_operand" "g"))] + "" + "* +{ + if (operands[1] == const0_rtx) + return \"clrb %0\"; + if (GET_CODE (operands[1]) == CONST_INT + && (unsigned) INTVAL (operands[1]) >= 64) + { + int i = INTVAL (operands[1]); + if ((unsigned)((~i) & 0xff) < 64) + { + operands[1] = gen_rtx (CONST_INT, VOIDmode, (~i) & 0xff); + return \"mcomb %1,%0\"; + } +#if 0 + /* ASCII alphabetics */ + if (((unsigned) INTVAL (operands[1]) &0xff) < 127) + { + operands[1] = gen_rtx (CONST_INT, VOIDmode, 63); + operands[2] = gen_rtx (CONST_INT, VOIDmode, i-63); + return \"addb3 %2,%1,%0\"; + } +#endif + } + return \"movb %1,%0\"; +}") + +;; The definition of this insn does not really explain what it does, +;; but it should suffice +;; that anything generated as this insn will be recognized as one +;; and that it won't successfully combine with anything. +(define_insn "movstrhi" + [(set (match_operand:BLK 0 "general_operand" "=g") + (match_operand:BLK 1 "general_operand" "g")) + (use (match_operand:HI 2 "general_operand" "g")) + (clobber (reg:SI 0)) + (clobber (reg:SI 1)) + (clobber (reg:SI 2)) + (clobber (reg:SI 3)) + (clobber (reg:SI 4)) + (clobber (reg:SI 5))] + "" + "movc3 %2,%1,%0") + +;; Extension and truncation insns. +;; Those for integer source operand +;; are ordered widest source type first. + +(define_insn "truncsiqi2" + [(set (match_operand:QI 0 "general_operand" "=g") + (truncate:QI (match_operand:SI 1 "general_operand" "g")))] + "" + "cvtlb %1,%0") + +(define_insn "truncsihi2" + [(set (match_operand:HI 0 "general_operand" "=g") + (truncate:HI (match_operand:SI 1 "general_operand" "g")))] + "" + "cvtlw %1,%0") + +(define_insn "trunchiqi2" + [(set (match_operand:QI 0 "general_operand" "=g") + (truncate:QI (match_operand:HI 1 "general_operand" "g")))] + "" + "cvtwb %1,%0") + +(define_insn "extendhisi2" + [(set (match_operand:SI 0 "general_operand" "=g") + (sign_extend:SI (match_operand:HI 1 "general_operand" "g")))] + "" + "cvtwl %1,%0") + +(define_insn "extendqihi2" + [(set (match_operand:HI 0 "general_operand" "=g") + (sign_extend:HI (match_operand:QI 1 "general_operand" "g")))] + "" + "cvtbw %1,%0") + +(define_insn "extendqisi2" + [(set (match_operand:SI 0 "general_operand" "=g") + (sign_extend:SI (match_operand:QI 1 "general_operand" "g")))] + "" + "cvtbl %1,%0") + +(define_insn "extendsfdf2" + [(set (match_operand:DF 0 "general_operand" "=g") + (float_extend:DF (match_operand:SF 1 "general_operand" "gF")))] + "" + "cvtf%# %1,%0") + +(define_insn "truncdfsf2" + [(set (match_operand:SF 0 "general_operand" "=g") + (float_truncate:SF (match_operand:DF 1 "general_operand" "gF")))] + "" + "cvt%#f %1,%0") + +(define_insn "zero_extendhisi2" + [(set (match_operand:SI 0 "general_operand" "=g") + (zero_extend:SI (match_operand:HI 1 "general_operand" "g")))] + "" + "movzwl %1,%0") + +(define_insn "zero_extendqihi2" + [(set (match_operand:HI 0 "general_operand" "=g") + (zero_extend:HI (match_operand:QI 1 "general_operand" "g")))] + "" + "movzbw %1,%0") + +(define_insn "zero_extendqisi2" + [(set (match_operand:SI 0 "general_operand" "=g") + (zero_extend:SI (match_operand:QI 1 "general_operand" "g")))] + "" + "movzbl %1,%0") + +;; Fix-to-float conversion insns. +;; Note that the ones that start with SImode come first. +;; That is so that an operand that is a CONST_INT +;; (and therefore lacks a specific machine mode). +;; will be recognized as SImode (which is always valid) +;; rather than as QImode or HImode. + +(define_insn "floatsisf2" + [(set (match_operand:SF 0 "general_operand" "=g") + (float:SF (match_operand:SI 1 "general_operand" "g")))] + "" + "cvtlf %1,%0") + +(define_insn "floatsidf2" + [(set (match_operand:DF 0 "general_operand" "=g") + (float:DF (match_operand:SI 1 "general_operand" "g")))] + "" + "cvtl%# %1,%0") + +(define_insn "floathisf2" + [(set (match_operand:SF 0 "general_operand" "=g") + (float:SF (match_operand:HI 1 "general_operand" "g")))] + "" + "cvtwf %1,%0") + +(define_insn "floathidf2" + [(set (match_operand:DF 0 "general_operand" "=g") + (float:DF (match_operand:HI 1 "general_operand" "g")))] + "" + "cvtw%# %1,%0") + +(define_insn "floatqisf2" + [(set (match_operand:SF 0 "general_operand" "=g") + (float:SF (match_operand:QI 1 "general_operand" "g")))] + "" + "cvtbf %1,%0") + +(define_insn "floatqidf2" + [(set (match_operand:DF 0 "general_operand" "=g") + (float:DF (match_operand:QI 1 "general_operand" "g")))] + "" + "cvtb%# %1,%0") + +;; Float-to-fix conversion insns. + +(define_insn "fix_truncsfqi2" + [(set (match_operand:QI 0 "general_operand" "=g") + (fix:QI (fix:SF (match_operand:SF 1 "general_operand" "gF"))))] + "" + "cvtfb %1,%0") + +(define_insn "fix_truncsfhi2" + [(set (match_operand:HI 0 "general_operand" "=g") + (fix:HI (fix:SF (match_operand:SF 1 "general_operand" "gF"))))] + "" + "cvtfw %1,%0") + +(define_insn "fix_truncsfsi2" + [(set (match_operand:SI 0 "general_operand" "=g") + (fix:SI (fix:SF (match_operand:SF 1 "general_operand" "gF"))))] + "" + "cvtfl %1,%0") + +(define_insn "fix_truncdfqi2" + [(set (match_operand:QI 0 "general_operand" "=g") + (fix:QI (fix:DF (match_operand:DF 1 "general_operand" "gF"))))] + "" + "cvt%#b %1,%0") + +(define_insn "fix_truncdfhi2" + [(set (match_operand:HI 0 "general_operand" "=g") + (fix:HI (fix:DF (match_operand:DF 1 "general_operand" "gF"))))] + "" + "cvt%#w %1,%0") + +(define_insn "fix_truncdfsi2" + [(set (match_operand:SI 0 "general_operand" "=g") + (fix:SI (fix:DF (match_operand:DF 1 "general_operand" "gF"))))] + "" + "cvt%#l %1,%0") + +;;- All kinds of add instructions. + +(define_insn "adddf3" + [(set (match_operand:DF 0 "general_operand" "=g") + (plus:DF (match_operand:DF 1 "general_operand" "gF") + (match_operand:DF 2 "general_operand" "gF")))] + "" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + return \"add%#2 %2,%0\"; + if (rtx_equal_p (operands[0], operands[2])) + return \"add%#2 %1,%0\"; + return \"add%#3 %1,%2,%0\"; +}") + +(define_insn "addsf3" + [(set (match_operand:SF 0 "general_operand" "=g") + (plus:SF (match_operand:SF 1 "general_operand" "gF") + (match_operand:SF 2 "general_operand" "gF")))] + "" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + return \"addf2 %2,%0\"; + if (rtx_equal_p (operands[0], operands[2])) + return \"addf2 %1,%0\"; + return \"addf3 %1,%2,%0\"; +}") + +(define_insn "addsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (plus:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")))] + "" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + { + if (operands[2] == const1_rtx) + return \"incl %0\"; + if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) == -1) + return \"decl %0\"; + if (GET_CODE (operands[2]) == CONST_INT + && (unsigned) (- INTVAL (operands[2])) < 64) + return \"subl2 $%n2,%0\"; + if (GET_CODE (operands[2]) == CONST_INT + && (unsigned) INTVAL (operands[2]) >= 64 + && GET_CODE (operands[1]) == REG) + return \"movab %c2(%1),%0\"; + return \"addl2 %2,%0\"; + } + if (rtx_equal_p (operands[0], operands[2])) + return \"addl2 %1,%0\"; + if (GET_CODE (operands[2]) == CONST_INT + && (unsigned) (- INTVAL (operands[2])) < 64) + return \"subl3 $%n2,%1,%0\"; + if (GET_CODE (operands[2]) == CONST_INT + && (unsigned) INTVAL (operands[2]) >= 64 + && GET_CODE (operands[1]) == REG) + { + if (push_operand (operands[0], SImode)) + return \"pushab %c2(%1)\"; + return \"movab %c2(%1),%0\"; + } + return \"addl3 %1,%2,%0\"; +}") + +(define_insn "addhi3" + [(set (match_operand:HI 0 "general_operand" "=g") + (plus:HI (match_operand:HI 1 "general_operand" "g") + (match_operand:HI 2 "general_operand" "g")))] + "" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + { + if (operands[2] == const1_rtx) + return \"incw %0\"; + if (GET_CODE (operands[1]) == CONST_INT + && INTVAL (operands[1]) == -1) + return \"decw %0\"; + if (GET_CODE (operands[2]) == CONST_INT + && (unsigned) (- INTVAL (operands[2])) < 64) + return \"subw2 $%n2,%0\"; + return \"addw2 %2,%0\"; + } + if (rtx_equal_p (operands[0], operands[2])) + return \"addw2 %1,%0\"; + if (GET_CODE (operands[2]) == CONST_INT + && (unsigned) (- INTVAL (operands[2])) < 64) + return \"subw3 $%n2,%1,%0\"; + return \"addw3 %1,%2,%0\"; +}") + +(define_insn "addqi3" + [(set (match_operand:QI 0 "general_operand" "=g") + (plus:QI (match_operand:QI 1 "general_operand" "g") + (match_operand:QI 2 "general_operand" "g")))] + "" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + { + if (operands[2] == const1_rtx) + return \"incb %0\"; + if (GET_CODE (operands[1]) == CONST_INT + && INTVAL (operands[1]) == -1) + return \"decb %0\"; + if (GET_CODE (operands[2]) == CONST_INT + && (unsigned) (- INTVAL (operands[2])) < 64) + return \"subb2 $%n2,%0\"; + return \"addb2 %2,%0\"; + } + if (rtx_equal_p (operands[0], operands[2])) + return \"addb2 %1,%0\"; + if (GET_CODE (operands[2]) == CONST_INT + && (unsigned) (- INTVAL (operands[2])) < 64) + return \"subb3 $%n2,%1,%0\"; + return \"addb3 %1,%2,%0\"; +}") + +;;- All kinds of subtract instructions. + +(define_insn "subdf3" + [(set (match_operand:DF 0 "general_operand" "=g") + (minus:DF (match_operand:DF 1 "general_operand" "gF") + (match_operand:DF 2 "general_operand" "gF")))] + "" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + return \"sub%#2 %2,%0\"; + return \"sub%#3 %2,%1,%0\"; +}") + +(define_insn "subsf3" + [(set (match_operand:SF 0 "general_operand" "=g") + (minus:SF (match_operand:SF 1 "general_operand" "gF") + (match_operand:SF 2 "general_operand" "gF")))] + "" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + return \"subf2 %2,%0\"; + return \"subf3 %2,%1,%0\"; +}") + +(define_insn "subsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (minus:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")))] + "" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + { + if (operands[2] == const1_rtx) + return \"decl %0\"; + return \"subl2 %2,%0\"; + } + return \"subl3 %2,%1,%0\"; +}") + +(define_insn "subhi3" + [(set (match_operand:HI 0 "general_operand" "=g") + (minus:HI (match_operand:HI 1 "general_operand" "g") + (match_operand:HI 2 "general_operand" "g")))] + "" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + { + if (operands[2] == const1_rtx) + return \"decw %0\"; + return \"subw2 %2,%0\"; + } + return \"subw3 %2,%1,%0\"; +}") + +(define_insn "subqi3" + [(set (match_operand:QI 0 "general_operand" "=g") + (minus:QI (match_operand:QI 1 "general_operand" "g") + (match_operand:QI 2 "general_operand" "g")))] + "" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + { + if (operands[2] == const1_rtx) + return \"decb %0\"; + return \"subb2 %2,%0\"; + } + return \"subb3 %2,%1,%0\"; +}") + +;;- Multiply instructions. + +(define_insn "muldf3" + [(set (match_operand:DF 0 "general_operand" "=g") + (mult:DF (match_operand:DF 1 "general_operand" "gF") + (match_operand:DF 2 "general_operand" "gF")))] + "" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + return \"mul%#2 %2,%0\"; + if (rtx_equal_p (operands[0], operands[2])) + return \"mul%#2 %1,%0\"; + return \"mul%#3 %1,%2,%0\"; +}") + +(define_insn "mulsf3" + [(set (match_operand:SF 0 "general_operand" "=g") + (mult:SF (match_operand:SF 1 "general_operand" "gF") + (match_operand:SF 2 "general_operand" "gF")))] + "" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + return \"mulf2 %2,%0\"; + if (rtx_equal_p (operands[0], operands[2])) + return \"mulf2 %1,%0\"; + return \"mulf3 %1,%2,%0\"; +}") + +(define_insn "mulsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (mult:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")))] + "" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + return \"mull2 %2,%0\"; + if (rtx_equal_p (operands[0], operands[2])) + return \"mull2 %1,%0\"; + return \"mull3 %1,%2,%0\"; +}") + +(define_insn "mulhi3" + [(set (match_operand:HI 0 "general_operand" "=g") + (mult:HI (match_operand:HI 1 "general_operand" "g") + (match_operand:HI 2 "general_operand" "g")))] + "" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + return \"mulw2 %2,%0\"; + if (rtx_equal_p (operands[0], operands[2])) + return \"mulw2 %1,%0\"; + return \"mulw3 %1,%2,%0\"; +}") + +(define_insn "mulqi3" + [(set (match_operand:QI 0 "general_operand" "=g") + (mult:QI (match_operand:QI 1 "general_operand" "g") + (match_operand:QI 2 "general_operand" "g")))] + "" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + return \"mulb2 %2,%0\"; + if (rtx_equal_p (operands[0], operands[2])) + return \"mulb2 %1,%0\"; + return \"mulb3 %1,%2,%0\"; +}") + +;;- Divide instructions. + +(define_insn "divdf3" + [(set (match_operand:DF 0 "general_operand" "=g") + (div:DF (match_operand:DF 1 "general_operand" "gF") + (match_operand:DF 2 "general_operand" "gF")))] + "" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + return \"div%#2 %2,%0\"; + return \"div%#3 %2,%1,%0\"; +}") + +(define_insn "divsf3" + [(set (match_operand:SF 0 "general_operand" "=g") + (div:SF (match_operand:SF 1 "general_operand" "gF") + (match_operand:SF 2 "general_operand" "gF")))] + "" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + return \"divf2 %2,%0\"; + return \"divf3 %2,%1,%0\"; +}") + +(define_insn "divsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (div:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")))] + "" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + return \"divl2 %2,%0\"; + return \"divl3 %2,%1,%0\"; +}") + +(define_insn "divhi3" + [(set (match_operand:HI 0 "general_operand" "=g") + (div:HI (match_operand:HI 1 "general_operand" "g") + (match_operand:HI 2 "general_operand" "g")))] + "" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + return \"divw2 %2,%0\"; + return \"divw3 %2,%1,%0\"; +}") + +(define_insn "divqi3" + [(set (match_operand:QI 0 "general_operand" "=g") + (div:QI (match_operand:QI 1 "general_operand" "g") + (match_operand:QI 2 "general_operand" "g")))] + "" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + return \"divb2 %2,%0\"; + return \"divb3 %2,%1,%0\"; +}") + +;This is left out because it is very slow; +;we are better off programming around the "lack" of this insn. +;(define_insn "divmoddisi4" +; [(set (match_operand:SI 0 "general_operand" "=g") +; (div:SI (match_operand:DI 1 "general_operand" "g") +; (match_operand:SI 2 "general_operand" "g"))) +; (set (match_operand:SI 3 "general_operand" "=g") +; (mod:SI (match_operand:DI 1 "general_operand" "g") +; (match_operand:SI 2 "general_operand" "g")))] +; "" +; "ediv %2,%1,%0,%3") + +;; Bit-and on the vax is done with a clear-bits insn. +(define_expand "andsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (and:SI (match_operand:SI 1 "general_operand" "g") + (not:SI (match_operand:SI 2 "general_operand" "g"))))] + "" + " +{ + extern rtx expand_unop (); + if (GET_CODE (operands[2]) == CONST_INT) + operands[2] = gen_rtx (CONST_INT, VOIDmode, ~INTVAL (operands[2])); + else + operands[2] = expand_unop (SImode, one_cmpl_optab, operands[2], 0, 1); +}") + +(define_expand "andhi3" + [(set (match_operand:HI 0 "general_operand" "=g") + (and:HI (match_operand:HI 1 "general_operand" "g") + (not:HI (match_operand:HI 2 "general_operand" "g"))))] + "" + " +{ + extern rtx expand_unop (); + rtx op = operands[2]; + if (GET_CODE (op) == CONST_INT) + operands[2] = gen_rtx (CONST_INT, VOIDmode, + ((1 << 16) - 1) & ~INTVAL (op)); + else + operands[2] = expand_unop (HImode, one_cmpl_optab, op, 0, 1); +}") + +(define_expand "andqi3" + [(set (match_operand:QI 0 "general_operand" "=g") + (and:QI (match_operand:QI 1 "general_operand" "g") + (not:QI (match_operand:QI 2 "general_operand" "g"))))] + "" + " +{ + extern rtx expand_unop (); + rtx op = operands[2]; + if (GET_CODE (op) == CONST_INT) + operands[2] = gen_rtx (CONST_INT, VOIDmode, + ((1 << 8) - 1) & ~INTVAL (op)); + else + operands[2] = expand_unop (QImode, one_cmpl_optab, op, 0, 1); +}") + +(define_insn "andcbsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (and:SI (match_operand:SI 1 "general_operand" "g") + (not:SI (match_operand:SI 2 "general_operand" "g"))))] + "" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + return \"bicl2 %2,%0\"; + return \"bicl3 %2,%1,%0\"; +}") + +(define_insn "andcbhi3" + [(set (match_operand:HI 0 "general_operand" "=g") + (and:HI (match_operand:HI 1 "general_operand" "g") + (not:HI (match_operand:HI 2 "general_operand" "g"))))] + "" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + return \"bicw2 %2,%0\"; + return \"bicw3 %2,%1,%0\"; +}") + +(define_insn "andcbqi3" + [(set (match_operand:QI 0 "general_operand" "=g") + (and:QI (match_operand:QI 1 "general_operand" "g") + (not:QI (match_operand:QI 2 "general_operand" "g"))))] + "" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + return \"bicb2 %2,%0\"; + return \"bicb3 %2,%1,%0\"; +}") + +;; The following are needed because constant propagation can +;; create them starting from the bic insn patterns above. + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=g") + (and:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")))] + "GET_CODE (operands[2]) == CONST_INT" + "* +{ operands[2] = gen_rtx (CONST_INT, VOIDmode, ~INTVAL (operands[2])); + if (rtx_equal_p (operands[1], operands[0])) + return \"bicl2 %2,%0\"; + return \"bicl3 %2,%1,%0\"; +}") + +(define_insn "" + [(set (match_operand:HI 0 "general_operand" "=g") + (and:HI (match_operand:HI 1 "general_operand" "g") + (match_operand:HI 2 "general_operand" "g")))] + "GET_CODE (operands[2]) == CONST_INT" + "* +{ operands[2] = gen_rtx (CONST_INT, VOIDmode, 0xffff & ~INTVAL (operands[2])); + if (rtx_equal_p (operands[1], operands[0])) + return \"bicw2 %2,%0\"; + return \"bicw3 %2,%1,%0\"; +}") + +(define_insn "" + [(set (match_operand:QI 0 "general_operand" "=g") + (and:QI (match_operand:QI 1 "general_operand" "g") + (match_operand:QI 2 "general_operand" "g")))] + "GET_CODE (operands[2]) == CONST_INT" + "* +{ operands[2] = gen_rtx (CONST_INT, VOIDmode, 0xff & ~INTVAL (operands[2])); + if (rtx_equal_p (operands[1], operands[0])) + return \"bicb2 %2,%0\"; + return \"bicb3 %2,%1,%0\"; +}") + +;;- Bit set instructions. + +(define_insn "iorsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (ior:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")))] + "" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + return \"bisl2 %2,%0\"; + if (rtx_equal_p (operands[0], operands[2])) + return \"bisl2 %1,%0\"; + return \"bisl3 %2,%1,%0\"; +}") + +(define_insn "iorhi3" + [(set (match_operand:HI 0 "general_operand" "=g") + (ior:HI (match_operand:HI 1 "general_operand" "g") + (match_operand:HI 2 "general_operand" "g")))] + "" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + return \"bisw2 %2,%0\"; + if (rtx_equal_p (operands[0], operands[2])) + return \"bisw2 %1,%0\"; + return \"bisw3 %2,%1,%0\"; +}") + +(define_insn "iorqi3" + [(set (match_operand:QI 0 "general_operand" "=g") + (ior:QI (match_operand:QI 1 "general_operand" "g") + (match_operand:QI 2 "general_operand" "g")))] + "" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + return \"bisb2 %2,%0\"; + if (rtx_equal_p (operands[0], operands[2])) + return \"bisb2 %1,%0\"; + return \"bisb3 %2,%1,%0\"; +}") + +;;- xor instructions. + +(define_insn "xorsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (xor:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")))] + "" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + return \"xorl2 %2,%0\"; + if (rtx_equal_p (operands[0], operands[2])) + return \"xorl2 %1,%0\"; + return \"xorl3 %2,%1,%0\"; +}") + +(define_insn "xorhi3" + [(set (match_operand:HI 0 "general_operand" "=g") + (xor:HI (match_operand:HI 1 "general_operand" "g") + (match_operand:HI 2 "general_operand" "g")))] + "" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + return \"xorw2 %2,%0\"; + if (rtx_equal_p (operands[0], operands[2])) + return \"xorw2 %1,%0\"; + return \"xorw3 %2,%1,%0\"; +}") + +(define_insn "xorqi3" + [(set (match_operand:QI 0 "general_operand" "=g") + (xor:QI (match_operand:QI 1 "general_operand" "g") + (match_operand:QI 2 "general_operand" "g")))] + "" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + return \"xorb2 %2,%0\"; + if (rtx_equal_p (operands[0], operands[2])) + return \"xorb2 %1,%0\"; + return \"xorb3 %2,%1,%0\"; +}") + +(define_insn "negdf2" + [(set (match_operand:DF 0 "general_operand" "=g") + (neg:DF (match_operand:DF 1 "general_operand" "gF")))] + "" + "mneg%# %1,%0") + +(define_insn "negsf2" + [(set (match_operand:SF 0 "general_operand" "=g") + (neg:SF (match_operand:SF 1 "general_operand" "gF")))] + "" + "mnegf %1,%0") + +(define_insn "negsi2" + [(set (match_operand:SI 0 "general_operand" "=g") + (neg:SI (match_operand:SI 1 "general_operand" "g")))] + "" + "mnegl %1,%0") + +(define_insn "neghi2" + [(set (match_operand:HI 0 "general_operand" "=g") + (neg:HI (match_operand:HI 1 "general_operand" "g")))] + "" + "mnegw %1,%0") + +(define_insn "negqi2" + [(set (match_operand:QI 0 "general_operand" "=g") + (neg:QI (match_operand:QI 1 "general_operand" "g")))] + "" + "mnegb %1,%0") + +(define_insn "one_cmplsi2" + [(set (match_operand:SI 0 "general_operand" "=g") + (not:SI (match_operand:SI 1 "general_operand" "g")))] + "" + "mcoml %1,%0") + +(define_insn "one_cmplhi2" + [(set (match_operand:HI 0 "general_operand" "=g") + (not:HI (match_operand:HI 1 "general_operand" "g")))] + "" + "mcomw %1,%0") + +(define_insn "one_cmplqi2" + [(set (match_operand:QI 0 "general_operand" "=g") + (not:QI (match_operand:QI 1 "general_operand" "g")))] + "" + "mcomb %1,%0") + +;; Arithmetic right shift on the vax works by negating the shift count. +(define_expand "ashrsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (ashift:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:QI 2 "general_operand" "g")))] + "" + " +{ + operands[2] = negate_rtx (QImode, operands[2]); +}") + +(define_insn "ashlsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (ashift:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:QI 2 "general_operand" "g")))] + "" + "* +{ + if (operands[2] == const1_rtx && rtx_equal_p (operands[0], operands[1])) + return \"addl2 %0,%0\"; + if (GET_CODE (operands[1]) == REG + && GET_CODE (operands[2]) == CONST_INT) + { + int i = INTVAL (operands[2]); + if (i == 1) + return \"addl3 %1,%1,%0\"; + if (i == 2) + return \"moval 0[%1],%0\"; + if (i == 3) + return \"movad 0[%1],%0\"; + } + return \"ashl %2,%1,%0\"; +}") + +;; Arithmetic right shift on the vax works by negating the shift count. +(define_expand "ashrdi3" + [(set (match_operand:DI 0 "general_operand" "=g") + (ashift:DI (match_operand:DI 1 "general_operand" "g") + (match_operand:QI 2 "general_operand" "g")))] + "" + " +{ + operands[2] = negate_rtx (QImode, operands[2]); +}") + +(define_insn "ashldi3" + [(set (match_operand:DI 0 "general_operand" "=g") + (ashift:DI (match_operand:DI 1 "general_operand" "g") + (match_operand:QI 2 "general_operand" "g")))] + "" + "ashq %2,%1,%0") + +;; Rotate right on the vax works by negating the shift count. +(define_expand "rotrsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (rotate:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:QI 2 "general_operand" "g")))] + "" + " +{ + operands[2] = negate_rtx (QImode, operands[2]); +}") + +(define_insn "rotlsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (rotate:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:QI 2 "general_operand" "g")))] + "" + "rotl %2,%1,%0") + +;This insn is probably slower than a multiply and an add. +;(define_insn "" +; [(set (match_operand:SI 0 "general_operand" "=g") +; (mult:SI (plus:SI (match_operand:SI 1 "general_operand" "g") +; (match_operand:SI 2 "general_operand" "g")) +; (match_operand:SI 3 "general_operand" "g")))] +; "" +; "index %1,$0x80000000,$0x7fffffff,%3,%2,%0") + +;; Special cases of bit-field insns which we should +;; recognize in preference to the general case. +;; These handle aligned 8-bit and 16-bit fields, +;; which can usually be done with move instructions. + +(define_insn "" + [(set (zero_extract:SI (match_operand:SI 0 "general_operand" "+ro") + (match_operand:SI 1 "immediate_operand" "i") + (match_operand:SI 2 "immediate_operand" "i")) + (match_operand:SI 3 "general_operand" "g"))] + "GET_CODE (operands[1]) == CONST_INT + && (INTVAL (operands[1]) == 8 || INTVAL (operands[1]) == 16) + && GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) % INTVAL (operands[1]) == 0 + && (GET_CODE (operands[0]) == REG + || ! mode_dependent_address_p (XEXP (operands[0], 0)))" + "* +{ + if (REG_P (operands[0])) + { + if (INTVAL (operands[2]) != 0) + return \"insv %3,%2,%1,%0\"; + } + else + operands[0] + = adj_offsettable_operand (operands[0], INTVAL (operands[2]) / 8); + + if (INTVAL (operands[1]) == 8) + return \"movb %3,%0\"; + return \"movw %3,%0\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=&g") + (zero_extract:SI (match_operand:SI 1 "general_operand" "ro") + (match_operand:SI 2 "immediate_operand" "i") + (match_operand:SI 3 "immediate_operand" "i")))] + "GET_CODE (operands[2]) == CONST_INT + && (INTVAL (operands[2]) == 8 || INTVAL (operands[2]) == 16) + && GET_CODE (operands[3]) == CONST_INT + && INTVAL (operands[3]) % INTVAL (operands[2]) == 0 + && (GET_CODE (operands[1]) == REG + || ! mode_dependent_address_p (XEXP (operands[1], 0)))" + "* +{ + if (REG_P (operands[1])) + { + if (INTVAL (operands[3]) != 0) + return \"extzv %3,%2,%1,%0\"; + } + else + operands[1] + = adj_offsettable_operand (operands[1], INTVAL (operands[3]) / 8); + + if (INTVAL (operands[2]) == 8) + return \"movzbl %1,%0\"; + return \"movzwl %1,%0\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=g") + (sign_extract:SI (match_operand:SI 1 "general_operand" "ro") + (match_operand:SI 2 "immediate_operand" "i") + (match_operand:SI 3 "immediate_operand" "i")))] + "GET_CODE (operands[2]) == CONST_INT + && (INTVAL (operands[2]) == 8 || INTVAL (operands[2]) == 16) + && GET_CODE (operands[3]) == CONST_INT + && INTVAL (operands[3]) % INTVAL (operands[2]) == 0 + && (GET_CODE (operands[1]) == REG + || ! mode_dependent_address_p (XEXP (operands[1], 0)))" + "* +{ + if (REG_P (operands[1])) + { + if (INTVAL (operands[3]) != 0) + return \"extv %3,%2,%1,%0\"; + } + else + operands[1] + = adj_offsettable_operand (operands[1], INTVAL (operands[3]) / 8); + + if (INTVAL (operands[2]) == 8) + return \"cvtbl %1,%0\"; + return \"cvtwl %1,%0\"; +}") + +;; Register-only SImode cases of bit-field insns. + +(define_insn "" + [(set (cc0) + (compare + (sign_extract:SI (match_operand:SI 0 "general_operand" "r") + (match_operand:SI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")) + (match_operand:SI 3 "general_operand" "g")))] + "" + "cmpv %2,%1,%0,%3") + +(define_insn "" + [(set (cc0) + (compare + (zero_extract:SI (match_operand:SI 0 "general_operand" "r") + (match_operand:SI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")) + (match_operand:SI 3 "general_operand" "g")))] + "" + "cmpzv %2,%1,%0,%3") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=g") + (sign_extract:SI (match_operand:SI 1 "general_operand" "r") + (match_operand:SI 2 "general_operand" "g") + (match_operand:SI 3 "general_operand" "g")))] + "" + "extv %3,%2,%1,%0") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=g") + (zero_extract:SI (match_operand:SI 1 "general_operand" "r") + (match_operand:SI 2 "general_operand" "g") + (match_operand:SI 3 "general_operand" "g")))] + "" + "extzv %3,%2,%1,%0") + +;; Non-register cases. +;; nonimmediate_operand is used to make sure that mode-ambiguous cases +;; don't match these (and therefore match the cases above instead). + +(define_insn "" + [(set (cc0) + (compare + (sign_extract:SI (match_operand:QI 0 "nonimmediate_operand" "rm") + (match_operand:SI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")) + (match_operand:SI 3 "general_operand" "g")))] + "" + "cmpv %2,%1,%0,%3") + +(define_insn "" + [(set (cc0) + (compare + (zero_extract:SI (match_operand:QI 0 "nonimmediate_operand" "rm") + (match_operand:SI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")) + (match_operand:SI 3 "general_operand" "g")))] + "" + "cmpzv %2,%1,%0,%3") + +(define_insn "extv" + [(set (match_operand:SI 0 "general_operand" "=g") + (sign_extract:SI (match_operand:QI 1 "nonimmediate_operand" "rm") + (match_operand:SI 2 "general_operand" "g") + (match_operand:SI 3 "general_operand" "g")))] + "" + "extv %3,%2,%1,%0") + +(define_insn "extzv" + [(set (match_operand:SI 0 "general_operand" "=g") + (zero_extract:SI (match_operand:QI 1 "nonimmediate_operand" "rm") + (match_operand:SI 2 "general_operand" "g") + (match_operand:SI 3 "general_operand" "g")))] + "" + "extzv %3,%2,%1,%0") + +(define_insn "insv" + [(set (zero_extract:SI (match_operand:QI 0 "general_operand" "+g") + (match_operand:SI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")) + (match_operand:SI 3 "general_operand" "g"))] + "" + "insv %3,%2,%1,%0") + +(define_insn "" + [(set (zero_extract:SI (match_operand:SI 0 "register_operand" "+r") + (match_operand:SI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")) + (match_operand:SI 3 "general_operand" "g"))] + "" + "insv %3,%2,%1,%0") + +(define_insn "jump" + [(set (pc) + (label_ref (match_operand 0 "" "")))] + "" + "jbr %l0") + +(define_insn "beq" + [(set (pc) + (if_then_else (eq (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "jeql %l0") + +(define_insn "bne" + [(set (pc) + (if_then_else (ne (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "jneq %l0") + +(define_insn "bgt" + [(set (pc) + (if_then_else (gt (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "jgtr %l0") + +(define_insn "bgtu" + [(set (pc) + (if_then_else (gtu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "jgtru %l0") + +(define_insn "blt" + [(set (pc) + (if_then_else (lt (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "jlss %l0") + +(define_insn "bltu" + [(set (pc) + (if_then_else (ltu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "jlssu %l0") + +(define_insn "bge" + [(set (pc) + (if_then_else (ge (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "jgeq %l0") + +(define_insn "bgeu" + [(set (pc) + (if_then_else (geu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "jgequ %l0") + +(define_insn "ble" + [(set (pc) + (if_then_else (le (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "jleq %l0") + +(define_insn "bleu" + [(set (pc) + (if_then_else (leu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "jlequ %l0") + +(define_insn "" + [(set (pc) + (if_then_else (eq (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "jneq %l0") + +(define_insn "" + [(set (pc) + (if_then_else (ne (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "jeql %l0") + +(define_insn "" + [(set (pc) + (if_then_else (gt (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "jleq %l0") + +(define_insn "" + [(set (pc) + (if_then_else (gtu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "jlequ %l0") + +(define_insn "" + [(set (pc) + (if_then_else (lt (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "jgeq %l0") + +(define_insn "" + [(set (pc) + (if_then_else (ltu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "jgequ %l0") + +(define_insn "" + [(set (pc) + (if_then_else (ge (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "jlss %l0") + +(define_insn "" + [(set (pc) + (if_then_else (geu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "jlssu %l0") + +(define_insn "" + [(set (pc) + (if_then_else (le (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "jgtr %l0") + +(define_insn "" + [(set (pc) + (if_then_else (leu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "jgtru %l0") + +;; Recognize jlbs and jlbc insns. +;; These come before the jbc and jbs recognizers so these will be preferred. + +(define_insn "" + [(set (pc) + (if_then_else + (ne (and:SI (match_operand:SI 0 "general_operand" "g") + (const_int 1)) + (const_int 0)) + (label_ref (match_operand 1 "" "")) + (pc)))] + "GET_CODE (operands[0]) != MEM + || ! mode_dependent_address_p (XEXP (operands[0], 0))" + "jlbs %0,%l1") + +(define_insn "" + [(set (pc) + (if_then_else + (eq (and:SI (match_operand:SI 0 "general_operand" "g") + (const_int 1)) + (const_int 0)) + (label_ref (match_operand 1 "" "")) + (pc)))] + "GET_CODE (operands[0]) != MEM + || ! mode_dependent_address_p (XEXP (operands[0], 0))" + "jlbc %0,%l1") + +(define_insn "" + [(set (pc) + (if_then_else + (ne (and:SI (match_operand:SI 0 "general_operand" "g") + (const_int 1)) + (const_int 0)) + (pc) + (label_ref (match_operand 1 "" ""))))] + "GET_CODE (operands[0]) != MEM + || ! mode_dependent_address_p (XEXP (operands[0], 0))" + "jlbc %0,%l1") + +(define_insn "" + [(set (pc) + (if_then_else + (eq (and:SI (match_operand:SI 0 "general_operand" "g") + (const_int 1)) + (const_int 0)) + (pc) + (label_ref (match_operand 1 "" ""))))] + "GET_CODE (operands[0]) != MEM + || ! mode_dependent_address_p (XEXP (operands[0], 0))" + "jlbs %0,%l1") + +;; These four entries allow a jlbc or jlbs to be made +;; by combination with a bic. +(define_insn "" + [(set (pc) + (if_then_else + (ne (and:SI (match_operand:SI 0 "general_operand" "g") + (not:SI (const_int -2))) + (const_int 0)) + (label_ref (match_operand 1 "" "")) + (pc)))] + "GET_CODE (operands[0]) != MEM + || ! mode_dependent_address_p (XEXP (operands[0], 0))" + "jlbs %0,%l1") + +(define_insn "" + [(set (pc) + (if_then_else + (eq (and:SI (match_operand:SI 0 "general_operand" "g") + (not:SI (const_int -2))) + (const_int 0)) + (label_ref (match_operand 1 "" "")) + (pc)))] + "GET_CODE (operands[0]) != MEM + || ! mode_dependent_address_p (XEXP (operands[0], 0))" + "jlbc %0,%l1") + +(define_insn "" + [(set (pc) + (if_then_else + (ne (and:SI (match_operand:SI 0 "general_operand" "g") + (not:SI (const_int -2))) + (const_int 0)) + (pc) + (label_ref (match_operand 1 "" ""))))] + "GET_CODE (operands[0]) != MEM + || ! mode_dependent_address_p (XEXP (operands[0], 0))" + "jlbc %0,%l1") + +(define_insn "" + [(set (pc) + (if_then_else + (eq (and:SI (match_operand:SI 0 "general_operand" "g") + (not:SI (const_int -2))) + (const_int 0)) + (pc) + (label_ref (match_operand 1 "" ""))))] + "GET_CODE (operands[0]) != MEM + || ! mode_dependent_address_p (XEXP (operands[0], 0))" + "jlbs %0,%l1") + +;; Recognize jbs and jbc instructions. + +(define_insn "" + [(set (pc) + (if_then_else + (ne (sign_extract:SI (match_operand:QI 0 "general_operand" "g") + (const_int 1) + (match_operand:SI 1 "general_operand" "g")) + (const_int 0)) + (label_ref (match_operand 2 "" "")) + (pc)))] + "" + "jbs %1,%0,%l2") + +(define_insn "" + [(set (pc) + (if_then_else + (eq (sign_extract:SI (match_operand:QI 0 "general_operand" "g") + (const_int 1) + (match_operand:SI 1 "general_operand" "g")) + (const_int 0)) + (label_ref (match_operand 2 "" "")) + (pc)))] + "" + "jbc %1,%0,%l2") + +(define_insn "" + [(set (pc) + (if_then_else + (ne (sign_extract:SI (match_operand:QI 0 "general_operand" "g") + (const_int 1) + (match_operand:SI 1 "general_operand" "g")) + (const_int 0)) + (pc) + (label_ref (match_operand 2 "" ""))))] + "" + "jbc %1,%0,%l2") + +(define_insn "" + [(set (pc) + (if_then_else + (eq (sign_extract:SI (match_operand:QI 0 "general_operand" "g") + (const_int 1) + (match_operand:SI 1 "general_operand" "g")) + (const_int 0)) + (pc) + (label_ref (match_operand 2 "" ""))))] + "" + "jbs %1,%0,%l2") + +(define_insn "" + [(set (pc) + (if_then_else + (ne (sign_extract:SI (match_operand:SI 0 "general_operand" "r") + (const_int 1) + (match_operand:SI 1 "general_operand" "g")) + (const_int 0)) + (label_ref (match_operand 2 "" "")) + (pc)))] + "GET_CODE (operands[0]) != MEM + || ! mode_dependent_address_p (XEXP (operands[0], 0))" + "jbs %1,%0,%l2") + +(define_insn "" + [(set (pc) + (if_then_else + (eq (sign_extract:SI (match_operand:SI 0 "general_operand" "r") + (const_int 1) + (match_operand:SI 1 "general_operand" "g")) + (const_int 0)) + (label_ref (match_operand 2 "" "")) + (pc)))] + "GET_CODE (operands[0]) != MEM + || ! mode_dependent_address_p (XEXP (operands[0], 0))" + "jbc %1,%0,%l2") + +(define_insn "" + [(set (pc) + (if_then_else + (eq (and:SI (match_operand:SI 0 "general_operand" "g") + (match_operand:SI 1 "general_operand" "g")) + (const_int 0)) + (pc) + (label_ref (match_operand 2 "" ""))))] + "GET_CODE (operands[1]) == CONST_INT + && exact_log2 (INTVAL (operands[1])) >= 0 + && (GET_CODE (operands[0]) != MEM + || ! mode_dependent_address_p (XEXP (operands[0], 0)))" + "* +{ + operands[1] + = gen_rtx (CONST_INT, VOIDmode, exact_log2 (INTVAL (operands[1]))); + return \"jbs %1,%0,%l2\"; +}") + +(define_insn "" + [(set (pc) + (if_then_else + (eq (and:SI (match_operand:SI 0 "general_operand" "g") + (match_operand:SI 1 "general_operand" "g")) + (const_int 0)) + (label_ref (match_operand 2 "" "")) + (pc)))] + "GET_CODE (operands[1]) == CONST_INT + && exact_log2 (INTVAL (operands[1])) >= 0 + && (GET_CODE (operands[0]) != MEM + || ! mode_dependent_address_p (XEXP (operands[0], 0)))" + "* +{ + operands[1] + = gen_rtx (CONST_INT, VOIDmode, exact_log2 (INTVAL (operands[1]))); + return \"jbc %1,%0,%l2\"; +}") + +(define_insn "" + [(set (pc) + (if_then_else + (ne (and:SI (match_operand:SI 0 "general_operand" "g") + (match_operand:SI 1 "general_operand" "g")) + (const_int 0)) + (pc) + (label_ref (match_operand 2 "" ""))))] + "GET_CODE (operands[1]) == CONST_INT + && exact_log2 (INTVAL (operands[1])) >= 0 + && (GET_CODE (operands[0]) != MEM + || ! mode_dependent_address_p (XEXP (operands[0], 0)))" + "* +{ + operands[1] + = gen_rtx (CONST_INT, VOIDmode, exact_log2 (INTVAL (operands[1]))); + return \"jbc %1,%0,%l2\"; +}") + +(define_insn "" + [(set (pc) + (if_then_else + (ne (and:SI (match_operand:SI 0 "general_operand" "g") + (match_operand:SI 1 "general_operand" "g")) + (const_int 0)) + (label_ref (match_operand 2 "" "")) + (pc)))] + "GET_CODE (operands[1]) == CONST_INT + && exact_log2 (INTVAL (operands[1])) >= 0 + && (GET_CODE (operands[0]) != MEM + || ! mode_dependent_address_p (XEXP (operands[0], 0)))" + "* +{ + operands[1] + = gen_rtx (CONST_INT, VOIDmode, exact_log2 (INTVAL (operands[1]))); + return \"jbs %1,%0,%l2\"; +}") + +(define_insn "" + [(set (pc) + (if_then_else + (ne (sign_extract:SI (match_operand:SI 0 "general_operand" "r") + (const_int 1) + (match_operand:SI 1 "general_operand" "g")) + (const_int 0)) + (pc) + (label_ref (match_operand 2 "" ""))))] + "GET_CODE (operands[0]) != MEM + || ! mode_dependent_address_p (XEXP (operands[0], 0))" + "jbc %1,%0,%l2") + +(define_insn "" + [(set (pc) + (if_then_else + (eq (sign_extract:SI (match_operand:SI 0 "general_operand" "r") + (const_int 1) + (match_operand:SI 1 "general_operand" "g")) + (const_int 0)) + (pc) + (label_ref (match_operand 2 "" ""))))] + "GET_CODE (operands[0]) != MEM + || ! mode_dependent_address_p (XEXP (operands[0], 0))" + "jbs %1,%0,%l2") + +;; Subtract-and-jump and Add-and-jump insns. +;; These are not used when output is for the Unix assembler +;; because it does not know how to modify them to reach far. + +;; Normal sob insns. + +(define_insn "" + [(set (pc) + (if_then_else + (gt (plus:SI (match_operand:SI 0 "general_operand" "+g") + (const_int -1)) + (const_int 0)) + (label_ref (match_operand 1 "" "")) + (pc))) + (set (match_dup 0) + (plus:SI (match_dup 0) + (const_int -1)))] + "!TARGET_UNIX_ASM" + "jsobgtr %0,%l1") + +(define_insn "" + [(set (pc) + (if_then_else + (ge (plus:SI (match_operand:SI 0 "general_operand" "+g") + (const_int -1)) + (const_int 0)) + (label_ref (match_operand 1 "" "")) + (pc))) + (set (match_dup 0) + (plus:SI (match_dup 0) + (const_int -1)))] + "!TARGET_UNIX_ASM" + "jsobgeq %0,%l1") + +;; Reversed sob insns. + +(define_insn "" + [(set (pc) + (if_then_else + (le (plus:SI (match_operand:SI 0 "general_operand" "+g") + (const_int -1)) + (const_int 0)) + (pc) + (label_ref (match_operand 1 "" "")))) + (set (match_dup 0) + (plus:SI (match_dup 0) + (const_int -1)))] + "!TARGET_UNIX_ASM" + "jsobgtr %0,%l1") + +(define_insn "" + [(set (pc) + (if_then_else + (lt (plus:SI (match_operand:SI 0 "general_operand" "+g") + (const_int -1)) + (const_int 0)) + (pc) + (label_ref (match_operand 1 "" "")))) + (set (match_dup 0) + (plus:SI (match_dup 0) + (const_int -1)))] + "!TARGET_UNIX_ASM" + "jsobgeq %0,%l1") + +;; Normal aob insns. +(define_insn "" + [(set (pc) + (if_then_else + (lt (compare (plus:SI (match_operand:SI 0 "general_operand" "+g") + (const_int 1)) + (match_operand:SI 1 "general_operand" "g")) + (const_int 0)) + (label_ref (match_operand 2 "" "")) + (pc))) + (set (match_dup 0) + (plus:SI (match_dup 0) + (const_int 1)))] + "!TARGET_UNIX_ASM" + "jaoblss %1,%0,%l2") + +(define_insn "" + [(set (pc) + (if_then_else + (le (compare (plus:SI (match_operand:SI 0 "general_operand" "+g") + (const_int 1)) + (match_operand:SI 1 "general_operand" "g")) + (const_int 0)) + (label_ref (match_operand 2 "" "")) + (pc))) + (set (match_dup 0) + (plus:SI (match_dup 0) + (const_int 1)))] + "!TARGET_UNIX_ASM" + "jaobleq %1,%0,%l2") + +;; Reverse aob insns. +(define_insn "" + [(set (pc) + (if_then_else + (ge (compare (plus:SI (match_operand:SI 0 "general_operand" "+g") + (const_int 1)) + (match_operand:SI 1 "general_operand" "g")) + (const_int 0)) + (pc) + (label_ref (match_operand 2 "" "")))) + (set (match_dup 0) + (plus:SI (match_dup 0) + (const_int 1)))] + "!TARGET_UNIX_ASM" + "jaoblss %1,%0,%l2") + +(define_insn "" + [(set (pc) + (if_then_else + (gt (compare (plus:SI (match_operand:SI 0 "general_operand" "+g") + (const_int 1)) + (match_operand:SI 1 "general_operand" "g")) + (const_int 0)) + (pc) + (label_ref (match_operand 2 "" "")))) + (set (match_dup 0) + (plus:SI (match_dup 0) + (const_int 1)))] + "!TARGET_UNIX_ASM" + "jaobleq %1,%0,%l2") + +;; Something like a sob insn, but compares against -1. +;; This finds `while (foo--)' which was changed to `while (--foo != -1)'. + +(define_insn "" + [(set (pc) + (if_then_else + (ne (compare (plus:SI (match_operand:SI 0 "general_operand" "g") + (const_int -1)) + (const_int -1)) + (const_int 0)) + (label_ref (match_operand 1 "" "")) + (pc))) + (set (match_dup 0) + (plus:SI (match_dup 0) + (const_int -1)))] + "" + "decl %0\;jgequ %l1") + +;; Note that operand 1 is total size of args, in bytes, +;; and what the call insn wants is the number of words. +(define_insn "call" + [(call (match_operand:QI 0 "general_operand" "g") + (match_operand:QI 1 "general_operand" "g"))] + "" + "* + if (INTVAL (operands[1]) > 255 * 4) + /* Vax `calls' really uses only one byte of #args, so pop explicitly. */ + return \"calls $0,%0\;addl2 %1,sp\"; + operands[1] = gen_rtx (CONST_INT, VOIDmode, (INTVAL (operands[1]) + 3)/ 4); + return \"calls %1,%0\"; +") + +(define_insn "call_value" + [(set (match_operand 0 "" "=g") + (call (match_operand:QI 1 "general_operand" "g") + (match_operand:QI 2 "general_operand" "g")))] + "" + "* + if (INTVAL (operands[2]) > 255 * 4) + /* Vax `calls' really uses only one byte of #args, so pop explicitly. */ + return \"calls $0,%1\;addl2 %2,sp\"; + operands[2] = gen_rtx (CONST_INT, VOIDmode, (INTVAL (operands[2]) + 3)/ 4); + return \"calls %2,%1\"; +") + +(define_insn "return" + [(return)] + "" + "ret") + +(define_insn "nop" + [(const_int 0)] + "" + "nop") + +(define_insn "casesi" + [(set (pc) + (if_then_else (le (minus:SI (match_operand:SI 0 "general_operand" "g") + (match_operand:SI 1 "general_operand" "g")) + (match_operand:SI 2 "general_operand" "g")) + (plus:SI (sign_extend:SI + (mem:HI (plus:SI (pc) + (minus:SI (match_dup 0) + (match_dup 1))))) + (label_ref:SI (match_operand 3 "" ""))) + (pc)))] + "" + "casel %0,%1,%2") + +;; This used to arise from the preceding by simplification +;; if operand 1 is zero. Perhaps it is no longer necessary. +(define_insn "" + [(set (pc) + (if_then_else (le (match_operand:SI 0 "general_operand" "g") + (match_operand:SI 1 "general_operand" "g")) + (plus:SI (sign_extend:SI + (mem:HI (plus:SI (pc) + (minus:SI (match_dup 0) + (const_int 0))))) + (label_ref:SI (match_operand 3 "" ""))) + (pc)))] + "" + "casel %0,$0,%1") + +;; This arises from the preceding by simplification if operand 1 is zero. +(define_insn "" + [(set (pc) + (if_then_else (le (match_operand:SI 0 "general_operand" "g") + (match_operand:SI 1 "general_operand" "g")) + (plus:SI (sign_extend:SI + (mem:HI (plus:SI (pc) + (match_dup 0)))) + (label_ref:SI (match_operand 3 "" ""))) + (pc)))] + "" + "casel %0,$0,%1") + +;; This arises from casesi if operand 0 is a constant, in range. +(define_insn "" + [(set (pc) + (plus:SI (sign_extend:SI + (mem:HI (plus:SI (pc) + (match_operand:SI 0 "general_operand" "g")))) + (label_ref:SI (match_operand 3 "" ""))))] + "" + "casel %0,$0,%0") + +;; This arises from the above if both operands are the same. +(define_insn "" + [(set (pc) + (plus:SI (sign_extend:SI (mem:HI (pc))) + (label_ref:SI (match_operand 3 "" ""))))] + "" + "casel $0,$0,$0") + +;;- load or push effective address +;; These come after the move and add/sub patterns +;; because we don't want pushl $1 turned into pushad 1. +;; or addl3 r1,r2,r3 turned into movab 0(r1)[r2],r3. + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=g") + (match_operand:QI 1 "address_operand" "p"))] + "" + "* +{ + if (push_operand (operands[0], SImode)) + return \"pushab %a1\"; + return \"movab %a1,%0\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=g") + (match_operand:HI 1 "address_operand" "p"))] + "" + "* +{ + if (push_operand (operands[0], SImode)) + return \"pushaw %a1\"; + return \"movaw %a1,%0\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=g") + (match_operand:SI 1 "address_operand" "p"))] + "" + "* +{ + if (push_operand (operands[0], SImode)) + return \"pushal %a1\"; + return \"moval %a1,%0\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=g") + (match_operand:SF 1 "address_operand" "p"))] + "" + "* +{ + if (push_operand (operands[0], SImode)) + return \"pushaf %a1\"; + return \"movaf %a1,%0\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=g") + (match_operand:DF 1 "address_operand" "p"))] + "" + "* +{ + if (push_operand (operands[0], SImode)) + return \"pushad %a1\"; + return \"movad %a1,%0\"; +}") + +;; Optimize extzv ...,z; andl2 ...,z +;; with other operands constant. +(define_peephole + [(set (match_operand:SI 0 "general_operand" "g") + (zero_extract:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g") + (match_operand:SI 3 "general_operand" "g"))) + (set (match_operand:SI 4 "general_operand" "g") + (and:SI (match_dup 0) + (match_operand:SI 5 "general_operand" "g")))] + "GET_CODE (operands[2]) == CONST_INT + && GET_CODE (operands[3]) == CONST_INT + && (INTVAL (operands[2]) + INTVAL (operands[3])) == 32 + && GET_CODE (operands[5]) == CONST_INT + && dead_or_set_p (insn, operands[0])" + "* +{ + unsigned long mask = INTVAL (operands[5]); + operands[3] = gen_rtx (CONST_INT, VOIDmode, -INTVAL (operands[3])); + + if ((floor_log2 (mask) + 1) >= INTVAL (operands[2])) + mask &= ((1 << INTVAL (operands[2])) - 1); + + operands[5] = gen_rtx (CONST_INT, VOIDmode, ~mask); + if (push_operand (operands[4], SImode)) + { + output_asm_insn (\"rotl %3,%1,%0\", operands); + return \"bicl3 %5,%0,%4\"; + } + else + { + output_asm_insn (\"rotl %3,%1,%4\", operands); + return \"bicl2 %5,%4\"; + } +}") + +;; Optimize andl3 x,y,z; extzv z,....,z + +(define_peephole + [(set (match_operand:SI 0 "general_operand" "g") + (and:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g"))) + (set (match_operand 3 "general_operand" "g") + (zero_extract:SI (match_dup 0) + (match_operand:SI 4 "general_operand" "g") + (match_operand:SI 5 "general_operand" "g")))] + "GET_CODE (operands[2]) == CONST_INT + && GET_CODE (operands[4]) == CONST_INT + && GET_CODE (operands[5]) == CONST_INT + && (INTVAL (operands[4]) + INTVAL (operands[5])) == 32 + && dead_or_set_p (insn, operands[0])" + "* +{ + unsigned long mask = INTVAL (operands[2]); + + mask &= ~((1 << INTVAL (operands[5])) - 1); + operands[2] = gen_rtx (CONST_INT, VOIDmode, ~mask); + + operands[5] = gen_rtx (CONST_INT, VOIDmode, -INTVAL (operands[5])); + + if (rtx_equal_p (operands[0], operands[1])) + output_asm_insn (\"bicl2 %2,%0\", operands); + else + output_asm_insn (\"bicl3 %2,%1,%0\", operands); + return \"rotl %5,%0,%3\"; +}") + +;;- Local variables: +;;- mode:emacs-lisp +;;- comment-start: ";;- " +;;- eval: (set-syntax-table (copy-sequence (syntax-table))) +;;- eval: (modify-syntax-entry ?[ "(]") +;;- eval: (modify-syntax-entry ?] ")[") +;;- eval: (modify-syntax-entry ?{ "(}") +;;- eval: (modify-syntax-entry ?} "){") +;;- End: diff --git a/gcc-1.40/config/xm-3b1.h b/gcc-1.40/config/xm-3b1.h new file mode 100644 index 0000000..2dc36fe --- /dev/null +++ b/gcc-1.40/config/xm-3b1.h @@ -0,0 +1,7 @@ +#define USG + +#include "xm-m68k.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/gcc-1.40/config/xm-aix386.h b/gcc-1.40/config/xm-aix386.h new file mode 100644 index 0000000..500e29f --- /dev/null +++ b/gcc-1.40/config/xm-aix386.h @@ -0,0 +1,53 @@ +/* Configuration for GNU C-compiler for IBM PS/2 running AIX/386. + Copyright (C) 1988 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 1, 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. */ + + +/* #defines that need visibility everywhere. */ +#ifdef FALSE +#undef FALSE +#endif +#ifdef TRUE +#undef TRUE +#endif +#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 + +/* Arguments to use with `exit'. */ +#define SUCCESS_EXIT_CODE 0 +#define FATAL_EXIT_CODE 33 + +#define USG + +/* target machine dependencies. + tm.h is a symbolic link to the actual target specific file. */ +#include "tm.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) + +#ifdef __GNUC__ +#define alloca(n) __builtin_alloca(n) +#endif diff --git a/gcc-1.40/config/xm-alliant.h b/gcc-1.40/config/xm-alliant.h new file mode 100644 index 0000000..2028c62 --- /dev/null +++ b/gcc-1.40/config/xm-alliant.h @@ -0,0 +1,48 @@ +/* Configuration for GNU C-compiler for Alliant FX computers. + Copyright (C) 1989 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 1, 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. */ + + +/* #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 + +/* 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 GNU C, use the built-in alloca */ +#ifdef __GNUC__ +#define alloca __builtin_alloca +#endif + +/* Make the linker remove temporary labels, since the Alliant assembler + doesn't. */ + +#define LINK_SPEC "-X" + diff --git a/gcc-1.40/config/xm-altos3068.h b/gcc-1.40/config/xm-altos3068.h new file mode 100644 index 0000000..2dc36fe --- /dev/null +++ b/gcc-1.40/config/xm-altos3068.h @@ -0,0 +1,7 @@ +#define USG + +#include "xm-m68k.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/gcc-1.40/config/xm-convex.h b/gcc-1.40/config/xm-convex.h new file mode 100644 index 0000000..bddbef2 --- /dev/null +++ b/gcc-1.40/config/xm-convex.h @@ -0,0 +1,61 @@ +/* Configuration for GNU C-compiler for Convex. + Copyright (C) 1989, 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 1, 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. */ + +/* #defines that need visibility everywhere. */ +#define FALSE 0 +#define TRUE 1 + +/* target machine dependencies. + tm.h is a symbolic link to the actual target specific file. */ +#include "tm.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 + +/* Arguments to use with `exit'. */ +#define SUCCESS_EXIT_CODE 0 +#define FATAL_EXIT_CODE 33 + +/* If compiled with GNU C, use the built-in alloca */ +#ifdef __GNUC__ +#define alloca __builtin_alloca +#endif + +#ifdef _POSIX_SOURCE + +/* Un-hide names hidden in Posix include files. */ + +#define S_IFMT _S_IFMT +#define S_IFREG _S_IFREG + +#else + +/* This definition is to prevent 8.0 include files from declaring prototypes. + Those include files ANSIfied, but the prototypes sometimes do not match. + There is no effect on pre-8.0 OS versions. */ + +#ifndef _PROTO +#define _PROTO(X) () +#endif + +#endif /* _POSIX_SOURCE */ + diff --git a/gcc-1.40/config/xm-delta68k.h b/gcc-1.40/config/xm-delta68k.h new file mode 100644 index 0000000..0decc16 --- /dev/null +++ b/gcc-1.40/config/xm-delta68k.h @@ -0,0 +1,8 @@ +#define USG +#define USE_C_ALLOCA + +#include "xm-m68k.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/gcc-1.40/config/xm-genix.h b/gcc-1.40/config/xm-genix.h new file mode 100644 index 0000000..11d31de --- /dev/null +++ b/gcc-1.40/config/xm-genix.h @@ -0,0 +1,9 @@ +/* Config file for ns32k running system V. */ + +#include "xm-ns32k.h" + +#define USG + +#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/gcc-1.40/config/xm-hp9k320.h b/gcc-1.40/config/xm-hp9k320.h new file mode 100644 index 0000000..0974ac8 --- /dev/null +++ b/gcc-1.40/config/xm-hp9k320.h @@ -0,0 +1,13 @@ +#define USG + +#include "xm-m68k.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 compiling with HPUX compiler, we are probably using alloca.c, + so help it work right. */ +#ifndef __GNUC__ +#define USE_C_ALLOCA +#endif diff --git a/gcc-1.40/config/xm-i386.h b/gcc-1.40/config/xm-i386.h new file mode 100644 index 0000000..e883f47 --- /dev/null +++ b/gcc-1.40/config/xm-i386.h @@ -0,0 +1,42 @@ +/* Configuration for GNU C-compiler for Intel 80386 running Sequent Symmetry + Copyright (C) 1988 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 1, 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. */ + + +/* #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 + +/* Arguments to use with `exit'. */ +#define SUCCESS_EXIT_CODE 0 +#define FATAL_EXIT_CODE 33 + +/* target machine dependencies. + tm.h is a symbolic link to the actual target specific file. */ + +#include "tm.h" + +#ifdef __GNUC__ +#define alloca __builtin_alloca +#endif diff --git a/gcc-1.40/config/xm-i386v.h b/gcc-1.40/config/xm-i386v.h new file mode 100644 index 0000000..60d4ce9 --- /dev/null +++ b/gcc-1.40/config/xm-i386v.h @@ -0,0 +1,47 @@ +/* Configuration for GNU C-compiler for Intel 80386 running System V. + Copyright (C) 1988 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 1, 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. */ + + +/* #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 + +/* Arguments to use with `exit'. */ +#define SUCCESS_EXIT_CODE 0 +#define FATAL_EXIT_CODE 33 + +#define USG + +/* target machine dependencies. + tm.h is a symbolic link to the actual target specific file. */ +#include "tm.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) + +#ifdef __GNUC__ +#define alloca(n) __builtin_alloca(n) +#endif diff --git a/gcc-1.40/config/xm-i860.h b/gcc-1.40/config/xm-i860.h new file mode 100644 index 0000000..61fa8be --- /dev/null +++ b/gcc-1.40/config/xm-i860.h @@ -0,0 +1,38 @@ +/* Configuration for GNU C-compiler for Intel i860. + Copyright (C) 1988 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 1, 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. */ + + +/* #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 + +/* Arguments to use with `exit'. */ +#define SUCCESS_EXIT_CODE 0 +#define FATAL_EXIT_CODE 33 + +/* target machine dependencies. + tm.h is a symbolic link to the actual target specific file. */ + +#include "tm.h" diff --git a/gcc-1.40/config/xm-iris.h b/gcc-1.40/config/xm-iris.h new file mode 100644 index 0000000..fddef9e --- /dev/null +++ b/gcc-1.40/config/xm-iris.h @@ -0,0 +1,7 @@ +#include "xm-mips.h" + +#define USG + +#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/gcc-1.40/config/xm-m68k.h b/gcc-1.40/config/xm-m68k.h new file mode 100644 index 0000000..0165b58 --- /dev/null +++ b/gcc-1.40/config/xm-m68k.h @@ -0,0 +1,43 @@ +/* Configuration for GNU C-compiler for Motorola 68000 family. + Copyright (C) 1987 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 1, 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. */ + + +/* #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_WORDS_BIG_ENDIAN + +/* 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 GNU C, use the built-in alloca */ +#ifdef __GNUC__ +#define alloca __builtin_alloca +#endif diff --git a/gcc-1.40/config/xm-m88k.h b/gcc-1.40/config/xm-m88k.h new file mode 100644 index 0000000..ea98030 --- /dev/null +++ b/gcc-1.40/config/xm-m88k.h @@ -0,0 +1,37 @@ +/* Configuration for GNU C-compiler for Motorola 88000 family. + Copyright (C) 1987 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 1, 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. */ + + +/* #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 + +/* 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 diff --git a/gcc-1.40/config/xm-mips.h b/gcc-1.40/config/xm-mips.h new file mode 100644 index 0000000..e73e992 --- /dev/null +++ b/gcc-1.40/config/xm-mips.h @@ -0,0 +1,44 @@ +/* Configuration for GNU C-compiler for MIPS Rx000 family + Copyright (C) 1987 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 1, 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. */ + + +/* #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 + +/* 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 GNU C, use the built-in alloca */ +#ifdef __GNUC__ +#define alloca __builtin_alloca +#else +#define USE_C_ALLOCA +#endif diff --git a/gcc-1.40/config/xm-ns32k.h b/gcc-1.40/config/xm-ns32k.h new file mode 100644 index 0000000..a19dcb6 --- /dev/null +++ b/gcc-1.40/config/xm-ns32k.h @@ -0,0 +1,41 @@ +/* Configuration for GNU C-compiler for Vax. + Copyright (C) 1987 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 1, 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. */ + +/* #defines that need visibility everywhere. */ +#define FALSE 0 +#define TRUE 1 + +/* target machine dependencies. + tm.h is a symbolic link to the actual target specific file. */ +#include "tm.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 + +/* Arguments to use with `exit'. */ +#define SUCCESS_EXIT_CODE 0 +#define FATAL_EXIT_CODE 33 + +/* If compiled with GNU C, use the built-in alloca */ +#ifdef __GNUC__ +#define alloca __builtin_alloca +#endif diff --git a/gcc-1.40/config/xm-pyr.h b/gcc-1.40/config/xm-pyr.h new file mode 100644 index 0000000..063829a --- /dev/null +++ b/gcc-1.40/config/xm-pyr.h @@ -0,0 +1,43 @@ +/* Configuration for GNU compiler for Pyramid 90 Series. + Copyright (C) 1989 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 1, 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. */ + +/* xm-pyr.h -- based on xm-vax.h */ + +/* #defines that need visibility everywhere. */ +#define FALSE 0 +#define TRUE 1 + +/* target machine dependencies. + tm.h is a symbolic link to the actual target specific file. */ +#include "tm.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 + +/* Arguments to use with `exit'. */ +#define SUCCESS_EXIT_CODE 0 +#define FATAL_EXIT_CODE 33 + +/* If compiled with GNU C, use the built-in alloca */ +#ifdef __GNUC__ +#define alloca __builtin_alloca +#endif diff --git a/gcc-1.40/config/xm-sparc.h b/gcc-1.40/config/xm-sparc.h new file mode 100644 index 0000000..84a5984 --- /dev/null +++ b/gcc-1.40/config/xm-sparc.h @@ -0,0 +1,44 @@ +/* Configuration for GNU C-compiler for Sun Sparc. + Copyright (C) 1988 Free Software Foundation, Inc. + Contributed by Michael Tiemann (tiemann@mcc.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 1, 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. */ + + +/* #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 + +/* Place any machine-dependent include files here, in case we + are bootstrapping. */ +#ifndef alloca +#include "alloca.h" +#endif + +/* 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 diff --git a/gcc-1.40/config/xm-spur.h b/gcc-1.40/config/xm-spur.h new file mode 100644 index 0000000..a9db436 --- /dev/null +++ b/gcc-1.40/config/xm-spur.h @@ -0,0 +1,37 @@ +/* Configuration for GNU C-compiler for Berkeley SPUR processor. + Copyright (C) 1988 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 1, 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. */ + + +/* #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 + +/* 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 diff --git a/gcc-1.40/config/xm-sun386i.h b/gcc-1.40/config/xm-sun386i.h new file mode 100644 index 0000000..48ca9a0 --- /dev/null +++ b/gcc-1.40/config/xm-sun386i.h @@ -0,0 +1,48 @@ +/* Configuration for GNU C-compiler for Intel 80386 running SunOS 4.0. + Copyright (C) 1988 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 1, 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. */ + + +/* #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 + +/* Arguments to use with `exit'. */ +#define SUCCESS_EXIT_CODE 0 +#define FATAL_EXIT_CODE 33 + +#define USG + +/* target machine dependencies. + tm.h is a symbolic link to the actual target specific file. */ +#include "tm.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) + +#ifdef __GNUC__ +#define alloca(n) __builtin_alloca(n) +#endif + diff --git a/gcc-1.40/config/xm-tahoe.h b/gcc-1.40/config/xm-tahoe.h new file mode 100644 index 0000000..e52ebe3 --- /dev/null +++ b/gcc-1.40/config/xm-tahoe.h @@ -0,0 +1,57 @@ +/* Configuration for GNU C-compiler for Tahoe. + Copyright (C) 1987 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 1, 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. */ + +/* + * File: xm-tahoe.h + * + * This port made at the University of Buffalo by Devon Bowen, + * Dale Wiles and Kevin Zachmann. + * + * Mail bugs reports or fixes to: gcc@cs.buffalo.edu + */ + + +/* This file has the same stuff the vax version does */ + +/* defines that need visibility everywhere */ + +#define FALSE 0 +#define TRUE 1 + +/* target machine dependencies */ + +#include "tm.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 + +/* Arguments to use with `exit'. */ + +#define SUCCESS_EXIT_CODE 0 +#define FATAL_EXIT_CODE 33 + +/* use built in alloca if gcc compiled */ + +#ifdef __GNUC__ +#define alloca __builtin_alloca +#endif diff --git a/gcc-1.40/config/xm-tower.h b/gcc-1.40/config/xm-tower.h new file mode 100644 index 0000000..1dc01ef --- /dev/null +++ b/gcc-1.40/config/xm-tower.h @@ -0,0 +1,8 @@ +#include "xm-m68k.h" + +#define USG +#define HAVE_VPRINTF + +#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/gcc-1.40/config/xm-umips.h b/gcc-1.40/config/xm-umips.h new file mode 100644 index 0000000..bed8022 --- /dev/null +++ b/gcc-1.40/config/xm-umips.h @@ -0,0 +1,44 @@ +/* Configuration for GNU C-compiler for UMIPS operating system + Copyright (C) 1989 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 1, 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. */ + +/* + * Notes for compiling gcc on umips (v3.0) + * - change the -g in the CFLAGS to a -g3 or take it out all together. + * - do not define DBX_DEBUGGING_INFO in tm.h, it doesn't exist (unless + * you get one from a bsd system) + */ +#include "xm-mips.h" + +/* Arguments to use with `exit'. */ +#define SUCCESS_EXIT_CODE 0 +#define FATAL_EXIT_CODE 33 + +/* If compiled with GNU C, use the built-in alloca */ +#ifdef __GNUC__ +#define alloca __builtin_alloca +#endif + +#define USG + +/* for the emacs version of alloca */ +#define STACK_DIRECTION -1 + +#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/gcc-1.40/config/xm-vax.h b/gcc-1.40/config/xm-vax.h new file mode 100644 index 0000000..0057ae6 --- /dev/null +++ b/gcc-1.40/config/xm-vax.h @@ -0,0 +1,42 @@ +/* Configuration for GNU C-compiler for Vax. + Copyright (C) 1987 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 1, 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. */ + +/* #defines that need visibility everywhere. */ +#define FALSE 0 +#define TRUE 1 + +/* target machine dependencies. + tm.h is a symbolic link to the actual target specific file. */ +#include "tm.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 + +/* Arguments to use with `exit'. */ +#define SUCCESS_EXIT_CODE 0 +#define FATAL_EXIT_CODE 33 + +/* If compiled with GNU C, use the built-in alloca */ +#ifdef __GNUC__ +#define alloca __builtin_alloca +#endif + diff --git a/gcc-1.40/config/xm-vaxv.h b/gcc-1.40/config/xm-vaxv.h new file mode 100644 index 0000000..d347694 --- /dev/null +++ b/gcc-1.40/config/xm-vaxv.h @@ -0,0 +1,9 @@ +/* Config file for Vax running system V. */ + +#include "xm-vax.h" + +#define USG + +#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/gcc-1.40/config/xm-vms.h b/gcc-1.40/config/xm-vms.h new file mode 100644 index 0000000..368c167 --- /dev/null +++ b/gcc-1.40/config/xm-vms.h @@ -0,0 +1,61 @@ +/* Configuration for GNU C-compiler for Vax. + Copyright (C) 1987 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 1, 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. */ + +/* #defines that need visibility everywhere. */ +#define FALSE 0 +#define TRUE 1 + +/* target machine dependencies. + tm.h is a symbolic link to the actual target specific file. */ +#include "tm.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 SUCCESS_EXIT_CODE 1 +#define FATAL_EXIT_CODE (44 | 0x10000000) /* Failure, and no DCL message. */ + + +/* A couple of conditionals for execution machine are controlled here. */ +#ifndef VMS +#define VMS +#endif + +#ifndef __GNUC__ +/* not present, at least in VAX-11 C (VMS) v2.2 */ +#define R_OK 4 +#define W_OK 2 +#define X_OK 1 +#define F_OK 0 + +#define unlink delete +#endif + +/* global const variables don't work, + so turn off const-ness to prevent trouble with insn-output.c. */ +#define const + +/* If compiled with GNU C, use the built-in alloca */ +#ifdef __GNUC__ +#define alloca __builtin_alloca +#endif + diff --git a/gcc-1.40/cpp.aux b/gcc-1.40/cpp.aux new file mode 100644 index 0000000..f7e90c7 --- /dev/null +++ b/gcc-1.40/cpp.aux @@ -0,0 +1,82 @@ +'xrdef {Top-pg}{1} +'xrdef {Top-snt}{chapter'tie1} +'xrdef {Global Actions-pg}{1} +'xrdef {Global Actions-snt}{section'tie1.1} +'xrdef {Commands-pg}{3} +'xrdef {Commands-snt}{section'tie1.2} +'xrdef {Header Files-pg}{3} +'xrdef {Header Files-snt}{section'tie1.3} +'xrdef {Header Uses-pg}{3} +'xrdef {Header Uses-snt}{section'tie1.3.1} +'xrdef {Include Syntax-pg}{4} +'xrdef {Include Syntax-snt}{section'tie1.3.2} +'xrdef {Include Operation-pg}{5} +'xrdef {Include Operation-snt}{section'tie1.3.3} +'xrdef {Once-Only-pg}{6} +'xrdef {Once-Only-snt}{section'tie1.3.4} +'xrdef {Macros-pg}{7} +'xrdef {Macros-snt}{section'tie1.4} +'xrdef {Simple Macros-pg}{7} +'xrdef {Simple Macros-snt}{section'tie1.4.1} +'xrdef {Argument Macros-pg}{9} +'xrdef {Argument Macros-snt}{section'tie1.4.2} +'xrdef {Predefined-pg}{11} +'xrdef {Predefined-snt}{section'tie1.4.3} +'xrdef {Standard Predefined-pg}{11} +'xrdef {Standard Predefined-snt}{section'tie1.4.3.1} +'xrdef {Nonstandard Predefined-pg}{13} +'xrdef {Nonstandard Predefined-snt}{section'tie1.4.3.2} +'xrdef {Stringification-pg}{15} +'xrdef {Stringification-snt}{section'tie1.4.4} +'xrdef {Concatenation-pg}{16} +'xrdef {Concatenation-snt}{section'tie1.4.5} +'xrdef {Undefining-pg}{17} +'xrdef {Undefining-snt}{section'tie1.4.6} +'xrdef {Redefining-pg}{18} +'xrdef {Redefining-snt}{section'tie1.4.7} +'xrdef {Macro Pitfalls-pg}{19} +'xrdef {Macro Pitfalls-snt}{section'tie1.4.8} +'xrdef {Misnesting-pg}{19} +'xrdef {Misnesting-snt}{section'tie1.4.8.1} +'xrdef {Macro Parentheses-pg}{19} +'xrdef {Macro Parentheses-snt}{section'tie1.4.8.2} +'xrdef {Swallow Semicolon-pg}{21} +'xrdef {Swallow Semicolon-snt}{section'tie1.4.8.3} +'xrdef {Side Effects-pg}{22} +'xrdef {Side Effects-snt}{section'tie1.4.8.4} +'xrdef {Self-Reference-pg}{23} +'xrdef {Self-Reference-snt}{section'tie1.4.8.5} +'xrdef {Argument Prescan-pg}{24} +'xrdef {Argument Prescan-snt}{section'tie1.4.8.6} +'xrdef {Cascaded Macros-pg}{27} +'xrdef {Cascaded Macros-snt}{section'tie1.4.8.7} +'xrdef {Conditionals-pg}{27} +'xrdef {Conditionals-snt}{section'tie1.5} +'xrdef {Conditional Uses-pg}{28} +'xrdef {Conditional Uses-snt}{section'tie1.5.1} +'xrdef {Conditional Syntax-pg}{28} +'xrdef {Conditional Syntax-snt}{section'tie1.5.2} +'xrdef {#if Command-pg}{28} +'xrdef {#if Command-snt}{section'tie1.5.2.1} +'xrdef {#else Command-pg}{29} +'xrdef {#else Command-snt}{section'tie1.5.2.2} +'xrdef {#elif Command-pg}{30} +'xrdef {#elif Command-snt}{section'tie1.5.2.3} +'xrdef {Deleted Code-pg}{31} +'xrdef {Deleted Code-snt}{section'tie1.5.3} +'xrdef {Conditionals-Macros-pg}{31} +'xrdef {Conditionals-Macros-snt}{section'tie1.5.4} +'xrdef {#error Command-pg}{32} +'xrdef {#error Command-snt}{section'tie1.5.5} +'xrdef {Combining Sources-pg}{33} +'xrdef {Combining Sources-snt}{section'tie1.6} +'xrdef {Other Commands-pg}{34} +'xrdef {Other Commands-snt}{section'tie1.7} +'xrdef {Output-pg}{35} +'xrdef {Output-snt}{section'tie1.8} +'xrdef {Invocation-pg}{35} +'xrdef {Invocation-snt}{section'tie1.9} +'xrdef {Concept Index-pg}{39} +'xrdef {Concept Index-snt}{} +'xrdef {Index-pg}{41} +'xrdef {Index-snt}{} diff --git a/gcc-1.40/cpp.cps b/gcc-1.40/cpp.cps new file mode 100644 index 0000000..3a32bf5 --- /dev/null +++ b/gcc-1.40/cpp.cps @@ -0,0 +1,30 @@ +\initial {C} +\entry {cascaded macros}{27} +\entry {commands}{3} +\entry {concatenation}{16} +\entry {conditionals}{27} +\initial {H} +\entry {header file}{3} +\initial {L} +\entry {line control}{33} +\initial {M} +\entry {macro body uses macro}{27} +\initial {N} +\entry {null command}{34} +\initial {O} +\entry {options}{35} +\entry {output format}{35} +\initial {P} +\entry {predefined macros}{11} +\entry {preprocessor commands}{3} +\initial {R} +\entry {redefining macros}{18} +\entry {repeated inclusion}{6} +\initial {S} +\entry {self-reference}{23} +\entry {semicolons (after macro calls)}{21} +\entry {side effects (in macro arguments)}{22} +\entry {stringification}{15} +\initial {U} +\entry {undefining macros}{17} +\entry {unsafe macros}{22} diff --git a/gcc-1.40/cpp.dvi b/gcc-1.40/cpp.dvi new file mode 100644 index 0000000..486a97a Binary files /dev/null and b/gcc-1.40/cpp.dvi differ diff --git a/gcc-1.40/cpp.fns b/gcc-1.40/cpp.fns new file mode 100644 index 0000000..8d5df42 --- /dev/null +++ b/gcc-1.40/cpp.fns @@ -0,0 +1,51 @@ +\initial {#} +\entry {\code {#elif}}{30} +\entry {\code {#else}}{29} +\entry {\code {#error}}{32} +\entry {\code {#ident}}{34} +\entry {\code {#if}}{28} +\entry {\code {#ifdef}}{32} +\entry {\code {#ifndef}}{32} +\entry {\code {#include}}{4} +\entry {\code {#line}}{33} +\entry {\code {#pragma}}{34} +\initial {-} +\entry {\code {-C}}{36} +\entry {\code {-d}}{37} +\entry {\code {-D}}{36} +\entry {\code {-i}}{37} +\entry {\code {-I}}{36} +\entry {\code {-M}}{37} +\entry {\code {-MM}}{37} +\entry {\code {-P}}{35} +\entry {\code {-pedantic}}{36} +\entry {\code {-trigraphs}}{36} +\entry {\code {-U}}{37} +\entry {\code {-undef}}{37} +\initial {{@fam @ttfam @tentt @char '137}} +\entry {\code {{@fam @ttfam @tentt @char '137}{@fam @ttfam @tentt @char '137}BASE{@fam @ttfam @tentt @char '137}FILE{@fam @ttfam @tentt @char '137}{@fam @ttfam @tentt @char '137}}}{12} +\entry {\code {{@fam @ttfam @tentt @char '137}{@fam @ttfam @tentt @char '137}DATE{@fam @ttfam @tentt @char '137}{@fam @ttfam @tentt @char '137}}}{12} +\entry {\code {{@fam @ttfam @tentt @char '137}{@fam @ttfam @tentt @char '137}FILE{@fam @ttfam @tentt @char '137}{@fam @ttfam @tentt @char '137}}}{12} +\entry {\code {{@fam @ttfam @tentt @char '137}{@fam @ttfam @tentt @char '137}LINE{@fam @ttfam @tentt @char '137}{@fam @ttfam @tentt @char '137}}}{12} +\entry {\code {{@fam @ttfam @tentt @char '137}{@fam @ttfam @tentt @char '137}STDC{@fam @ttfam @tentt @char '137}{@fam @ttfam @tentt @char '137}}}{12} +\entry {\code {{@fam @ttfam @tentt @char '137}{@fam @ttfam @tentt @char '137}TIME{@fam @ttfam @tentt @char '137}{@fam @ttfam @tentt @char '137}}}{12} +\initial {B} +\entry {\code {BSD}}{13} +\initial {D} +\entry {\code {defined}}{31} +\initial {M} +\entry {\code {M68020}}{14} +\entry {\code {m68k}}{13} +\entry {\code {mc68000}}{13} +\initial {N} +\entry {\code {ns32000}}{14} +\initial {P} +\entry {\code {pyr}}{14} +\initial {S} +\entry {\code {sequent}}{14} +\entry {\code {sun}}{14} +\entry {\code {system header files}}{4} +\initial {U} +\entry {\code {unix}}{13} +\initial {V} +\entry {\code {vax}}{13} diff --git a/gcc-1.40/cpp.info b/gcc-1.40/cpp.info new file mode 100644 index 0000000..ec8b4e4 --- /dev/null +++ b/gcc-1.40/cpp.info @@ -0,0 +1,69 @@ +Info file cpp.info, produced by Makeinfo, -*- Text -*- from input +file cpp.texinfo. + +This file documents the GNU C Preprocessor. + +Copyright (C) 1987, 1989 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. + +Permission is granted to copy and distribute modified versions of +this manual under the conditions for verbatim copying, provided also +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. + +Indirect: +cpp.info-1: 748 +cpp.info-2: 48706 + +Tag Table: +(Indirect) +Node: Top750 +Node: Global Actions3306 +Node: Commands5809 +Node: Header Files7414 +Node: Header Uses7990 +Node: Include Syntax9377 +Node: Include Operation12390 +Node: Once-Only14056 +Node: Macros15867 +Node: Simple Macros16779 +Node: Argument Macros19826 +Node: Predefined24914 +Node: Standard Predefined25342 +Node: Nonstandard Predefined29545 +Node: Stringification32827 +Node: Concatenation35666 +Node: Undefining38922 +Node: Redefining39944 +Node: Macro Pitfalls41230 +Node: Misnesting42273 +Node: Macro Parentheses43281 +Node: Swallow Semicolon45136 +Node: Side Effects47024 +Node: Self-Reference48708 +Node: Argument Prescan50953 +Node: Cascaded Macros55914 +Node: Conditionals56935 +Node: Conditional Uses58223 +Node: Conditional Syntax59610 +Node: #if Command60179 +Node: #else Command62430 +Node: #elif Command63077 +Node: Deleted Code64418 +Node: Conditionals-Macros64949 +Node: #error Command68171 +Node: Combining Sources69215 +Node: Other Commands71829 +Node: Output73062 +Node: Invocation73993 +Node: Concept Index79417 +Node: Index80219 + +End Tag Table diff --git a/gcc-1.40/cpp.info-1 b/gcc-1.40/cpp.info-1 new file mode 100644 index 0000000..7b07416 --- /dev/null +++ b/gcc-1.40/cpp.info-1 @@ -0,0 +1,1254 @@ +Info file cpp.info, produced by Makeinfo, -*- Text -*- from input +file cpp.texinfo. + +This file documents the GNU C Preprocessor. + +Copyright (C) 1987, 1989 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. + +Permission is granted to copy and distribute modified versions of +this manual under the conditions for verbatim copying, provided also +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. + + + +File: cpp.info, Node: Top, Next: Global Actions, Up: (DIR) + +The C Preprocessor +****************** + +The C preprocessor is a "macro processor" that is used automatically +by the C compiler to transform your program before actual +compilation. It is called a macro processor because it allows you to +define "macros", which are brief abbreviations for longer constructs. + +The C preprocessor provides four separate facilities that you can use +as you see fit: + + * Inclusion of header files. These are files of declarations that + can be substituted into your program. + + * Macro expansion. You can define "macros", which are + abbreviations for arbitrary fragments of C code, and then the C + preprocessor will replace the macros with their definitions + throughout the program. + + * Conditional compilation. Using special preprocessor commands, + you can include or exclude parts of the program according to + various conditions. + + * Line control. If you use a program to combine or rearrange + source files into an intermediate file which is then compiled, + you can use line control 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. + +ANSI Standard C requires the rejection of many harmless constructs +commonly used by today's C programs. Such incompatibility would be +inconvenient for users, so the GNU C preprocessor is configured to +accept these constructs by default. Strictly speaking, to get ANSI +Standard C, you must use the options `-trigraphs', `-undef' and +`-pedantic', but in practice the consequences of having strict ANSI +Standard C make it undesirable to do this. *Note Invocation::. + +* Menu: + +* Global Actions:: Actions made uniformly on all input files. +* Commands:: General syntax of preprocessor commands. +* Header Files:: How and why to use header files. +* Macros:: How and why to use macros. +* Conditionals:: How and why to use conditionals. +* Combining Sources:: Use of line control when you combine source files. +* Other Commands:: Miscellaneous preprocessor commands. +* Output:: Format of output from the C preprocessor. +* Invocation:: How to invoke the preprocessor; command options. +* Concept Index:: Index of concepts and terms. +* Index:: Index of commands, predefined macros and options. + + + +File: cpp.info, Node: Global Actions, Next: Commands, Prev: Top, Up: Top + +Transformations Made Globally +============================= + +Most C preprocessor features are inactive unless you give specific +commands to request their use. (Preprocessor commands are lines +starting with `#'; *note Commands::.). But there are three +transformations that the preprocessor always makes on all the input +it receives, even in the absence of commands. + + * All C comments are replaced with single spaces. + + * Backslash-Newline sequences are deleted, no matter where. This + feature allows you to break long lines for cosmetic purposes + without changing their meaning. + + * Predefined macro names are replaced with their expansions (*note + Predefined::.). + +The first two transformations are done *before* nearly all other +parsing and before preprocessor commands are recognized. Thus, for +example, you can split a line cosmetically with Backslash-Newline +anywhere (except when trigraphs are in use; see below). + + /* + */ # /* + */ defi\ + ne FO\ + O 10\ + 20 + +is equivalent into `#define FOO 1020'. You can split even an escape +sequence with Backslash-Newline. For example, you can split +`"foo\bar"' between the `\' and the `b' to get + + "foo\\ + bar" + +This behavior is unclean: in all other contexts, a Backslash can be +inserted in a string constant as an ordinary character by writing a +double Backslash, and this creates an exception. But the ANSI C +standard requires it. (Strict ANSI C does not allow Newlines in +string constants, so they do not consider this a problem.) + +But there are a few exceptions to all three transformations. + + * C comments and predefined macro names are not recognized inside + a `#include' command in which the file name is delimited with + `<' and `>'. + + * C comments and predefined macro names are never recognized + within a character or string constant. (Strictly speaking, this + is the rule, not an exception, but it is worth noting here + anyway.) + + * Backslash-Newline may not safely be used within an ANSI + "trigraph". Trigraphs are converted before Backslash-Newline is + deleted. If you write what looks like a trigraph with a + Backslash-Newline inside, the Backslash-Newline is deleted as + usual, but it is then too late to recognize the trigraph. + + This exception is relevant only if you use the `-trigraphs' + option to enable trigraph processing. *Note Invocation::. + + + +File: cpp.info, Node: Commands, Next: Header Files, Prev: Global Actions, Up: Top + +Preprocessor Commands +===================== + +Most preprocessor features are active only if you use preprocessor +commands to request their use. + +Preprocessor commands are lines in your program that start with `#'. +The `#' is followed by an identifier that is the "command name". For +example, `#define' is the command that defines a macro. Whitespace +is also allowed before and after the `#'. + +The set of valid command names is fixed. Programs cannot define new +preprocessor commands. + +Some command names require arguments; these make up the rest of the +command line and must be separated from the command name by +whitespace. For example, `#define' must be followed by a macro name +and the intended expansion of the macro. + +A preprocessor command cannot be more than one line in normal +circumstances. It may be split cosmetically with Backslash-Newline, +but that has no effect on its meaning. Comments containing Newlines +can also divide the command into multiple lines, but the comments are +changed to Spaces before the command is interpreted. The only way a +significant Newline can occur in a preprocessor command is within a +string constant or character constant. Note that most C compilers +that might be applied to the output from the preprocessor do not +accept string or character constants containing Newlines. + +The `#' and the command name cannot come from a macro expansion. For +example, if `foo' is defined as a macro expanding to `define', that +does not make `#foo' a valid preprocessor command. + + + +File: cpp.info, Node: Header Files, Next: Macros, Prev: Commands, Up: Top + +Header Files +============ + +A header file is a file containing C declarations and macro +definitions (*note Macros::.) to be shared between several source +files. You request the use of a header file in your program with the +C preprocessor command `#include'. + +* Menu: + +* Header Uses:: What header files are used for. +* Include Syntax:: How to write `#include' commands. +* Include Operation:: What `#include' does. +* Once-Only:: Preventing multiple inclusion of one header file. + + + +File: cpp.info, Node: Header Uses, Next: Include Syntax, Prev: Header Files, Up: Header Files + +Uses of Header Files +-------------------- + +Header files serve two kinds of purposes. + + * System header files declare the interfaces to parts of the + operating system. You include them in your program to supply + the definitions you need to invoke system calls and libraries. + + * Your own header files contain declarations for interfaces + between the source files of your program. Each time you have a + group of related declarations and macro definitions all or most + of which are needed in several different source files, it is a + good idea to create a header file for them. + +Including a header file produces the same results in C compilation as +copying the header file into each source file that needs it. But +such copying would be time-consuming and error-prone. With a header +file, the related declarations appear in only one place. If they +need to be changed, they can be changed in one place, and programs +that include the header file will automatically use the new version +when next recompiled. The header file eliminates the labor of +finding and changing all the copies as well as the risk that a +failure to find one copy will result in inconsistencies within a +program. + +The usual convention is to give header files names that end with `.h'. + + + +File: cpp.info, Node: Include Syntax, Next: Include Operation, Prev: Header Uses, Up: Header Files + +The `#include' Command +---------------------- + +Both user and system header files are included using the preprocessor +command `#include'. It has three variants: + +`#include ' + This variant is used for system header files. It searches for a + file named FILE in a list of directories specified by you, then + in a standard list of system directories. You specify + directories to search for header files with the command option + `-I' (*note Invocation::.). The option `-nostdinc' inhibits + searching the standard system directories; in this case only the + directories you specify are searched. + + The parsing of this form of `#include' is slightly special + because comments are not recognized within the `<...>'. Thus, + in `#include ' the `/*' does not start a comment and the + command specifies inclusion of a system header file named + `x/*y'. Of course, a header file with such a name is unlikely + to exist on Unix, where shell wildcard features would make it + hard to manipulate. + + The argument FILE may not contain a `>' character. It may, + however, contain a `<' character. + +`#include "FILE"' + This variant is used for header files of your own program. It + searches for a file named FILE first in the current directory, + then in the same directories used for system header files. The + current directory is the directory of the current input file. + It is tried first because it is presumed to be the location of + the files that the current input file refers to. (If the `-I-' + option is used, the special treatment of the current directory + is inhibited.) + + The argument FILE may not contain `"' characters. If + backslashes occur within FILE, they are considered ordinary text + characters, not escape characters. None of the character escape + sequences appropriate to string constants in C are processed. + Thus, `#include "x\n\\y"' specifies a filename containing three + backslashes. It is not clear why this behavior is ever useful, + but the ANSI standard specifies it. + +`#include ANYTHING ELSE' + This variant is called a "computed #include". Any `#include' + command whose argument does not fit the above two forms is a + computed include. The text ANYTHING ELSE is checked for macro + calls, which are expanded (*note Macros::.). When this is done, + the result must fit one of the above two variants. + + This feature allows you to define a macro which controls the + file name to be used at a later point in the program. One + application of this is to allow a site-configuration file for + your program to specify the names of the system include files to + be used. This can help in porting the program to various + operating systems in which the necessary system header files are + found in different places. + + + +File: cpp.info, Node: Include Operation, Next: Once-Only, Prev: Include Syntax, Up: Header Files + +How `#include' Works +-------------------- + +The `#include' command works by directing the C preprocessor to scan +the specified file as input before continuing with the rest of the +current file. The output from the preprocessor contains the output +already generated, followed by the output resulting from the included +file, followed by the output that comes from the text after the +`#include' command. For example, given two files as follows: + + /* File program.c */ + int x; + #include "header.h" + + main () + { + printf (test ()); + } + + + /* File header.h */ + char *test (); + +the output generated by the C preprocessor for `program.c' as input +would be + + int x; + char *test (); + + main () + { + printf (test ()); + } + +Included files are not limited to declarations and macro definitions; +they are merely the typical use. Any fragment of a C program can be +included from another file. The include file could even contain the +beginning of a statement that is concluded in the containing file, or +the end of a statement that was started in the including file. +However, a comment or a string or character constant may not start in +the included file and finish in the including file. An unterminated +comment, string constant or character constant in an included file is +considered to end (with an error message) at the end of the file. + +The line following the `#include' command is always treated as a +separate line by the C preprocessor even if the included file lacks a +final newline. + + + +File: cpp.info, Node: Once-Only, Prev: Include Operation, Up: Header Files + +Once-Only Include Files +----------------------- + +Very often, one header file includes another. It can easily result +that a certain header file is included more than once. This may lead +to errors, if the header file defines structure types or typedefs, +and is certainly wasteful. Therefore, we often wish to prevent +multiple inclusion of a header file. + +The standard way to do this is to enclose the entire real contents of +the file in a conditional, like this: + + #ifndef __FILE_FOO_SEEN__ + #define __FILE_FOO_SEEN__ + + THE ENTIRE FILE + + #endif /* __FILE_FOO_SEEN__ */ + +The macro `__FILE_FOO_SEEN__' indicates that the file has been +included once already; its name should begin with `__', and should +contain the name of the file to avoid accidental conflicts. + +One drawback of this method is that the preprocessor must scan the +input file completely in order to determine that all of it is to be +ignored. This makes compilation slower. You can avoid the delay by +inserting the following command near the beginning of file *in +addition to the conditionals described above*: + + #pragma once + +This command tells the GNU C preprocessor to ignore any future +commands to include the same file (whichever file the `#pragma' +appears in). + +You should not *rely* on `#pragma once' to prevent multiple inclusion +of the file. It is just a hint, and a nonstandard one at that. Most +C compilers will ignore it entirely. For this reason, you still need +the conditionals if you want to make certain that the file's contents +are not included twice. + +Note that `#pragma once' works by file name; if a file has more than +one name, it can be included once under each name, even in GNU CC, +despite `#pragma once'. + + + +File: cpp.info, Node: Macros, Next: Conditionals, Prev: Header Files, Up: Top + +Macros +====== + +A macro is a sort of abbreviation which you can define once and then +use later. There are many complicated features associated with +macros in the C preprocessor. + +* Menu: + +* Simple Macros:: Macros that always expand the same way. +* Argument Macros:: Macros that accept arguments that are substituted + into the macro expansion. +* Predefined:: Predefined macros that are always available. +* Stringification:: Macro arguments converted into string constants. +* Concatenation:: Building tokens from parts taken from macro arguments. +* Undefining:: Cancelling a macro's definition. +* Redefining:: Changing a macro's definition. +* Macro Pitfalls:: Macros can confuse the unwary. Here we explain + several common problems and strange features. + + + +File: cpp.info, Node: Simple Macros, Next: Argument Macros, Prev: Macros, Up: Macros + +Simple Macros +------------- + +A "simple macro" is a kind of abbreviation. It is a name which +stands for a fragment of code. + +Before you can use a macro, you must "define" it explicitly with the +`#define' command. `#define' is followed by the name of the macro +and then the code it should be an abbreviation for. For example, + + #define BUFFER_SIZE 1020 + +defines a macro named `BUFFER_SIZE' as an abbreviation for the text +`1020'. Therefore, if somewhere after this `#define' command there +comes a C statement of the form + + foo = (char *) xmalloc (BUFFER_SIZE); + +then the C preprocessor will recognize and "expand" the macro +`BUFFER_SIZE', resulting in + + foo = (char *) xmalloc (1020); + +the definition must be a single line; however, it may not end in the +middle of a multi-line string constant or character constant. + +The use of all upper case for macro names is a standard convention. +Programs are easier to read when it is possible to tell at a glance +which names are macros. + +Normally, a macro definition must be a single line, like all C +preprocessor commands. (You can split a long macro definition +cosmetically with Backslash-Newline.) There is one exception: +Newlines can be included in the macro definition if within a string +or character constant. By the same token, it is not possible for a +macro definition to contain an unbalanced quote character; the +definition automatically extends to include the matching quote +character that ends the string or character constant. Comments +within a macro definition may contain Newlines, which make no +difference since the comments are entirely replaced with Spaces +regardless of their contents. + +Aside from the above, there is no restriction on what can go in a +macro body. Parentheses need not balance. The body need not +resemble valid C code. (Of course, you might get error messages from +the C compiler when you use the macro.) + +The C preprocessor scans your program sequentially, so macro +definitions take effect at the place you write them. Therefore, the +following input to the C preprocessor + + foo = X; + #define X 4 + bar = X; + +produces as output + + foo = X; + + bar = 4; + +After the preprocessor expands a macro name, the macro's definition +body is appended to the front of the remaining input, and the check +for macro calls continues. Therefore, the macro body can contain +calls to other macros. For example, after + + #define BUFSIZE 1020 + #define TABLESIZE BUFSIZE + +the name `TABLESIZE' when used in the program would go through two +stages of expansion, resulting ultimately in `1020'. + +This is not at all the same as defining `TABLESIZE' to be `1020'. +The `#define' for `TABLESIZE' uses exactly the body you specify--in +this case, `BUFSIZE'--and does not check to see whether it too is the +name of a macro. It's only when you *use* `TABLESIZE' that the +result of its expansion is checked for more macro names. *Note +Cascaded Macros::. + + + +File: cpp.info, Node: Argument Macros, Next: Predefined, Prev: Simple Macros, Up: Macros + +Macros with Arguments +--------------------- + +A simple macro always stands for exactly the same text, each time it +is used. Macros can be more flexible when they accept "arguments". +Arguments are fragments of code that you supply each time the macro +is used. These fragments are included in the expansion of the macro +according to the directions in the macro definition. + +To define a macro that uses arguments, you write a `#define' command +with a list of "argument names" in parentheses after the name of the +macro. The argument names may be any valid C identifiers, separated +by commas and optionally whitespace. The open-parenthesis must +follow the macro name immediately, with no space in between. + +For example, here is a macro that computes the minimum of two numeric +values, as it is defined in many C programs: + + #define min(X, Y) ((X) < (Y) ? (X) : (Y)) + +(This is not the best way to define a "minimum" macro in GNU C. +*Note Side Effects::, for more information.) + +To use a macro that expects arguments, you write the name of the +macro followed by a list of "actual arguments" in parentheses. +separated by commas. The number of actual arguments you give must +match the number of arguments the macro expects. Examples of use of +the macro `min' include `min (1, 2)' and `min (x + 28, *p)'. + +The expansion text of the macro depends on the arguments you use. +Each of the argument names of the macro is replaced, throughout the +macro definition, with the corresponding actual argument. Using the +same macro `min' defined above, `min (1, 2)' expands into + + ((1) < (2) ? (1) : (2)) + +where `1' has been substituted for `X' and `2' for `Y'. + +Likewise, `min (x + 28, *p)' expands into + + ((x + 28) < (*p) ? (x + 28) : (*p)) + +Parentheses in the actual arguments must balance; a comma within +parentheses does not end an argument. However, there is no +requirement for brackets or braces to balance; thus, if you want to +supply `array[x = y, x + 1]' as an argument, you must write it as +`array[(x = y, x + 1)]', which is equivalent C code. + +After the actual arguments are substituted into the macro body, the +entire result is appended to the front of the remaining input, and +the check for macro calls continues. Therefore, the actual arguments +can contain calls to other macros, either with or without arguments, +or even to the same macro. The macro body can also contain calls to +other macros. For example, `min (min (a, b), c)' expands into + + ((((a) < (b) ? (a) : (b))) < (c) + ? (((a) < (b) ? (a) : (b))) + : (c)) + +(Line breaks shown here for clarity would not actually be generated.) + +If you use the macro name followed by something other than an +open-parenthesis (after ignoring any spaces, tabs and comments that +follow), it is not a call to the macro, and the preprocessor leaves +the name unaltered. Therefore, it is possible for the same name to +be a variable or function in your program as well as a macro, and you +can choose in each instance whether to refer to the macro (if an +actual argument list follows) or the variable or function (if an +argument list does not follow). + +Such dual use of one name could be confusing and should be avoided +except when the two meanings are effectively synonymous: that is, +when the name is both a macro and a function and the two have similar +effects. You can think of the name simply as a function; use of the +name for purposes other than calling it (such as, to take the +address) will refer to the function, while calls will expand the +macro and generate better but equivalent code. For example, you can +use a function named `min' in the same source file that defines the +macro. If you write `&min' with no argument list, you refer to the +function. If you write `min (x, bb)', with an argument list, the +macro is expanded. If you write `(min) (a, bb)', where the name +`min' is not followed by an open-parenthesis, the macro is not +expanded, so you wind up with a call to the function `min'. + +It is not allowed to define the same name as both a simple macro and +a macro with arguments. + +In the definition of a macro with arguments, the list of argument +names must follow the macro name immediately with no space in +between. If there is a space after the macro name, the macro is +defined as taking no arguments, and all the rest of the name is taken +to be the expansion. The reason for this is that it is often useful +to define a macro that takes no arguments and whose definition begins +with an identifier in parentheses. This rule about spaces makes it +possible for you to do either this: + + #define FOO(x) - 1 / (x) + +(which defines `FOO' to take an argument and expand into minus the +reciprocal of that argument) or this: + + #define BAR (x) - 1 / (x) + +(which defines `BAR' to take no argument and always expand into `(x) +- 1 / (x)'). + +Note that the *uses* of a macro with arguments can have spaces before +the left parenthesis; it's the *definition* where it matters whether +there is a space. + + + +File: cpp.info, Node: Predefined, Next: Stringification, Prev: Argument Macros, Up: Macros + +Predefined Macros +----------------- + +Several simple macros are predefined. You can use them without +giving definitions for them. They fall into two classes: standard +macros and system-specific macros. + +* Menu: + +* Standard Predefined:: Standard predefined macros. +* Nonstandard Predefined:: Nonstandard predefined macros. + + + +File: cpp.info, Node: Standard Predefined, Next: Nonstandard Predefined, Prev: Predefined, Up: Predefined + +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. Their names all start and end with double underscores. Those +preceding `__GNUC__' in this table are standardized by ANSI C; the +rest are GNU C extensions. + +`__FILE__' + This macro expands to the name of the current input file, in the + form of a C string constant. + +`__BASE_FILE__' + This macro expands to the name of the main input file, in the + form of a C string constant. This is the source file that was + specified as an argument when the C compiler was invoked. + +`__LINE__' + This macro expands to the current input line number, in the form + of a decimal integer constant. While we call it a predefined + macro, it's a pretty strange macro, since its "definition" + changes with each new line of source code. + + This and `__FILE__' are useful in generating an error message to + report an inconsistency detected by the program; the message can + state the source line at which the inconsistency was detected. + For example, + + fprintf (stderr, "Internal error: negative string length " + "%d at %s, line %d.", + length, __FILE__, __LINE__); + + A `#include' command changes the expansions of `__FILE__' and + `__LINE__' to correspond to the included file. At the end of + that file, when processing resumes on the input file that + contained the `#include' command, the expansions of `__FILE__' + and `__LINE__' revert to the values they had before the + `#include' (but `__LINE__' is then incremented by one as + processing moves to the line after the `#include'). + + The expansions of both `__FILE__' and `__LINE__' are altered if + a `#line' command is used. *Note Combining Sources::. + +`__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 `"Jan 29 1987"' or + `"Apr 1 1905"'. + +`__TIME__' + This macro expands to a string constant that describes the time + at which the preprocessor is being run. The string constant + contains eight characters and looks like `"23:59:01"'. + +`__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 will operate on the output from the preprocessor.) + +`__GNUC__' + 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, `__GNUC__' is undefined. + +`__STRICT_ANSI__' + This macro is defined if and only if the `-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. + +`__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 `"1.18"'. The only + reasonable use of this macro is to incorporate it into a string + constant. + +`__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. + +`__CHAR_UNSIGNED__' + This macro is defined if and only if the data type `char' is + unsigned on the target machine. It exists to cause the standard + header file `limit.h' to work correctly. It is bad practice to + refer to this macro yourself; instead, refer to the standard + macros defined in `limit.h'. + + + +File: cpp.info, Node: Nonstandard Predefined, Prev: Standard Predefined, Up: Predefined + +Nonstandard Predefined Macros +............................. + + The C preprocessor normally has several predefined macros that vary +between machines because their purpose is to indicate what type of +system and machine is in use. This manual, being for all systems and +machines, cannot tell you exactly what their names are; instead, we +offer a list of some typical ones. + +Some nonstandard predefined macros describe the operating system in +use, with more or less specificity. For example, + +`unix' + `unix' is normally predefined on all Unix systems. + +`BSD' + `BSD' is predefined on recent versions of Berkeley Unix (perhaps + only in version 4.3). + +Other nonstandard predefined macros describe the kind of CPU, with +more or less specificity. For example, + +`vax' + `vax' is predefined on Vax computers. + +`mc68000' + `mc68000' is predefined on most computers whose CPU is a + Motorola 68000, 68010 or 68020. + +`m68k' + `m68k' is also predefined on most computers whose CPU is a + 68000, 68010 or 68020; however, some makers use `mc68000' and + some use `m68k'. Some predefine both names. What happens in + GNU C depends on the system you are using it on. + +`M68020' + `M68020' has been observed to be predefined on some systems that + use 68020 CPUs--in addition to `mc68000' and `m68k' that are + less specific. + +`ns32000' + `ns32000' is predefined on computers which use the National + Semiconductor 32000 series CPU. + +Yet other nonstandard predefined macros describe the manufacturer of +the system. For example, + +`sun' + `sun' is predefined on all models of Sun computers. + +`pyr' + `pyr' is predefined on all models of Pyramid computers. + +`sequent' + `sequent' is predefined on all models of Sequent computers. + +These predefined symbols are not only nonstandard, they are contrary +to the ANSI standard because their names do not start with underscores. +Therefore, the option `-ansi' inhibits the definition of these symbols. + +This tends to make `-ansi' useless, since many programs depend on the +customary nonstandard predefined symbols. Even system header files +check them and will generate incorrect declarations if they do not +find the names that are expected. You might think that the header +files supplied for the Uglix computer would not need to test what +machine they are running on, because they can simply assume it is the +Uglix; but often they do, and they do so using the customary names. +As a result, very few C programs will compile with `-ansi'. We +intend to avoid such problems on the GNU system. + +What, then, should you do in an ANSI C program to test the type of +machine it is to run on? + +GNU C offers a parallel series of symbols for this purpose, whose +names are made from the customary ones by adding `__' at the +beginning and end. Thus, the symbol `__vax__' would be available on +a vax, and so on. + +The set of nonstandard predefined names in the GNU C preprocessor is +controlled by the macro `CPP_PREDEFINES', which should be a string +containing `-D' options, separated by spaces. For example, on the +Sun 3, we use the following definition: + + #define CPP_PREDEFINES "-Dmc68000 -Dsun -Dunix -Dm68k" + + + +File: cpp.info, Node: Stringification, Next: Concatenation, Prev: Predefined, Up: Macros + +Stringification +--------------- + +"Stringification" means turning a code fragment into a string +constant whose contents are the text for the code fragment. For +example, stringifying `foo (z)' results in `"foo (z)"'. + +In the C preprocessor, stringification is an option available when +macro arguments are substituted into the macro definition. In the +body of the definition, when an argument name appears, the character +`#' before the name specifies stringification of the corresponding +actual argument when it is substituted at that point in the +definition. The same argument may be substituted in other places in +the definition without stringification if the argument name appears +in those places with no `#'. + +Here is an example of a macro definition that uses stringification: + + #define WARN_IF(EXP) \ + do { if (EXP) fprintf (stderr, "Warning: " #EXP "\n"); } while (0) + +Here the actual argument for `EXP' is substituted once as given, into +the `if' statement, and once as stringified, into the argument to +`fprintf'. The `do' and `while (0)' are a kludge to make it possible +to write `WARN_IF (ARG);', which the resemblance of `WARN_IF' to a +function would make C programmers want to do; *note Swallow +Semicolon::.). + +The stringification feature is limited to transforming one macro +argument into one string constant: there is no way to combine the +argument with other text and then stringify it all together. But the +example above shows how an equivalent result can be obtained in ANSI +Standard C using the feature that adjacent string constants are +concatenated as one string constant. The preprocessor stringifies +`EXP''s actual argument into a separate string constant, resulting in +text like + + do { if (x == 0) fprintf (stderr, "Warning: " "x == 0" "\n"); } while (0) + +but the C compiler then sees three consecutive string constants and +concatenates them into one, producing effectively + + do { if (x == 0) fprintf (stderr, "Warning: x == 0\n"); } while (0) + +Stringification in C involves more than putting doublequote +characters around the fragment; it is necessary to put backslashes in +front of all doublequote characters, and all backslashes in string +and character constants, in order to get a valid C string constant +with the proper contents. Thus, stringifying `p = "foo\n";' results +in `"p = \"foo\\n\";"'. However, backslashes that are not inside of +string or character constants are not duplicated: `\n' by itself +stringifies to `"\n"'. + +Whitespace (including comments) in the text being stringified is +handled according to precise rules. All leading and trailing +whitespace is ignored. Any sequence of whitespace in the middle of +the text is converted to a single space in the stringified result. + + + +File: cpp.info, Node: Concatenation, Next: Undefining, Prev: Stringification, Up: Macros + +Concatenation +------------- + +"Concatenation" means joining two strings into one. In the context +of macro expansion, concatenation refers to joining two lexical units +into one longer one. Specifically, an actual argument to the macro +can be concatenated with another actual argument or with fixed text +to produce a longer name. The longer name might be the name of a +function, variable or type, or a C keyword; it might even be the name +of another macro, in which case it will be expanded. + +When you define a macro, you request concatenation with the special +operator `##' in the macro body. When the macro is called, after +actual arguments are substituted, all `##' operators are deleted, and +so is any whitespace next to them (including whitespace that was part +of an actual argument). The result is to concatenate the syntactic +tokens on either side of the `##'. + +Consider a C program that interprets named commands. There probably +needs to be a table of commands, perhaps an array of structures +declared as follows: + + struct command + { + char *name; + void (*function) (); + }; + + struct command commands[] = + { + { "quit", quit_command}, + { "help", help_command}, + ... + }; + +It would be cleaner not to have to give each command name twice, once +in the string constant and once in the function name. A macro which +takes the name of a command as an argument can make this unnecessary. +The string constant can be created with stringification, and the +function name by concatenating the argument with `_command'. Here is +how it is done: + + #define COMMAND(NAME) { #NAME, NAME ## _command } + + struct command commands[] = + { + COMMAND (quit), + COMMAND (help), + ... + }; + +The usual case of concatenation is concatenating two names (or a name +and a number) into a longer name. But this isn't the only valid +case. It is also possible to concatenate two numbers (or a number +and a name, such as `1.5' and `e3') into a number. Also, +multi-character operators such as `+=' can be formed by +concatenation. In some cases it is even 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 `x' on one side and `+' 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 +concatenation are undefined, but in the GNU C preprocessor it is well +defined: it puts the `x' and `+' side by side with no particular +special results. + +Keep in mind that the C preprocessor converts comments to whitespace +before macros are even considered. Therefore, you cannot create a +comment by concatenating `/' and `*': the `/*' sequence that starts a +comment is not a lexical unit, but rather the beginning of a "long" +space character. Also, you can freely use comments next to a `##' in +a macro definition, or in actual arguments that will be concatenated, +because the comments will be converted to spaces at first sight, and +concatenation will later discard the spaces. + + + +File: cpp.info, Node: Undefining, Next: Redefining, Prev: Concatenation, Up: Macros + +Undefining Macros +----------------- + +To "undefine" a macro means to cancel its definition. This is done +with the `#undef' command. `#undef' is followed by the macro name to +be undefined. + +Like definition, undefinition occurs at a specific point in the +source file, and it applies starting from that point. The name +ceases to be a macro name, and from that point on it is treated by +the preprocessor as if it had never been a macro name. + +For example, + + #define FOO 4 + x = FOO; + #undef FOO + x = FOO; + +expands into + + x = 4; + + x = FOO; + +In this example, `FOO' had better be a variable or function as well +as (temporarily) a macro, in order for the result of the expansion to +be valid C code. + +The same form of `#undef' command will cancel definitions with +arguments or definitions that don't expect arguments. The `#undef' +command has no effect when used on a name not currently defined as a +macro. + + + +File: cpp.info, Node: Redefining, Next: Macro Pitfalls, Prev: Undefining, Up: Macros + +Redefining Macros +----------------- + +"Redefining" a macro means defining (with `#define') a name that is +already defined as a macro. + +A redefinition is trivial if the new definition is transparently +identical to the old one. You probably wouldn't deliberately write a +trivial redefinition, but they can happen automatically when a header +file is included more than once (*note Header Files::.), so they are +accepted silently and without effect. + +Nontrivial redefinition is considered likely to be an error, so it +provokes a warning message from the preprocessor. However, sometimes +it is useful to change the definition of a macro in mid-compilation. +You can inhibit the warning by undefining the macro with `#undef' +before the second definition. + +In order for a redefinition to be trivial, the new definition must +exactly match the one already in effect, with two possible exceptions: + + * Whitespace may be added or deleted at the beginning or the end. + + * Whitespace may be changed in the middle (but not inside strings). + However, it may not be eliminated entirely, and it may not be + added where there was no whitespace at all. + +Recall that a comment counts as whitespace. + + + +File: cpp.info, Node: Macro Pitfalls, Prev: Redefining, Up: Macros + +Pitfalls and Subtleties of Macros +--------------------------------- + +In this section we describe some special rules that apply to macros +and macro expansion, and point out certain cases in which the rules +have counterintuitive consequences that you must watch out for. + +* Menu: + +* Misnesting:: Macros can contain unmatched parentheses. +* Macro Parentheses:: Why apparently superfluous parentheses + may be necessary to avoid incorrect grouping. +* Swallow Semicolon:: Macros that look like functions + but expand into compound statements. +* Side Effects:: Unsafe macros that cause trouble when + arguments contain side effects. +* Self-Reference:: Macros whose definitions use the macros' own names. +* Argument Prescan:: Actual arguments are checked for macro calls + before they are substituted. +* Cascaded Macros:: Macros whose definitions use other macros. + + + +File: cpp.info, Node: Misnesting, Next: Macro Parentheses, Prev: Macro Pitfalls, Up: Macro Pitfalls + +Improperly Nested Constructs +............................ + + Recall that when a macro is called with arguments, the arguments are +substituted into the macro body and the result is checked, together +with the rest of the input file, for more macro calls. + +It is possible to piece together a macro call coming partially from +the macro body and partially from the actual arguments. For example, + + #define double(x) (2*(x)) + #define call_with_1(x) x(1) + +would expand `call_with_1 (double)' into `(2*(1))'. + +Macro definitions do not have to have balanced parentheses. By +writing an unbalanced open parenthesis in a macro body, it is +possible to create a macro call that begins inside the macro body but +ends outside of it. For example, + + #define strange(file) fprintf (file, "%s %d", + ... + strange(stderr) p, 35) + +This bizarre example expands to `fprintf (stderr, "%s %d", p, 35)'! + + + +File: cpp.info, Node: Macro Parentheses, Next: Swallow Semicolon, Prev: Misnesting, Up: Macro Pitfalls + +Unintended Grouping of Arithmetic +................................. + + You may have noticed that in most of the macro definition examples +shown above, each occurrence of a macro argument name had parentheses +around it. In addition, another pair of parentheses usually surround +the entire macro definition. Here is why it is best to write macros +that way. + +Suppose you define a macro as follows, + + #define ceil_div(x, y) (x + y - 1) / y + +whose purpose is to divide, rounding up. (One use for this operation +is to compute how many `int''s are needed to hold a certain number of +`char''s.) Then suppose it is used as follows: + + a = ceil_div (b & c, sizeof (int)); + +This expands into + + a = (b & c + sizeof (int) - 1) / sizeof (int); + +which does not do what is intended. The operator-precedence rules of +C make it equivalent to this: + + a = (b & (c + sizeof (int) - 1)) / sizeof (int); + +But what we want is this: + + a = ((b & c) + sizeof (int) - 1)) / sizeof (int); + +Defining the macro as + + #define ceil_div(x, y) ((x) + (y) - 1) / (y) + +provides the desired result. + +However, unintended grouping can result in another way. Consider +`sizeof ceil_div(1, 2)'. That has the appearance of a C expression +that would compute the size of the type of `ceil_div (1, 2)', but in +fact it means something very different. Here is what it expands to: + + sizeof ((1) + (2) - 1) / (2) + +This would take the size of an integer and divide it by two. The +precedence rules have put the division outside the `sizeof' when it +was intended to be inside. + +Parentheses around the entire macro definition can prevent such +problems. Here, then, is the recommended way to define `ceil_div': + + #define ceil_div(x, y) (((x) + (y) - 1) / (y)) + + + +File: cpp.info, Node: Swallow Semicolon, Next: Side Effects, Prev: Macro Parentheses, Up: Macro Pitfalls + +Swallowing the Semicolon +........................ + + Often it is desirable to define a macro that expands into a compound +statement. Consider, for example, the following macro, that advances +a pointer (the argument `p' says where to find it) across whitespace +characters: + + #define SKIP_SPACES (p, limit) \ + { register char *lim = (limit); \ + while (p != lim) { \ + if (*p++ != ' ') { \ + p--; break; }}} + +Here Backslash-Newline is used to split the macro definition, which +must be a single line, so that it resembles the way such C code would +be laid out if not part of a macro definition. + +A call to this macro might be `SKIP_SPACES (p, lim)'. Strictly +speaking, the call expands to a compound statement, which is a +complete statement with no need for a semicolon to end it. But it +looks like a function call. So it minimizes confusion if you can use +it like a function call, writing a semicolon afterward, as in +`SKIP_SPACES (p, lim);' + +But this can cause trouble before `else' statements, because the +semicolon is actually a null statement. Suppose you write + + if (*p != 0) + SKIP_SPACES (p, lim); + else ... + + The presence of two statements--the compound statement and a null +statement--in between the `if' condition and the `else' makes invalid +C code. + +The definition of the macro `SKIP_SPACES' can be altered to solve +this problem, using a `do ... while' statement. Here is how: + + #define SKIP_SPACES (p, limit) \ + do { register char *lim = (limit); \ + while (p != lim) { \ + if (*p++ != ' ') { \ + p--; break; }}} \ + while (0) + +Now `SKIP_SPACES (p, lim);' expands into + + do {...} while (0); + +which is one statement. + + + +File: cpp.info, Node: Side Effects, Next: Self-Reference, Prev: Swallow Semicolon, Up: Macro Pitfalls + +Duplication of Side Effects +........................... + + Many C programs define a macro `min', for "minimum", like this: + + #define min(X, Y) ((X) < (Y) ? (X) : (Y)) + +When you use this macro with an argument containing a side effect, as +shown here, + + next = min (x + y, foo (z)); + +it expands as follows: + + next = ((x + y) < (foo (z)) ? (x + y) : (foo (z))); + +where `x + y' has been substituted for `X' and `foo (z)' for `Y'. + +The function `foo' is used only once in the statement as it appears +in the program, but the expression `foo (z)' has been substituted +twice into the macro expansion. As a result, `foo' might be called +two times when the statement is executed. If it has side effects or +if it takes a long time to compute, the results might not be what you +intended. We say that `min' is an "unsafe" macro. + +The best solution to this problem is to define `min' in a way that +computes the value of `foo (z)' only once. The C language offers no +standard way to do this, but it can be done with GNU C extensions as +follows: + + #define min(X, Y) \ + ({ typeof (X) __x = (X), __y = (Y); \ + (__x < __y) ? __x : __y; }) + +If you do not wish to use GNU C extensions, the only solution is to +be careful when *using* the macro `min'. For example, you can +calculate the value of `foo (z)', save it in a variable, and use that +variable in `min': + + #define min(X, Y) ((X) < (Y) ? (X) : (Y)) + ... + { + int tem = foo (z); + next = min (x + y, tem); + } + +(where I assume that `foo' returns type `int'). + + diff --git a/gcc-1.40/cpp.info-2 b/gcc-1.40/cpp.info-2 new file mode 100644 index 0000000..1da8e85 --- /dev/null +++ b/gcc-1.40/cpp.info-2 @@ -0,0 +1,881 @@ +Info file cpp.info, produced by Makeinfo, -*- Text -*- from input +file cpp.texinfo. + +This file documents the GNU C Preprocessor. + +Copyright (C) 1987, 1989 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. + +Permission is granted to copy and distribute modified versions of +this manual under the conditions for verbatim copying, provided also +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. + + + +File: cpp.info, Node: Self-Reference, Next: Argument Prescan, Prev: Side Effects, Up: Macro Pitfalls + +Self-Referential Macros +....................... + + A "self-referential" macro is one whose name appears in its definition. +A special feature of ANSI Standard C is that the self-reference is +not considered a macro call. It is passed into the preprocessor +output unchanged. + +Let's consider an example: + + #define foo (4 + foo) + +where `foo' is also a variable in your program. + +Following the ordinary rules, each reference to `foo' will expand +into `(4 + foo)'; then this will be rescanned and will expand into +`(4 + (4 + foo))'; and so on until it causes a fatal error (memory +full) in the preprocessor. + +However, the special rule about self-reference cuts this process +short after one step, at `(4 + foo)'. Therefore, this macro +definition has the possibly useful effect of causing the program to +add 4 to the value of `foo' wherever `foo' is referred to. + +In most cases, it is a bad idea to take advantage of this feature. A +person reading the program who sees that `foo' is a variable will not +expect that it is a macro as well. The reader will come across the +identifier `foo' in the program and think its value should be that of +the variable `foo', whereas in fact the value is four greater. + +The special rule for self-reference applies also to "indirect" +self-reference. This is the case where a macro X expands to use a +macro `y', and `y''s expansion refers to the macro `x'. The +resulting reference to `x' comes indirectly from the expansion of +`x', so it is a self-reference and is not further expanded. Thus, +after + + #define x (4 + y) + #define y (2 * x) + +`x' would expand into `(4 + (2 * x))'. Clear? + +But suppose `y' is used elsewhere, not from the definition of `x'. +Then the use of `x' in the expansion of `y' is not a self-reference +because `x' is not "in progress". So it does expand. However, the +expansion of `x' contains a reference to `y', and that is an indirect +self-reference now because `y' is "in progress". The result is that +`y' expands to `(2 * (4 + y))'. + +It is not clear that this behavior would ever be useful, but it is +specified by the ANSI C standard, so you need to understand it. + + + +File: cpp.info, Node: Argument Prescan, Next: Cascaded Macros, Prev: Self-Reference, Up: Macro Pitfalls + +Separate Expansion of Macro Arguments +..................................... + + We have explained that the expansion of a macro, including the +substituted actual arguments, is scanned over again for macro calls +to be expanded. + +What really happens is more subtle: first each actual argument text +is scanned separately for macro calls. Then the results of this are +substituted into the macro body to produce the macro expansion, and +the macro expansion is scanned again for macros to expand. + +The result is that the actual arguments are scanned *twice* to expand +macro calls in them. + +Most of the time, this has no effect. If the actual argument +contained any macro calls, they are expanded during the first scan. +The result therefore contains no macro calls, so the second scan does +not change it. If the actual argument were substituted as given, +with no prescan, the single remaining scan would find the same macro +calls and produce the same results. + +You might expect the double scan to change the results when a +self-referential macro is used in an actual argument of another macro +(*note Self-Reference::.): the self-referential macro would be +expanded once in the first scan, and a second time in the second +scan. But this is not what happens. The self-references that do not +expand in the first scan are marked so that they will not expand in +the second scan either. + +The prescan is not done when an argument is stringified or +concatenated. Thus, + + #define str(s) #s + #define foo 4 + str (foo) + +expands to `"foo"'. Once more, prescan has been prevented from +having any noticeable effect. + +More precisely, stringification and concatenation use the argument as +written, in un-prescanned form. The same actual argument would be +used in prescanned form if it is substituted elsewhere without +stringification or concatenation. + + #define str(s) #s lose(s) + #define foo 4 + str (foo) + +expands to `"foo" lose(4)'. + +You might now ask, "Why mention the prescan, if it makes no difference? +And why not skip it and make the preprocessor faster?" The answer is +that the prescan does make a difference in three special cases: + + * Nested calls to a macro. + + * Macros that call other macros that stringify or concatenate. + + * Macros whose expansions contain unshielded commas. + +We say that "nested" calls to a macro occur when a macro's actual +argument contains a call to that very macro. For example, if `f' is +a macro that expects one argument, `f (f (1))' is a nested pair of +calls to `f'. The desired expansion is made by expanding `f (1)' and +substituting that into the definition of `f'. The prescan causes the +expected result to happen. Without the prescan, `f (1)' itself would +be substituted as an actual argument, and the inner use of `f' would +appear during the main scan as an indirect self-reference and would +not be expanded. Here, the prescan cancels an undesirable side +effect (in the medical, not computational, sense of the term) of the +special rule for self-referential macros. + +But prescan causes trouble in certain other cases of nested macro +calls. Here is an example: + + #define foo a,b + #define bar(x) lose(x) + #define lose(x) (1 + (x)) + + bar(foo) + +We would like `bar(foo)' to turn into `(1 + (foo))', which would then +turn into `(1 + (a,b))'. But instead, `bar(foo)' expands into +`lose(a,b)', and you get an error because `lose' requires a single +argument. In this case, the problem is easily solved by the same +parentheses that ought to be used to prevent misnesting of arithmetic +operations: + + #define foo (a,b) + #define bar(x) lose((x)) + +The problem is more serious when the operands of the macro are not +expressions; for example, when they are statements. Then parentheses +are unacceptable because they would make for invalid C code: + + #define foo { int a, b; ... } + +In GNU C you can shield the commas using the `({...})' construct +which turns a compound statement into an expression: + + #define foo ({ int a, b; ... }) + +Or you can rewrite the macro definition to avoid such commas: + + #define foo { int a; int b; ... } + +There is also one case where prescan is useful. It is possible to +use prescan to expand an argument and then stringify it--if you use +two levels of macros. Let's add a new macro `xstr' to the example +shown above: + + #define xstr(s) str(s) + #define str(s) #s + #define foo 4 + xstr (foo) + +This expands into `"4"', not `"foo"'. The reason for the difference +is that the argument of `xstr' is expanded at prescan (because `xstr' +does not specify stringification or concatenation of the argument). +The result of prescan then forms the actual argument for `str'. +`str' uses its argument without prescan because it performs +stringification; but it cannot prevent or undo the prescanning +already done by `xstr'. + + + +File: cpp.info, Node: Cascaded Macros, Prev: Argument Prescan, Up: Macro Pitfalls + +Cascaded Use of Macros +...................... + + A "cascade" of macros is when one macro's body contains a reference +to another macro. This is very common practice. For example, + + #define BUFSIZE 1020 + #define TABLESIZE BUFSIZE + +This is not at all the same as defining `TABLESIZE' to be `1020'. +The `#define' for `TABLESIZE' uses exactly the body you specify--in +this case, `BUFSIZE'--and does not check to see whether it too is the +name of a macro. + +It's only when you *use* `TABLESIZE' that the result of its expansion +is checked for more macro names. + +This makes a difference if you change the definition of `BUFSIZE' at +some point in the source file. `TABLESIZE', defined as shown, will +always expand using the definition of `BUFSIZE' that is currently in +effect: + + #define BUFSIZE 1020 + #define TABLESIZE BUFSIZE + #undef BUFSIZE + #define BUFSIZE 37 + +Now `TABLESIZE' expands (in two stages) to `37'. + + + +File: cpp.info, Node: Conditionals, Next: Combining Sources, Prev: Macros, Up: Top + +Conditionals +============ + +In a macro processor, a "conditional" is a command that allows a part +of the program to be ignored during compilation, on some conditions. +In the C preprocessor, a conditional can test either an arithmetic +expression or whether a name is defined as a macro. + +A conditional in the C preprocessor resembles in some ways an `if' +statement in C, but it is important to understand the difference +between them. The condition in an `if' statement is tested during +the execution of your program. Its purpose is to allow your program +to behave differently from run to run, depending on the data it is +operating on. The condition in a preprocessor conditional command is +tested when your program is compiled. Its purpose is to allow +different code to be included in the program depending on the +situation at the time of compilation. + +* Menu: + +* Uses: Conditional Uses. What conditionals are for. +* Syntax: Conditional Syntax. How conditionals are written. +* Deletion: Deleted Code. Making code into a comment. +* Macros: Conditionals-Macros. Why conditionals are used with macros. +* Errors: #error Command. Detecting inconsistent compilation parameters. + + + +File: cpp.info, Node: Conditional Uses, Next: Conditional Syntax, Prev: Conditionals, Up: Conditionals + +Why Conditionals are Used +------------------------- + +Generally there are three kinds of reason to use a conditional. + + * A program may need to use different code depending on the + machine or operating system it is to run on. In some cases the + code for one operating system may be erroneous on another + operating system; for example, it might refer to library + routines that do not exist on the other system. When this + happens, it is not enough to avoid executing the invalid code: + merely having it in the program makes it impossible to link the + program and run it. With a preprocessor conditional, the + offending code can be effectively excised from the program when + it is not valid. + + * You may want to be able to compile the same source file into two + different programs. Sometimes the difference between the + programs is that one makes frequent time-consuming consistency + checks on its intermediate data while the other does not. + + * A conditional whose condition is always false is a good way to + exclude code from the program but keep it as a sort of comment + for future reference. + +Most simple programs that are intended to run on only one machine +will not need to use preprocessor conditionals. + + + +File: cpp.info, Node: Conditional Syntax, Next: Deleted Code, Prev: Conditional Uses, Up: Conditionals + +Syntax of Conditionals +---------------------- + +A conditional in the C preprocessor begins with a "conditional +command": `#if', `#ifdef' or `#ifndef'. *Note Conditionals-Macros::, +for info on `#ifdef' and `#ifndef'; only `#if' is explained here. + +* Menu: + +* If: #if Command. Basic conditionals using `#if' and `#endif'. +* Else: #else Command. Including some text if the condition fails. +* Elif: #elif Command. Testing several alternative possibilities. + + + +File: cpp.info, Node: #if Command, Next: #else Command, Prev: Conditional Syntax, Up: Conditional Syntax + +The `#if' Command +................. + + The `#if' command in its simplest form consists of + + #if EXPRESSION + CONTROLLED TEXT + #endif /* EXPRESSION */ + +The comment following the `#endif' is not required, but it is a good +practice because it helps people match the `#endif' to the +corresponding `#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 `#endif' and it will be ignored by the GNU +C preprocessor, but only comments are acceptable in ANSI Standard C. + +EXPRESSION is a C expression of integer type, subject to stringent +restrictions. It may contain + + * Integer constants, which are all regarded as `long' or `unsigned + long'. + + * Character constants, which are interpreted according to the + character set and conventions of the machine and operating + system on which the preprocessor is running. The GNU C + preprocessor uses the C data type `char' for these character + constants; therefore, whether some character codes are negative + is determined by the C compiler used to compile the + preprocessor. If it treats `char' as signed, then character + codes large enough to set the sign bit will be considered + negative; otherwise, no character code is considered negative. + + * Arithmetic operators for addition, subtraction, multiplication, + division, bitwise operations, shifts, comparisons, and `&&' and + `||'. + + * Identifiers that are not macros, which are all treated as zero(!). + + * Macro calls. All macro calls in the expression are expanded + before actual computation of the expression's value begins. + +Note that `sizeof' operators and `enum'-type values are not allowed. +`enum'-type values, like all other identifiers that are not taken as +macro calls and expanded, are treated as zero. + +The text inside of a conditional can include preprocessor commands. +Then the commands inside the conditional are obeyed only if that +branch of the conditional succeeds. The text can also contain other +conditional groups. However, the `#if''s and `#endif''s must balance. + + + +File: cpp.info, Node: #else Command, Next: #elif Command, Prev: #if Command, Up: Conditional Syntax + +The `#else' Command +................... + + The `#else' command can be added to a conditional to provide +alternative text to be used if the condition is false. This looks like + + #if EXPRESSION + TEXT-IF-TRUE + #else /* Not EXPRESSION */ + TEXT-IF-FALSE + #endif /* Not EXPRESSION */ + +If EXPRESSION is nonzero, and the TEXT-IF-TRUE is considered +included, then `#else' acts like a failing conditional and the +TEXT-IF-FALSE is ignored. Contrariwise, if the `#if' conditional +fails, the TEXT-IF-FALSE is considered included. + + + +File: cpp.info, Node: #elif Command, Prev: #else Command, Up: Conditional Syntax + +The `#elif' Command +................... + + One common case of nested conditionals is used to check for more than +two possible alternatives. For example, you might have + + #if X == 1 + ... + #else /* X != 1 */ + #if X == 2 + ... + #else /* X != 2 */ + ... + #endif /* X != 2 */ + #endif /* X != 1 */ + +Another conditional command, `#elif', allows this to be abbreviated +as follows: + + #if X == 1 + ... + #elif X == 2 + ... + #else /* X != 2 and X != 1*/ + ... + #endif /* X != 2 and X != 1*/ + +`#elif' stands for "else if". Like `#else', it goes in the middle of +a `#if'-`#endif' pair and subdivides it; it does not require a +matching `#endif' of its own. Like `#if', the `#elif' command +includes an expression to be tested. + +The text following the `#elif' is processed only if the original +`#if'-condition failed and the `#elif' condition succeeeds. More +than one `#elif' can go in the same `#if'-`#endif' group. Then the +text after each `#elif' is processed only if the `#elif' condition +succeeds after the original `#if' and any previous `#elif''s within +it have failed. `#else' is equivalent to `#elif 1', and `#else' is +allowed after any number of `#elif''s, but `#elif' may not follow a +`#else'. + + + +File: cpp.info, Node: Deleted Code, Next: Conditionals-Macros, Prev: Conditional Syntax, Up: Conditionals + +Keeping Deleted Code for Future Reference +----------------------------------------- + +If you replace or delete a part of the program but want to keep the +old code around as a comment for future reference, the easy way to do +this is to put `#if 0' before it and `#endif' after it. + +This works even if the code being turned off contains conditionals, +but they must be entire conditionals (balanced `#if' and `#endif'). + + + +File: cpp.info, Node: Conditionals-Macros, Next: #error Command, Prev: Deleted Code, Up: Conditionals + +Conditionals and Macros +----------------------- + +Conditionals are rarely useful except in connection with macros. A +`#if' command whose expression uses no macros is equivalent to `#if +1' or `#if 0'; you might as well determine which one, by computing +the value of the expression yourself, and then simplify the program. +But when the expression uses macros, its value can vary from +compilation to compilation. + +For example, here is a conditional that tests the expression `BUFSIZE +== 1020', where `BUFSIZE' must be a macro. + + #if BUFSIZE == 1020 + printf ("Large buffers!\n"); + #endif /* BUFSIZE is large */ + +The special operator `defined' may be used in `#if' expressions to +test whether a certain name is defined as a macro. Either `defined +NAME' or `defined (NAME)' is an expression whose value is 1 if NAME +is defined as macro at the current point in the program, and 0 +otherwise. For the `defined' operator it makes no difference what +the definition of the macro is; all that matters is whether there is +a definition. Thus, for example, + + #if defined (vax) || defined (ns16000) + +would include the following code if either of the names `vax' and +`ns16000' is defined as a macro. + +If a macro is defined and later undefined with `#undef', subsequent +use of the `defined' operator will return 0, because the name is no +longer defined. If the macro is defined again with another +`#define', `defined' will recommence returning 1. + +Conditionals that test just the definedness of one name are very +common, so there are two special short conditional commands for this +case. They are + +`#ifdef NAME' + is equivalent to `#if defined (NAME)'. + +`#ifndef NAME' + is equivalent to `#if ! defined (NAME)'. + +Macro definitions can vary between compilations for several reasons. + + * Some macros are predefined on each kind of machine. For + example, on a Vax, the name `vax' is a predefined macro. On + other machines, it would not be defined. + + * Many more macros are defined by system header files. Different + systems and machines define different macros, or give them + different values. It is useful to test these macros with + conditionals to avoid using a system feature on a machine where + it is not implemented. + + * Macros are a common way of allowing users to customize a program + for different machines or applications. For example, the macro + `BUFSIZE' might be defined in a configuration file for your + program that is included as a header file in each source file. + You would use `BUFSIZE' in a preprocessor conditional in order + to generate different code depending on the chosen configuration. + + * Macros can be defined or undefined with `-D' and `-U' command + options when you compile the program. You can arrange to + compile the same source file into two different programs by + choosing a macro name to specify which program you want, writing + conditionals to test whether or how this macro is defined, and + then controlling the state of the macro with compiler command + options. *Note Invocation::. + + + +File: cpp.info, Node: #error Command, Prev: Conditionals-Macros, Up: Conditionals + +The `#error' Command +-------------------- + +The command `#error' causes the preprocessor to report a fatal error. +The rest of the line that follows `#error' is used as the error +message. + +You would use `#error' inside of a conditional that detects a +combination of parameters which you know the program does not +properly support. For example, if you know that the program will not +run properly on a Vax, you might write + + #ifdef vax + #error Won't work on Vaxen. See comments at get_last_object. + #endif + +*Note Nonstandard Predefined::, for why this works. + +If you have several configuration parameters that must be set up by +the installation in a consistent way, you can use conditionals to +detect an inconsistency and report it with `#error'. For example, + + #if HASH_TABLE_SIZE % 2 == 0 || HASH_TABLE_SIZE % 3 == 0 \ + || HASH_TABLE_SIZE % 5 == 0 + #error HASH_TABLE_SIZE should not be divisible by a small prime + #endif + + + +File: cpp.info, Node: Combining Sources, Next: Other Commands, Prev: Conditionals, Up: Top + +Combining Source Files +====================== + +One of the jobs of the C preprocessor is to inform the C compiler of +where each line of C code came from: which source file and which line +number. + +C code can come from multiple source files if you use `#include'; +both `#include' and the use of conditionals and macros can cause the +line number of a line in the preprocessor output to be different from +the line's number in the original source file. You will appreciate +the value of making both the C compiler (in error messages) and +symbolic debuggers such as GDB use the line numbers in your source +file. + +The C preprocessor builds on this feature by offering a command by +which you can control the feature explicitly. This is useful when a +file for input to the C preprocessor is the output from another +program such as the `bison' parser generator, which operates on +another file that is the true source file. Parts of the output from +`bison' are generated from scratch, other parts come from a standard +parser file. The rest are copied nearly verbatim from the source +file, but their line numbers in the `bison' output are not the same +as their original line numbers. Naturally you would like compiler +error messages and symbolic debuggers to know the original source +file and line number of each line in the `bison' output. + +`bison' arranges this by writing `#line' commands into the output +file. `#line' is a command that specifies the original line number +and source file name for subsequent input in the current preprocessor +input file. `#line' has three variants: + +`#line LINENUM' + Here LINENUM is a decimal integer constant. This specifies that + the line number of the following line of input, in its original + source file, was LINENUM. + +`#line LINENUM FILENAME' + Here LINENUM is a decimal integer constant and FILENAME is a + string constant. This specifies that the following line of + input came originally from source file FILENAME and its line + number there was LINENUM. Keep in mind that FILENAME is not + just a file name; it is surrounded by doublequote characters so + that it looks like a string constant. + +`#line ANYTHING ELSE' + ANYTHING ELSE is checked for macro calls, which are expanded. + The result should be a decimal integer constant followed + optionally by a string constant, as described above. + +`#line' commands alter the results of the `__FILE__' and `__LINE__' +predefined macros from that point on. *Note Standard Predefined::. + + + +File: cpp.info, Node: Other Commands, Next: Output, Prev: Combining Sources, Up: Top + +Miscellaneous Preprocessor Commands +=================================== + +This section describes three additional preprocessor commands. They +are not very useful, but are mentioned for completeness. + +The "null command" consists of a `#' followed by a Newline, with only +whitespace (including comments) in between. A null command is +understood as a preprocessor command but has no effect on the +preprocessor output. The primary significance of the existence of +the null command is that an input line consisting of just a `#' will +produce no output, rather than a line of output containing just a +`#'. Supposedly some old C programs contain such lines. + +The `#pragma' command is specified in the ANSI standard to have an +arbitrary implementation-defined effect. In the GNU C preprocessor, +`#pragma' commands are ignored, except for `#pragma once' (*note +Once-Only::.). + +The `#ident' command is supported for compatibility with certain +other systems. It is followed by a line of text. On certain +systems, the text is copied into a special place in the object file; +on most systems, the text is ignored and this directive has no effect. + + + +File: cpp.info, Node: Output, Next: Invocation, Prev: Other Commands, Up: Top + +C Preprocessor Output +===================== + +The output from the C preprocessor looks much like the input, except +that all preprocessor command 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. + +Source file name and line number information is conveyed by lines of +the form + + # LINENUM FILENAME FLAG + +which are inserted as needed into the middle of the input (but never +within a string or character constant). Such a line means that the +following line originated in file FILENAME at line LINENUM. + +The third field, FLAG, may be a number, or may be absent. It is `1' +for the beginning of a new source file, and `2' for return to an old +source file at the end of an included file. It is absent otherwise. + + + +File: cpp.info, Node: Invocation, Next: Concept Index, Prev: Output, Up: Top + +Invoking the C Preprocessor +=========================== + +Most often when you use the C preprocessor you will not have to +invoke it explicitly: the C compiler will do so automatically. +However, the preprocessor is sometimes useful individually. + +The C preprocessor expects two file names as arguments, INFILE and +OUTFILE. The preprocessor reads INFILE together with any other files +it specifies with `#include'. All the output generated by the +combined input files is written in OUTFILE. + +Either INFILE or OUTFILE may be `-', which as INFILE means to read +from standard input and as OUTFILE means to write to standard output. +Also, if OUTFILE or both file names are omitted, the standard output +and standard input are used for the omitted file names. + +Here is a table of command options accepted by the C preprocessor. +Most of them can also be given when compiling a C program; they are +passed along automatically to the preprocessor when it is invoked by +the compiler. + +`-P' + Inhibit generation of `#'-lines with line-number information in + the output from the preprocessor (*note Output::.). This might + be useful when running the preprocessor on something that is not + C code and will be sent to a program which might be confused by + the `#'-lines + +`-C' + Do not discard comments: pass them through to the output file. + Comments appearing in arguments of a macro call will be copied + to the output before the expansion of the macro call. + +`-trigraphs' + Process ANSI standard trigraph sequences. These are + three-character sequences, all starting with `??', that are + defined by ANSI C to stand for single characters. For example, + `??/' stands for `\', so `'??/n'' is a character constant for a + newline. Strictly speaking, the GNU C preprocessor does not + support all programs in ANSI Standard C unless `-trigraphs' is + used, but if you ever notice the difference it will be with + relief. + + You don't want to know any more about trigraphs. + +`-pedantic' + Issue warnings required by the ANSI C standard in certain cases + such as when text other than a comment follows `#else' or + `#endif'. + +`-I DIRECTORY' + Add the directory DIRECTORY to the end of the list of + directories to be searched for header files (*note Include + Syntax::.). 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 `-I' option, the directories are scanned in + left-to-right order; the standard system directories come after. + +`-I-' + Any directories specified with `-I' options before the `-I-' + option are searched only for the case of `#include "FILE"'; they + are not searched for `#include '. + + If additional directories are specified with `-I' options after + the `-I-', these directories are searched for all `#include' + directives. + + In addition, the `-I-' option inhibits the use of the current + directory as the first search directory for `#include "FILE"'. + Therefore, the current directory is searched only if it is + requested explicitly with `-I.'. Specifying both `-I-' and + `-I.' allows you to control precisely which directories are + searched before the current one and which are searched after. + +`-nostdinc' + Do not search the standard system directories for header files. + Only the directories you have specified with `-I' options (and + the current directory, if appropriate) are searched. + +`-D NAME' + Predefine NAME as a macro, with definition `1'. + +`-D NAME=DEFINITION' + Predefine NAME as a macro, with definition DEFINITION. There + are no restrictions on the contents of DEFINITION, but if you + are invoking the preprocessor from a shell or shell-like program + you may need to use the shell's quoting syntax to protect + characters such as spaces that have a meaning in the shell syntax. + +`-U NAME' + Do not predefine NAME. If both `-U' and `-D' are specified for + one name, the `-U' beats the `-D' and the name is not predefined. + +`-undef' + Do not predefine any nonstandard macros. + +`-d' + Instead of outputting the result of preprocessing, output a list + of `#define' commands for all the macros defined during the + execution of the preprocessor. + +`-M' + Instead of outputting the result of preprocessing, output a rule + suitable for `make' describing the dependencies of the main + source file. The preprocessor outputs one `make' rule + containing the object file name for that source file, a colon, + and the names of all the included files. If there are many + included files then the rule is split into several lines using + `\'-newline. + + This feature is used in automatic updating of makefiles. + +`-MM' + Like `-M' but mention only the files included with `#include + "FILE"'. System header files included with `#include ' + are omitted. + +`-i FILE' + Process FILE as input, discarding the resulting output, before + processing the regular input file. Because the output generated + from FILE is discarded, the only effect of `-i FILE' is to make + the macros defined in FILE available for use in the main input. + + + +File: cpp.info, Node: Concept Index, Next: Index, Prev: Invocation, Up: Top + +Concept Index +************* + +* Menu: + +* cascaded macros: Cascaded Macros. +* commands: Commands. +* concatenation: Concatenation. +* conditionals: Conditionals. +* header file: Header Files. +* line control: Combining Sources. +* macro body uses macro: Cascaded Macros. +* null command: Other Commands. +* options: Invocation. +* output format: Output. +* predefined macros: Predefined. +* preprocessor commands: Commands. +* redefining macros: Redefining. +* repeated inclusion: Once-Only. +* self-reference: Self-Reference. +* semicolons (after macro calls): Swallow Semicolon. +* side effects (in macro arguments): Side Effects. +* stringification: Stringification. +* undefining macros: Undefining. +* unsafe macros: Side Effects. + + + + +File: cpp.info, Node: Index, Prev: Concept Index, Up: Top + +Index of Commands, Macros and Options +************************************* + +* Menu: + +* #elif: #elif Command. +* #else: #else Command. +* #error: #error Command. +* #ident: Other Commands. +* #if: Conditional Syntax. +* #ifdef: Conditionals-Macros. +* #ifndef: Conditionals-Macros. +* #include: Include Syntax. +* #line: Combining Sources. +* #pragma: Other Commands. +* -C: Invocation. +* -D: Invocation. +* -I: Invocation. +* -M: Invocation. +* -MM: Invocation. +* -P: Invocation. +* -U: Invocation. +* -d: Invocation. +* -i: Invocation. +* -pedantic: Invocation. +* -trigraphs: Invocation. +* -undef: Invocation. +* BSD: Nonstandard Predefined. +* M68020: Nonstandard Predefined. +* __BASE_FILE__: Standard Predefined. +* __DATE__: Standard Predefined. +* __FILE__: Standard Predefined. +* __LINE__: Standard Predefined. +* __STDC__: Standard Predefined. +* __TIME__: Standard Predefined. +* defined: Conditionals-Macros. +* m68k: Nonstandard Predefined. +* mc68000: Nonstandard Predefined. +* ns32000: Nonstandard Predefined. +* pyr: Nonstandard Predefined. +* sequent: Nonstandard Predefined. +* sun: Nonstandard Predefined. +* system header files: Header Uses. +* unix: Nonstandard Predefined. +* vax: Nonstandard Predefined. + + + diff --git a/gcc-1.40/cpp.texinfo b/gcc-1.40/cpp.texinfo new file mode 100644 index 0000000..6a7ad41 --- /dev/null +++ b/gcc-1.40/cpp.texinfo @@ -0,0 +1,2194 @@ +\input texinfo +@setfilename cpp.info +@settitle The C Preprocessor +@setchapternewpage odd +@ifinfo +This file documents the GNU C Preprocessor. + +Copyright (C) 1987, 1989 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 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. +@end ifinfo + +@titlepage +@sp 6 +@center @titlefont{The C Preprocessor} +@sp 4 +@center Last revised July 1990 +@center for GCC version 1.38 +@sp 5 +@center Richard M. Stallman +@page +@vskip 0pt plus 1filll +Copyright @copyright{} 1987, 1989 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. + +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided also 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. +@end titlepage +@page + +@node Top, Global Actions,, (DIR) +@chapter The C Preprocessor + +The C preprocessor is a @dfn{macro processor} that is used automatically by +the C compiler to transform your program before actual compilation. It is +called a macro processor because it allows you to define @dfn{macros}, +which are brief abbreviations for longer constructs. + +The C preprocessor provides four separate facilities that you can use as +you see fit: + +@itemize @bullet +@item +Inclusion of header files. These are files of declarations that can be +substituted into your program. + +@item +Macro expansion. You can define @dfn{macros}, which are abbreviations +for arbitrary fragments of C code, and then the C preprocessor will +replace the macros with their definitions throughout the program. + +@item +Conditional compilation. Using special preprocessor commands, you +can include or exclude parts of the program according to various +conditions. + +@item +Line control. If you use a program to combine or rearrange source files into +an intermediate file which is then compiled, you can use line control +to inform the compiler of where each source line originally came from. +@end itemize + +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. + +ANSI Standard C requires the rejection of many harmless constructs commonly +used by today's C programs. Such incompatibility would be inconvenient for +users, so the GNU C preprocessor is configured to accept these constructs +by default. Strictly speaking, to get ANSI Standard C, you must use the +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}. + +@menu +* Global Actions:: Actions made uniformly on all input files. +* Commands:: General syntax of preprocessor commands. +* Header Files:: How and why to use header files. +* Macros:: How and why to use macros. +* Conditionals:: How and why to use conditionals. +* Combining Sources:: Use of line control when you combine source files. +* Other Commands:: Miscellaneous preprocessor commands. +* Output:: Format of output from the C preprocessor. +* Invocation:: How to invoke the preprocessor; command options. +* Concept Index:: Index of concepts and terms. +* Index:: Index of commands, predefined macros and options. +@end menu + +@node Global Actions, Commands, Top, Top +@section Transformations Made Globally + +Most C preprocessor features are inactive unless you give specific commands +to request their use. (Preprocessor commands are lines starting with +@samp{#}; @pxref{Commands}). But there are three transformations that the +preprocessor always makes on all the input it receives, even in the absence +of commands. + +@itemize @bullet +@item +All C comments are replaced with single spaces. + +@item +Backslash-Newline sequences are deleted, no matter where. This +feature allows you to break long lines for cosmetic purposes without +changing their meaning. + +@item +Predefined macro names are replaced with their expansions +(@pxref{Predefined}). +@end itemize + +The first two transformations are done @emph{before} nearly all other parsing +and before preprocessor commands are recognized. Thus, for example, you +can split a line cosmetically with Backslash-Newline anywhere (except +when trigraphs are in use; see below). + +@example +/* +*/ # /* +*/ defi\ +ne FO\ +O 10\ +20 +@end example + +@noindent +is equivalent into @samp{#define FOO 1020}. You can split even an escape +sequence with Backslash-Newline. For example, you can split @code{"foo\bar"} +between the @samp{\} and the @samp{b} to get + +@example +"foo\\ +bar" +@end example + +@noindent +This behavior is unclean: in all other contexts, a Backslash can be +inserted in a string constant as an ordinary character by writing a double +Backslash, and this creates an exception. But the ANSI C standard requires +it. (Strict ANSI C does not allow Newlines in string constants, so they +do not consider this a problem.) + +But there are a few exceptions to all three transformations. + +@itemize @bullet +@item +C comments and predefined macro names are not recognized inside a +@samp{#include} command in which the file name is delimited with +@samp{<} and @samp{>}. + +@item +C comments and predefined macro names are never recognized within a +character or string constant. (Strictly speaking, this is the rule, +not an exception, but it is worth noting here anyway.) + +@item +Backslash-Newline may not safely be used within an ANSI ``trigraph''. +Trigraphs are converted before Backslash-Newline is deleted. If you +write what looks like a trigraph with a Backslash-Newline inside, the +Backslash-Newline is deleted as usual, but it is then too late to +recognize the trigraph. + +This exception is relevant only if you use the @samp{-trigraphs} +option to enable trigraph processing. @xref{Invocation}. +@end itemize + +@node Commands, Header Files, Global Actions, Top +@section Preprocessor Commands + +@cindex preprocessor commands +@cindex commands +Most preprocessor features are active only if you use preprocessor commands +to request their use. + +Preprocessor commands are lines in your program that start with @samp{#}. +The @samp{#} is followed by an identifier that is the @dfn{command name}. +For example, @samp{#define} is the command that defines a macro. +Whitespace is also allowed before and after the @samp{#}. + +The set of valid command names is fixed. Programs cannot define new +preprocessor commands. + +Some command names require arguments; these make up the rest of the command +line and must be separated from the command name by whitespace. For example, +@samp{#define} must be followed by a macro name and the intended expansion +of the macro. + +A preprocessor command cannot be more than one line in normal circumstances. +It may be split cosmetically with Backslash-Newline, but that has no effect +on its meaning. Comments containing Newlines can also divide the command into +multiple lines, but the comments are changed to Spaces before the command +is interpreted. The only way a significant Newline can occur in a preprocessor +command is within a string constant or character constant. Note that +most C compilers that might be applied to the output from the preprocessor +do not accept string or character constants containing Newlines. + +The @samp{#} and the command name cannot come from a macro expansion. For +example, if @samp{foo} is defined as a macro expanding to @samp{define}, +that does not make @samp{#foo} a valid preprocessor command. + +@node Header Files, Macros, Commands, Top +@section Header Files + +@cindex header file +A header file is a file containing C declarations and macro definitions +(@pxref{Macros}) to be shared between several source files. You request +the use of a header file in your program with the C preprocessor command +@samp{#include}. + +@menu +* Header Uses:: What header files are used for. +* Include Syntax:: How to write @samp{#include} commands. +* Include Operation:: What @samp{#include} does. +* Once-Only:: Preventing multiple inclusion of one header file. +@end menu + +@node Header Uses, Include Syntax, Header Files, Header Files +@subsection Uses of Header Files + +Header files serve two kinds of purposes. + +@itemize @bullet +@item +@findex system header files +System header files declare the interfaces to parts of the operating +system. You include them in your program to supply the definitions +you need to invoke system calls and libraries. + +@item +Your own header files contain declarations for interfaces between the +source files of your program. Each time you have a group of related +declarations and macro definitions all or most of which are needed in +several different source files, it is a good idea to create a header +file for them. +@end itemize + +Including a header file produces the same results in C compilation as +copying the header file into each source file that needs it. But such +copying would be time-consuming and error-prone. With a header file, the +related declarations appear in only one place. If they need to be changed, +they can be changed in one place, and programs that include the header file +will automatically use the new version when next recompiled. The header +file eliminates the labor of finding and changing all the copies as well as +the risk that a failure to find one copy will result in inconsistencies +within a program. + +The usual convention is to give header files names that end with @file{.h}. + +@node Include Syntax, Include Operation, Header Uses, Header Files +@subsection The @samp{#include} Command + +@findex #include +Both user and system header files are included using the preprocessor +command @samp{#include}. It has three variants: + +@table @code +@item #include <@var{file}> +This variant is used for system header files. It searches for a file +named @var{file} in a list of directories specified by you, then in a +standard list of system directories. You specify directories to +search for header files with the command option @samp{-I} +(@pxref{Invocation}). The option @samp{-nostdinc} inhibits searching +the standard system directories; in this case only the directories +you specify are searched. + +The parsing of this form of @samp{#include} is slightly special +because comments are not recognized within the @samp{<@dots{}>}. +Thus, in @samp{#include } the @samp{/*} does not start a comment +and the command specifies inclusion of a system header file named +@file{x/*y}. Of course, a header file with such a name is unlikely to +exist on Unix, where shell wildcard features would make it hard to +manipulate.@refill + +The argument @var{file} may not contain a @samp{>} character. It may, +however, contain a @samp{<} character. + +@item #include "@var{file}" +This variant is used for header files of your own program. It +searches for a file named @var{file} first in the current directory, +then in the same directories used for system header files. The +current directory is the directory of the current input file. It is +tried first because it is presumed to be the location of the files +that the current input file refers to. (If the @samp{-I-} option is +used, the special treatment of the current directory is inhibited.) + +The argument @var{file} may not contain @samp{"} characters. If +backslashes occur within @var{file}, they are considered ordinary text +characters, not escape characters. None of the character escape +sequences appropriate to string constants in C are processed. Thus, +@samp{#include "x\n\\y"} specifies a filename containing three +backslashes. It is not clear why this behavior is ever useful, but +the ANSI standard specifies it. + +@item #include @var{anything else} +This variant is called a @dfn{computed #include}. Any @samp{#include} +command whose argument does not fit the above two forms is a computed +include. The text @var{anything else} is checked for macro calls, +which are expanded (@pxref{Macros}). When this is done, the result +must fit one of the above two variants. + +This feature allows you to define a macro which controls the file name +to be used at a later point in the program. One application of this +is to allow a site-configuration file for your program to specify the +names of the system include files to be used. This can help in +porting the program to various operating systems in which the +necessary system header files are found in different places. +@end table + +@node Include Operation, Once-Only, Include Syntax, Header Files +@subsection How @samp{#include} Works + +The @samp{#include} command works by directing the C preprocessor to scan +the specified file as input before continuing with the rest of the current +file. The output from the preprocessor contains the output already +generated, followed by the output resulting from the included file, +followed by the output that comes from the text after the @samp{#include} +command. For example, given two files as follows: + +@example +/* File program.c */ +int x; +#include "header.h" + +main () +@{ + printf (test ()); +@} + + +/* File header.h */ +char *test (); +@end example + +@noindent +the output generated by the C preprocessor for @file{program.c} as input +would be + +@example +int x; +char *test (); + +main () +@{ + printf (test ()); +@} +@end example + +Included files are not limited to declarations and macro definitions; they +are merely the typical use. Any fragment of a C program can be included +from another file. The include file could even contain the beginning of a +statement that is concluded in the containing file, or the end of a +statement that was started in the including file. However, a comment or a +string or character constant may not start in the included file and finish +in the including file. An unterminated comment, string constant or +character constant in an included file is considered to end (with an error +message) at the end of the file. + +The line following the @samp{#include} command is always treated as a +separate line by the C preprocessor even if the included file lacks a final +newline. + +@node Once-Only,, Include Operation, Header Files +@subsection Once-Only Include Files +@cindex repeated inclusion + +Very often, one header file includes another. It can easily result that a +certain header file is included more than once. This may lead to errors, +if the header file defines structure types or typedefs, and is certainly +wasteful. Therefore, we often wish to prevent multiple inclusion of a +header file. + +The standard way to do this is to enclose the entire real contents of the +file in a conditional, like this: + +@example +#ifndef __FILE_FOO_SEEN__ +#define __FILE_FOO_SEEN__ + +@var{the entire file} + +#endif /* __FILE_FOO_SEEN__ */ +@end example + +The macro @code{__FILE_FOO_SEEN__} indicates that the file has been +included once already; its name should begin with @samp{__}, and should +contain the name of the file to avoid accidental conflicts. + +One drawback of this method is that the preprocessor must scan the input +file completely in order to determine that all of it is to be ignored. +This makes compilation slower. You can avoid the delay by inserting the +following command near the beginning of file @emph{in addition to the +conditionals described above}: + +@example +#pragma once +@end example + +This command tells the GNU C preprocessor to ignore any future commands +to include the same file (whichever file the @samp{#pragma} appears in). + +You should not @emph{rely} on @samp{#pragma once} to prevent multiple +inclusion of the file. It is just a hint, and a nonstandard one at +that. Most C compilers will ignore it entirely. For this reason, you +still need the conditionals if you want to make certain that the file's +contents are not included twice. + +Note that @samp{#pragma once} works by file name; if a file has more +than one name, it can be included once under each name, even in GNU CC, +despite @samp{#pragma once}. + +@node Macros, Conditionals, Header Files, Top +@section Macros + +A macro is a sort of abbreviation which you can define once and then +use later. There are many complicated features associated with macros +in the C preprocessor. + +@menu +* Simple Macros:: Macros that always expand the same way. +* Argument Macros:: Macros that accept arguments that are substituted + into the macro expansion. +* Predefined:: Predefined macros that are always available. +* Stringification:: Macro arguments converted into string constants. +* Concatenation:: Building tokens from parts taken from macro arguments. +* Undefining:: Cancelling a macro's definition. +* Redefining:: Changing a macro's definition. +* Macro Pitfalls:: Macros can confuse the unwary. Here we explain + several common problems and strange features. +@end menu + +@node Simple Macros, Argument Macros, Macros, Macros +@subsection Simple Macros + +A @dfn{simple macro} is a kind of abbreviation. It is a name which stands +for a fragment of code. + +Before you can use a macro, you must @dfn{define} it explicitly with the +@samp{#define} command. @samp{#define} is followed by the name of the +macro and then the code it should be an abbreviation for. For example, + +@example +#define BUFFER_SIZE 1020 +@end example + +@noindent +defines a macro named @samp{BUFFER_SIZE} as an abbreviation for the text +@samp{1020}. Therefore, if somewhere after this @samp{#define} command +there comes a C statement of the form + +@example +foo = (char *) xmalloc (BUFFER_SIZE); +@end example + +@noindent +then the C preprocessor will recognize and @dfn{expand} the macro +@samp{BUFFER_SIZE}, resulting in + +@example +foo = (char *) xmalloc (1020); +@end example + +@noindent +the definition must be a single line; however, it may not end in the +middle of a multi-line string constant or character constant. + +The use of all upper case for macro names is a standard convention. +Programs are easier to read when it is possible to tell at a glance which +names are macros. + +Normally, a macro definition must be a single line, like all C preprocessor +commands. (You can split a long macro definition cosmetically with +Backslash-Newline.) There is one exception: Newlines can be included in +the macro definition if within a string or character constant. By the same +token, it is not possible for a macro definition to contain an unbalanced +quote character; the definition automatically extends to include the +matching quote character that ends the string or character constant. +Comments within a macro definition may contain Newlines, which make no +difference since the comments are entirely replaced with Spaces regardless +of their contents. + +Aside from the above, there is no restriction on what can go in a macro +body. Parentheses need not balance. The body need not resemble valid C +code. (Of course, you might get error messages from the C compiler when +you use the macro.) + +The C preprocessor scans your program sequentially, so macro definitions +take effect at the place you write them. Therefore, the following input to +the C preprocessor + +@example +foo = X; +#define X 4 +bar = X; +@end example + +@noindent +produces as output + +@example +foo = X; + +bar = 4; +@end example + +After the preprocessor expands a macro name, the macro's definition body is +appended to the front of the remaining input, and the check for macro calls +continues. Therefore, the macro body can contain calls to other macros. +For example, after + +@example +#define BUFSIZE 1020 +#define TABLESIZE BUFSIZE +@end example + +@noindent +the name @samp{TABLESIZE} when used in the program would go through two +stages of expansion, resulting ultimately in @samp{1020}. + +This is not at all the same as defining @samp{TABLESIZE} to be @samp{1020}. +The @samp{#define} for @samp{TABLESIZE} uses exactly the body you +specify---in this case, @samp{BUFSIZE}---and does not check to see whether +it too is the name of a macro. It's only when you @emph{use} @samp{TABLESIZE} +that the result of its expansion is checked for more macro names. +@xref{Cascaded Macros}. + +@node Argument Macros, Predefined, Simple Macros, Macros +@subsection Macros with Arguments + +A simple macro always stands for exactly the same text, each time it is +used. Macros can be more flexible when they accept @dfn{arguments}. +Arguments are fragments of code that you supply each time the macro is +used. These fragments are included in the expansion of the macro according +to the directions in the macro definition. + +To define a macro that uses arguments, you write a @samp{#define} command +with a list of @dfn{argument names} in parentheses after the name of the +macro. The argument names may be any valid C identifiers, separated by +commas and optionally whitespace. The open-parenthesis must follow the +macro name immediately, with no space in between. + +For example, here is a macro that computes the minimum of two numeric +values, as it is defined in many C programs: + +@example +#define min(X, Y) ((X) < (Y) ? (X) : (Y)) +@end example + +@noindent +(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 +followed by a list of @dfn{actual arguments} in parentheses. separated by +commas. The number of actual arguments you give must match the number of +arguments the macro expects. Examples of use of the macro @samp{min} +include @samp{min (1, 2)} and @samp{min (x + 28, *p)}. + +The expansion text of the macro depends on the arguments you use. +Each of the argument names of the macro is replaced, throughout the +macro definition, with the corresponding actual argument. Using the +same macro @samp{min} defined above, @samp{min (1, 2)} expands into + +@example +((1) < (2) ? (1) : (2)) +@end example + +@noindent +where @samp{1} has been substituted for @samp{X} and @samp{2} for @samp{Y}. + +Likewise, @samp{min (x + 28, *p)} expands into + +@example +((x + 28) < (*p) ? (x + 28) : (*p)) +@end example + +Parentheses in the actual arguments must balance; a comma within +parentheses does not end an argument. However, there is no requirement for +brackets or braces to balance; thus, if you want to supply @samp{array[x = +y, x + 1]} as an argument, you must write it as @samp{array[(x = y, x + +1)]}, which is equivalent C code. + +After the actual arguments are substituted into the macro body, the entire +result is appended to the front of the remaining input, and the check for +macro calls continues. Therefore, the actual arguments can contain calls +to other macros, either with or without arguments, or even to the same +macro. The macro body can also contain calls to other macros. For +example, @samp{min (min (a, b), c)} expands into + +@example +((((a) < (b) ? (a) : (b))) < (c) + ? (((a) < (b) ? (a) : (b))) + : (c)) +@end example + +@noindent +(Line breaks shown here for clarity would not actually be generated.) + +If you use the macro name followed by something other than an +open-parenthesis (after ignoring any spaces, tabs and comments that +follow), it is not a call to the macro, and the preprocessor leaves the +name unaltered. Therefore, it is possible for the same name to be a +variable or function in your program as well as a macro, and you can +choose in each instance whether to refer to the macro (if an actual +argument list follows) or the variable or function (if an argument list +does not follow). + +Such dual use of one name could be confusing and should be avoided +except when the two meanings are effectively synonymous: that is, when the +name is both a macro and a function and the two have similar effects. You +can think of the name simply as a function; use of the name for purposes +other than calling it (such as, to take the address) will refer to the +function, while calls will expand the macro and generate better but +equivalent code. For example, you can use a function named @samp{min} in +the same source file that defines the macro. If you write @samp{&min} with +no argument list, you refer to the function. If you write @samp{min (x, +bb)}, with an argument list, the macro is expanded. If you write +@samp{(min) (a, bb)}, where the name @samp{min} is not followed by an +open-parenthesis, the macro is not expanded, so you wind up with a call to +the function @samp{min}. + +It is not allowed to define the same name as both a simple macro and +a macro with arguments. + +In the definition of a macro with arguments, the list of argument names +must follow the macro name immediately with no space in between. If there +is a space after the macro name, the macro is defined as taking no +arguments, and all the rest of the name is taken to be the expansion. The +reason for this is that it is often useful to define a macro that takes no +arguments and whose definition begins with an identifier in parentheses. +This rule about spaces makes it possible for you to do either this: + +@example +#define FOO(x) - 1 / (x) +@end example + +@noindent +(which defines @samp{FOO} to take an argument and expand into minus the +reciprocal of that argument) or this: + +@example +#define BAR (x) - 1 / (x) +@end example + +@noindent +(which defines @samp{BAR} to take no argument and always expand into +@samp{(x) - 1 / (x)}). + +Note that the @emph{uses} of a macro with arguments can have spaces before +the left parenthesis; it's the @emph{definition} where it matters whether +there is a space. + +@node Predefined, Stringification, Argument Macros, Macros +@subsection Predefined Macros + +@cindex predefined macros +Several simple macros are predefined. You can use them without giving +definitions for them. They fall into two classes: standard macros and +system-specific macros. + +@menu +* Standard Predefined:: Standard predefined macros. +* Nonstandard Predefined:: Nonstandard predefined macros. +@end menu + +@node Standard Predefined, Nonstandard Predefined, Predefined, Predefined +@subsubsection 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. +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. + +@table @code +@item __FILE__ +@findex __FILE__ +This macro expands to the name of the current input file, in the form +of a C string constant. + +@item __BASE_FILE__ +@findex __BASE_FILE__ +This macro expands to the name of the main input file, in the form +of a C string constant. This is the source file that was specified +as an argument when the C compiler was invoked. + +@item __LINE__ +@findex __LINE__ +This macro expands to the current input line number, in the form of a +decimal integer constant. While we call it a predefined macro, it's +a pretty strange macro, since its ``definition'' changes with each +new line of source code. + +This and @samp{__FILE__} are useful in generating an error message to +report an inconsistency detected by the program; the message can state +the source line at which the inconsistency was detected. For example, + +@example +fprintf (stderr, "Internal error: negative string length " + "%d at %s, line %d.", + length, __FILE__, __LINE__); +@end example + +A @samp{#include} command changes the expansions of @samp{__FILE__} +and @samp{__LINE__} to correspond to the included file. At the end of +that file, when processing resumes on the input file that contained +the @samp{#include} command, the expansions of @samp{__FILE__} and +@samp{__LINE__} revert to the values they had before the +@samp{#include} (but @samp{__LINE__} is then incremented by one as +processing moves to the line after the @samp{#include}). + +The expansions of both @samp{__FILE__} and @samp{__LINE__} are altered +if a @samp{#line} command is used. @xref{Combining Sources}. + +@item __DATE__ +@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"}}. + +@item __TIME__ +@findex __TIME__ +This macro expands to a string constant that describes the time at +which the preprocessor is being run. The string constant contains +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 +will operate on the output from the preprocessor.) + +@item __GNUC__ +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. + +@item __STRICT_ANSI__ +This macro is defined 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. + +@item __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{"1.18"}. The only reasonable use of this +macro is to incorporate it into a string constant. + +@item __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. + +@item __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}. +@end table + +@node Nonstandard Predefined,, Standard Predefined, Predefined +@subsubsection Nonstandard Predefined Macros + +The C preprocessor normally has several predefined macros that vary between +machines because their purpose is to indicate what type of system and +machine is in use. This manual, being for all systems and machines, cannot +tell you exactly what their names are; instead, we offer a list of some +typical ones. + +Some nonstandard predefined macros describe the operating system in use, +with more or less specificity. For example, + +@table @code +@item unix +@findex unix +@samp{unix} is normally predefined on all Unix systems. + +@item BSD +@findex BSD +@samp{BSD} is predefined on recent versions of Berkeley Unix +(perhaps only in version 4.3). +@end table + +Other nonstandard predefined macros describe the kind of CPU, with more or +less specificity. For example, + +@table @code +@item vax +@findex vax +@samp{vax} is predefined on Vax computers. + +@item mc68000 +@findex mc68000 +@samp{mc68000} is predefined on most computers whose CPU is a Motorola +68000, 68010 or 68020. + +@item m68k +@findex m68k +@samp{m68k} is also predefined on most computers whose CPU is a 68000, +68010 or 68020; however, some makers use @samp{mc68000} and some use +@samp{m68k}. Some predefine both names. What happens in GNU C +depends on the system you are using it on. + +@item M68020 +@findex M68020 +@samp{M68020} has been observed to be predefined on some systems that +use 68020 CPUs---in addition to @samp{mc68000} and @samp{m68k} that +are less specific. + +@item ns32000 +@findex ns32000 +@samp{ns32000} is predefined on computers which use the National +Semiconductor 32000 series CPU. +@end table + +Yet other nonstandard predefined macros describe the manufacturer of +the system. For example, + +@table @code +@item sun +@findex sun +@samp{sun} is predefined on all models of Sun computers. + +@item pyr +@findex pyr +@samp{pyr} is predefined on all models of Pyramid computers. + +@item sequent +@findex sequent +@samp{sequent} is predefined on all models of Sequent computers. +@end table + +These predefined symbols are not only nonstandard, they are contrary to the +ANSI standard because their names do not start with underscores. +Therefore, the option @samp{-ansi} inhibits the definition of these +symbols. + +This tends to make @samp{-ansi} useless, since many programs depend on the +customary nonstandard predefined symbols. Even system header files check +them and will generate incorrect declarations if they do not find the names +that are expected. You might think that the header files supplied for the +Uglix computer would not need to test what machine they are running on, +because they can simply assume it is the Uglix; but often they do, and they +do so using the customary names. As a result, very few C programs will +compile with @samp{-ansi}. We intend to avoid such problems on the GNU +system. + +What, then, should you do in an ANSI C program to test the type of machine +it is to run on? + +GNU C offers a parallel series of symbols for this purpose, whose names +are made from the customary ones by adding @samp{__} at the beginning +and end. Thus, the symbol @code{__vax__} would be available on a vax, +and so on. + +The set of nonstandard predefined names in the GNU C preprocessor is +controlled by the macro @samp{CPP_PREDEFINES}, which should be a string +containing @samp{-D} options, separated by spaces. For example, on the +Sun 3, we use the following definition: + +@example +#define CPP_PREDEFINES "-Dmc68000 -Dsun -Dunix -Dm68k" +@end example + +@node Stringification, Concatenation, Predefined, Macros +@subsection Stringification + +@cindex stringification +@dfn{Stringification} means turning a code fragment into a string constant +whose contents are the text for the code fragment. For example, +stringifying @samp{foo (z)} results in @samp{"foo (z)"}. + +In the C preprocessor, stringification is an option available when macro +arguments are substituted into the macro definition. In the body of the +definition, when an argument name appears, the character @samp{#} before +the name specifies stringification of the corresponding actual argument +when it is substituted at that point in the definition. The same argument +may be substituted in other places in the definition without +stringification if the argument name appears in those places with no +@samp{#}. + +Here is an example of a macro definition that uses stringification: + +@example +#define WARN_IF(EXP) \ +do @{ if (EXP) fprintf (stderr, "Warning: " #EXP "\n"); @} while (0) +@end example + +@noindent +Here the actual argument for @samp{EXP} is substituted once as given, +into the @samp{if} statement, and once as stringified, into the +argument to @samp{fprintf}. The @samp{do} and @samp{while (0)} are +a kludge to make it possible to write @samp{WARN_IF (@var{arg});}, +which the resemblance of @samp{WARN_IF} to a function would make +C programmers want to do; @pxref{Swallow Semicolon}). + +The stringification feature is limited to transforming one macro argument +into one string constant: there is no way to combine the argument with +other text and then stringify it all together. But the example above shows +how an equivalent result can be obtained in ANSI Standard C using the +feature that adjacent string constants are concatenated as one string +constant. The preprocessor stringifies @samp{EXP}'s actual argument +into a separate string constant, resulting in text like + +@example +do @{ if (x == 0) fprintf (stderr, "Warning: " "x == 0" "\n"); @} while (0) +@end example + +@noindent +but the C compiler then sees three consecutive string constants and +concatenates them into one, producing effectively + +@example +do @{ if (x == 0) fprintf (stderr, "Warning: x == 0\n"); @} while (0) +@end example + +Stringification in C involves more than putting doublequote characters +around the fragment; it is necessary to put backslashes in front of all +doublequote characters, and all backslashes in string and character +constants, in order to get a valid C string constant with the proper +contents. Thus, stringifying @samp{p = "foo\n";} results in @samp{"p = +\"foo\\n\";"}. However, backslashes that are not inside of string or +character constants are not duplicated: @samp{\n} by itself stringifies to +@samp{"\n"}. + +Whitespace (including comments) in the text being stringified is handled +according to precise rules. All leading and trailing whitespace is ignored. +Any sequence of whitespace in the middle of the text is converted to +a single space in the stringified result. + +@node Concatenation, Undefining, Stringification, Macros +@subsection Concatenation + +@cindex concatenation +@dfn{Concatenation} means joining two strings into one. In the context +of macro expansion, concatenation refers to joining two lexical units +into one longer one. Specifically, an actual argument to the macro can be +concatenated with another actual argument or with fixed text to produce +a longer name. The longer name might be the name of a function, +variable or type, or a C keyword; it might even be the name of another +macro, in which case it will be expanded. + +When you define a macro, you request concatenation with the special +operator @samp{##} in the macro body. When the macro is called, +after actual arguments are substituted, all @samp{##} operators are +deleted, and so is any whitespace next to them (including whitespace +that was part of an actual argument). The result is to concatenate +the syntactic tokens on either side of the @samp{##}. + +Consider a C program that interprets named commands. There probably needs +to be a table of commands, perhaps an array of structures declared as +follows: + +@example +struct command +@{ + char *name; + void (*function) (); +@}; + +struct command commands[] = +@{ + @{ "quit", quit_command@}, + @{ "help", help_command@}, + @dots{} +@}; +@end example + +It would be cleaner not to have to give each command name twice, once in +the string constant and once in the function name. A macro which takes the +name of a command as an argument can make this unnecessary. The string +constant can be created with stringification, and the function name by +concatenating the argument with @samp{_command}. Here is how it is done: + +@example +#define COMMAND(NAME) @{ #NAME, NAME ## _command @} + +struct command commands[] = +@{ + COMMAND (quit), + COMMAND (help), + @dots{} +@}; +@end example + +The usual case of concatenation is concatenating two names (or a name and a +number) into a longer name. But this isn't the only valid case. It is +also possible to concatenate two numbers (or a number and a name, such as +@samp{1.5} and @samp{e3}) into a number. Also, multi-character operators +such as @samp{+=} can be formed by concatenation. In some cases it is even +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 +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. + +Keep in mind that the C preprocessor converts comments to whitespace before +macros are even considered. Therefore, you cannot create a comment by +concatenating @samp{/} and @samp{*}: the @samp{/*} sequence that starts a +comment is not a lexical unit, but rather the beginning of a ``long'' space +character. Also, you can freely use comments next to a @samp{##} in a +macro definition, or in actual arguments that will be concatenated, because +the comments will be converted to spaces at first sight, and concatenation +will later discard the spaces. + +@node Undefining, Redefining, Concatenation, Macros +@subsection Undefining Macros + +@cindex undefining macros +To @dfn{undefine} a macro means to cancel its definition. This is done +with the @samp{#undef} command. @samp{#undef} is followed by the macro +name to be undefined. + +Like definition, undefinition occurs at a specific point in the source +file, and it applies starting from that point. The name ceases to be a +macro name, and from that point on it is treated by the preprocessor as if +it had never been a macro name. + +For example, + +@example +#define FOO 4 +x = FOO; +#undef FOO +x = FOO; +@end example + +@noindent +expands into + +@example +x = 4; + +x = FOO; +@end example + +@noindent +In this example, @samp{FOO} had better be a variable or function as well +as (temporarily) a macro, in order for the result of the expansion to be +valid C code. + +The same form of @samp{#undef} command will cancel definitions with +arguments or definitions that don't expect arguments. The @samp{#undef} +command has no effect when used on a name not currently defined as a macro. + +@node Redefining, Macro Pitfalls, Undefining, Macros +@subsection Redefining Macros + +@cindex redefining macros +@dfn{Redefining} a macro means defining (with @samp{#define}) a name that +is already defined as a macro. + +A redefinition is trivial if the new definition is transparently identical +to the old one. You probably wouldn't deliberately write a trivial +redefinition, but they can happen automatically when a header file is +included more than once (@pxref{Header Files}), so they are accepted +silently and without effect. + +Nontrivial redefinition is considered likely to be an error, so +it provokes a warning message from the preprocessor. However, sometimes it +is useful to change the definition of a macro in mid-compilation. You can +inhibit the warning by undefining the macro with @samp{#undef} before the +second definition. + +In order for a redefinition to be trivial, the new definition must +exactly match the one already in effect, with two possible exceptions: + +@itemize @bullet +@item +Whitespace may be added or deleted at the beginning or the end. + +@item +Whitespace may be changed in the middle (but not inside strings). +However, it may not be eliminated entirely, and it may not be added +where there was no whitespace at all. +@end itemize + +Recall that a comment counts as whitespace. + +@node Macro Pitfalls,, Redefining, Macros +@subsection Pitfalls and Subtleties of Macros + +In this section we describe some special rules that apply to macros and +macro expansion, and point out certain cases in which the rules have +counterintuitive consequences that you must watch out for. + +@menu +* Misnesting:: Macros can contain unmatched parentheses. +* Macro Parentheses:: Why apparently superfluous parentheses + may be necessary to avoid incorrect grouping. +* Swallow Semicolon:: Macros that look like functions + but expand into compound statements. +* Side Effects:: Unsafe macros that cause trouble when + arguments contain side effects. +* Self-Reference:: Macros whose definitions use the macros' own names. +* Argument Prescan:: Actual arguments are checked for macro calls + before they are substituted. +* Cascaded Macros:: Macros whose definitions use other macros. +@end menu + +@node Misnesting, Macro Parentheses, Macro Pitfalls, Macro Pitfalls +@subsubsection Improperly Nested Constructs + +Recall that when a macro is called with arguments, the arguments are +substituted into the macro body and the result is checked, together with +the rest of the input file, for more macro calls. + +It is possible to piece together a macro call coming partially from the +macro body and partially from the actual arguments. For example, + +@example +#define double(x) (2*(x)) +#define call_with_1(x) x(1) +@end example + +@noindent +would expand @samp{call_with_1 (double)} into @samp{(2*(1))}. + +Macro definitions do not have to have balanced parentheses. By writing an +unbalanced open parenthesis in a macro body, it is possible to create a +macro call that begins inside the macro body but ends outside of it. For +example, + +@example +#define strange(file) fprintf (file, "%s %d", +@dots{} +strange(stderr) p, 35) +@end example + +@noindent +This bizarre example expands to @samp{fprintf (stderr, "%s %d", p, 35)}! + +@node Macro Parentheses, Swallow Semicolon, Misnesting, Macro Pitfalls +@subsubsection Unintended Grouping of Arithmetic + +You may have noticed that in most of the macro definition examples shown +above, each occurrence of a macro argument name had parentheses around it. +In addition, another pair of parentheses usually surround the entire macro +definition. Here is why it is best to write macros that way. + +Suppose you define a macro as follows, + +@example +#define ceil_div(x, y) (x + y - 1) / y +@end example + +@noindent +whose purpose is to divide, rounding up. (One use for this +operation is to compute how many @samp{int}'s are needed to hold +a certain number of @samp{char}'s.) Then suppose it is used as follows: + +@example +a = ceil_div (b & c, sizeof (int)); +@end example + +@noindent +This expands into + +@example +a = (b & c + sizeof (int) - 1) / sizeof (int); +@end example + +@noindent +which does not do what is intended. The operator-precedence rules of +C make it equivalent to this: + +@example +a = (b & (c + sizeof (int) - 1)) / sizeof (int); +@end example + +@noindent +But what we want is this: + +@example +a = ((b & c) + sizeof (int) - 1)) / sizeof (int); +@end example + +@noindent +Defining the macro as + +@example +#define ceil_div(x, y) ((x) + (y) - 1) / (y) +@end example + +@noindent +provides the desired result. + +However, 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: + +@example +sizeof ((1) + (2) - 1) / (2) +@end example + +@noindent +This would take the size of an integer and divide it by two. The precedence +rules have put the division outside the @samp{sizeof} when it was intended +to be inside. + +Parentheses around the entire macro definition can prevent such problems. +Here, then, is the recommended way to define @samp{ceil_div}: + +@example +#define ceil_div(x, y) (((x) + (y) - 1) / (y)) +@end example + +@node Swallow Semicolon, Side Effects, Macro Parentheses, Macro Pitfalls +@subsubsection Swallowing the Semicolon + +@cindex semicolons (after macro calls) +Often it is desirable to define a macro that expands into a compound +statement. Consider, for example, the following macro, that advances a +pointer (the argument @samp{p} says where to find it) across whitespace +characters: + +@example +#define SKIP_SPACES (p, limit) \ +@{ register char *lim = (limit); \ + while (p != lim) @{ \ + if (*p++ != ' ') @{ \ + p--; break; @}@}@} +@end example + +@noindent +Here Backslash-Newline is used to split the macro definition, which must +be a single line, so that it resembles the way such C code would be +laid out if not part of a macro definition. + +A call to this macro might be @samp{SKIP_SPACES (p, lim)}. Strictly +speaking, the call expands to a compound statement, which is a complete +statement with no need for a semicolon to end it. But it looks like a +function call. So it minimizes confusion if you can use it like a function +call, writing a semicolon afterward, as in @samp{SKIP_SPACES (p, lim);} + +But this can cause trouble before @samp{else} statements, because the +semicolon is actually a null statement. Suppose you write + +@example +if (*p != 0) + SKIP_SPACES (p, lim); +else @dots{} +@end example + +@noindent +The presence of two statements---the compound statement and a null +statement---in between the @samp{if} condition and the @samp{else} +makes invalid C code. + +The definition of the macro @samp{SKIP_SPACES} can be altered to solve +this problem, using a @samp{do @dots{} while} statement. Here is how: + +@example +#define SKIP_SPACES (p, limit) \ +do @{ register char *lim = (limit); \ + while (p != lim) @{ \ + if (*p++ != ' ') @{ \ + p--; break; @}@}@} \ +while (0) +@end example + +Now @samp{SKIP_SPACES (p, lim);} expands into + +@example +do @{@dots{}@} while (0); +@end example + +@noindent +which is one statement. + +@node Side Effects, Self-Reference, Swallow Semicolon, Macro Pitfalls +@subsubsection Duplication of Side Effects + +@cindex side effects (in macro arguments) +@cindex unsafe macros +Many C programs define a macro @samp{min}, for ``minimum'', like this: + +@example +#define min(X, Y) ((X) < (Y) ? (X) : (Y)) +@end example + +When you use this macro with an argument containing a side effect, +as shown here, + +@example +next = min (x + y, foo (z)); +@end example + +@noindent +it expands as follows: + +@example +next = ((x + y) < (foo (z)) ? (x + y) : (foo (z))); +@end example + +@noindent +where @samp{x + y} has been substituted for @samp{X} and @samp{foo (z)} +for @samp{Y}. + +The function @samp{foo} is used only once in the statement as it appears +in the program, but the expression @samp{foo (z)} has been substituted +twice into the macro expansion. As a result, @samp{foo} might be called +two times when the statement is executed. If it has side effects or +if it takes a long time to compute, the results might not be what you +intended. We say that @samp{min} is an @dfn{unsafe} macro. + +The best solution to this problem is to define @samp{min} in a way that +computes the value of @samp{foo (z)} only once. The C language offers no +standard way to do this, but it can be done with GNU C extensions as +follows: + +@example +#define min(X, Y) \ +(@{ typeof (X) __x = (X), __y = (Y); \ + (__x < __y) ? __x : __y; @}) +@end example + +If you do not wish to use GNU C extensions, the only solution is to be +careful when @emph{using} the macro @samp{min}. For example, you can +calculate the value of @samp{foo (z)}, save it in a variable, and use that +variable in @samp{min}: + +@example +#define min(X, Y) ((X) < (Y) ? (X) : (Y)) +@dots{} +@{ + int tem = foo (z); + next = min (x + y, tem); +@} +@end example + +@noindent +(where I assume that @samp{foo} returns type @samp{int}). + +@node Self-Reference, Argument Prescan, Side Effects, Macro Pitfalls +@subsubsection Self-Referential Macros + +@cindex self-reference +A @dfn{self-referential} macro is one whose name appears in its definition. +A special feature of ANSI Standard C is that the self-reference is not +considered a macro call. It is passed into the preprocessor output +unchanged. + +Let's consider an example: + +@example +#define foo (4 + foo) +@end example + +@noindent +where @samp{foo} is also a variable in your program. + +Following the ordinary rules, each reference to @samp{foo} will expand into +@samp{(4 + foo)}; then this will be rescanned and will expand into @samp{(4 ++ (4 + foo))}; and so on until it causes a fatal error (memory full) in the +preprocessor. + +However, the special rule about self-reference cuts this process short +after one step, at @samp{(4 + foo)}. Therefore, this macro definition +has the possibly useful effect of causing the program to add 4 to +the value of @samp{foo} wherever @samp{foo} is referred to. + +In most cases, it is a bad idea to take advantage of this feature. A +person reading the program who sees that @samp{foo} is a variable will +not expect that it is a macro as well. The reader will come across the +identifier @samp{foo} in the program and think its value should be that +of the variable @samp{foo}, whereas in fact the value is four greater. + +The special rule for self-reference applies also to @dfn{indirect} +self-reference. This is the case where a macro @var{x} expands to use a +macro @samp{y}, and @samp{y}'s expansion refers to the macro @samp{x}. The +resulting reference to @samp{x} comes indirectly from the expansion of +@samp{x}, so it is a self-reference and is not further expanded. Thus, +after + +@example +#define x (4 + y) +#define y (2 * x) +@end example + +@noindent +@samp{x} would expand into @samp{(4 + (2 * x))}. Clear? + +But suppose @samp{y} is used elsewhere, not from the definition of @samp{x}. +Then the use of @samp{x} in the expansion of @samp{y} is not a self-reference +because @samp{x} is not ``in progress''. So it does expand. However, +the expansion of @samp{x} contains a reference to @samp{y}, and that +is an indirect self-reference now because @samp{y} is ``in progress''. +The result is that @samp{y} expands to @samp{(2 * (4 + y))}. + +It is not clear that this behavior would ever be useful, but it is specified +by the ANSI C standard, so you need to understand it. + +@node Argument Prescan, Cascaded Macros, Self-Reference, Macro Pitfalls +@subsubsection Separate Expansion of Macro Arguments + +We have explained that the expansion of a macro, including the substituted +actual arguments, is scanned over again for macro calls to be expanded. + +What really happens is more subtle: first each actual argument text is scanned +separately for macro calls. Then the results of this are substituted into +the macro body to produce the macro expansion, and the macro expansion +is scanned again for macros to expand. + +The result is that the actual arguments are scanned @emph{twice} to expand +macro calls in them. + +Most of the time, this has no effect. If the actual argument contained +any macro calls, they are expanded during the first scan. The result +therefore contains no macro calls, so the second scan does not change it. +If the actual argument were substituted as given, with no prescan, +the single remaining scan would find the same macro calls and produce +the same results. + +You might expect the double scan to change the results when a +self-referential macro is used in an actual argument of another macro +(@pxref{Self-Reference}): the self-referential macro would be expanded once +in the first scan, and a second time in the second scan. But this is not +what happens. The self-references that do not expand in the first scan are +marked so that they will not expand in the second scan either. + +The prescan is not done when an argument is stringified or concatenated. +Thus, + +@example +#define str(s) #s +#define foo 4 +str (foo) +@end example + +@noindent +expands to @samp{"foo"}. Once more, prescan has been prevented from +having any noticeable effect. + +More precisely, stringification and concatenation use the argument as +written, in un-prescanned form. The same actual argument would be used in +prescanned form if it is substituted elsewhere without stringification or +concatenation. + +@example +#define str(s) #s lose(s) +#define foo 4 +str (foo) +@end example + +expands to @samp{"foo" lose(4)}. + +You might now ask, ``Why mention the prescan, if it makes no difference? +And why not skip it and make the preprocessor faster?'' The answer is +that the prescan does make a difference in three special cases: + +@itemize @bullet +@item +Nested calls to a macro. + +@item +Macros that call other macros that stringify or concatenate. + +@item +Macros whose expansions contain unshielded commas. +@end itemize + +We say that @dfn{nested} calls to a macro occur when a macro's actual +argument contains a call to that very macro. For example, if @samp{f} +is a macro that expects one argument, @samp{f (f (1))} is a nested +pair of calls to @samp{f}. The desired expansion is made by +expanding @samp{f (1)} and substituting that into the definition of +@samp{f}. The prescan causes the expected result to happen. +Without the prescan, @samp{f (1)} itself would be substituted as +an actual argument, and the inner use of @samp{f} would appear +during the main scan as an indirect self-reference and would not +be expanded. Here, the prescan cancels an undesirable side effect +(in the medical, not computational, sense of the term) of the special +rule for self-referential macros. + +But prescan causes trouble in certain other cases of nested macro calls. +Here is an example: + +@example +#define foo a,b +#define bar(x) lose(x) +#define lose(x) (1 + (x)) + +bar(foo) +@end example + +@noindent +We would like @samp{bar(foo)} to turn into @samp{(1 + (foo))}, which +would then turn into @samp{(1 + (a,b))}. But instead, @samp{bar(foo)} +expands into @samp{lose(a,b)}, and you get an error because @code{lose} +requires a single argument. In this case, the problem is easily solved +by the same parentheses that ought to be used to prevent misnesting of +arithmetic operations: + +@example +#define foo (a,b) +#define bar(x) lose((x)) +@end example + +The problem is more serious when the operands of the macro are not +expressions; for example, when they are statements. Then parentheses +are unacceptable because they would make for invalid C code: + +@example +#define foo @{ int a, b; @dots{} @} +@end example + +@noindent +In GNU C you can shield the commas using the @samp{(@{@dots{}@})} +construct which turns a compound statement into an expression: + +@example +#define foo (@{ int a, b; @dots{} @}) +@end example + +Or you can rewrite the macro definition to avoid such commas: + +@example +#define foo @{ int a; int b; @dots{} @} +@end example + +There is also one case where prescan is useful. It is possible +to use prescan to expand an argument and then stringify it---if you use +two levels of macros. Let's add a new macro @samp{xstr} to the +example shown above: + +@example +#define xstr(s) str(s) +#define str(s) #s +#define foo 4 +xstr (foo) +@end example + +This expands into @samp{"4"}, not @samp{"foo"}. The reason for the +difference is that the argument of @samp{xstr} is expanded at prescan +(because @samp{xstr} does not specify stringification or concatenation of +the argument). The result of prescan then forms the actual argument for +@samp{str}. @samp{str} uses its argument without prescan because it +performs stringification; but it cannot prevent or undo the prescanning +already done by @samp{xstr}. + +@node Cascaded Macros,, Argument Prescan, Macro Pitfalls +@subsubsection Cascaded Use of Macros + +@cindex cascaded macros +@cindex macro body uses macro +A @dfn{cascade} of macros is when one macro's body contains a reference +to another macro. This is very common practice. For example, + +@example +#define BUFSIZE 1020 +#define TABLESIZE BUFSIZE +@end example + +This is not at all the same as defining @samp{TABLESIZE} to be @samp{1020}. +The @samp{#define} for @samp{TABLESIZE} uses exactly the body you +specify---in this case, @samp{BUFSIZE}---and does not check to see whether +it too is the name of a macro. + +It's only when you @emph{use} @samp{TABLESIZE} that the result of its expansion +is checked for more macro names. + +This makes a difference if you change the definition of @samp{BUFSIZE} +at some point in the source file. @samp{TABLESIZE}, defined as shown, +will always expand using the definition of @samp{BUFSIZE} that is +currently in effect: + +@example +#define BUFSIZE 1020 +#define TABLESIZE BUFSIZE +#undef BUFSIZE +#define BUFSIZE 37 +@end example + +@noindent +Now @samp{TABLESIZE} expands (in two stages) to @samp{37}. + +@node Conditionals, Combining Sources, Macros, Top +@section Conditionals + +@cindex conditionals +In a macro processor, a @dfn{conditional} is a command that allows a part +of the program to be ignored during compilation, on some conditions. +In the C preprocessor, a conditional can test either an arithmetic expression +or whether a name is defined as a macro. + +A conditional in the C preprocessor resembles in some ways an @samp{if} +statement in C, but it is important to understand the difference between +them. The condition in an @samp{if} statement is tested during the execution +of your program. Its purpose is to allow your program to behave differently +from run to run, depending on the data it is operating on. The condition +in a preprocessor conditional command is tested when your program is compiled. +Its purpose is to allow different code to be included in the program depending +on the situation at the time of compilation. + +@menu +* Uses: Conditional Uses. What conditionals are for. +* Syntax: Conditional Syntax. How conditionals are written. +* Deletion: Deleted Code. Making code into a comment. +* Macros: Conditionals-Macros. Why conditionals are used with macros. +* Errors: #error Command. Detecting inconsistent compilation parameters. +@end menu + +@node Conditional Uses, Conditional Syntax, Conditionals, Conditionals +@subsection Why Conditionals are Used + +Generally there are three kinds of reason to use a conditional. + +@itemize @bullet +@item +A program may need to use different code depending on the machine or +operating system it is to run on. In some cases the code for one +operating system may be erroneous on another operating system; for +example, it might refer to library routines that do not exist on the +other system. When this happens, it is not enough to avoid executing +the invalid code: merely having it in the program makes it impossible +to link the program and run it. With a preprocessor conditional, the +offending code can be effectively excised from the program when it is +not valid. + +@item +You may want to be able to compile the same source file into two +different programs. Sometimes the difference between the programs is +that one makes frequent time-consuming consistency checks on its +intermediate data while the other does not. + +@item +A conditional whose condition is always false is a good way to exclude +code from the program but keep it as a sort of comment for future +reference. +@end itemize + +Most simple programs that are intended to run on only one machine will +not need to use preprocessor conditionals. + +@node Conditional Syntax, Deleted Code, Conditional Uses, Conditionals +@subsection Syntax of Conditionals + +@findex #if +A conditional in the C preprocessor begins with a @dfn{conditional +command}: @samp{#if}, @samp{#ifdef} or @samp{#ifndef}. +@xref{Conditionals-Macros}, for info on @samp{#ifdef} and +@samp{#ifndef}; only @samp{#if} is explained here. + +@menu +* If: #if Command. Basic conditionals using @samp{#if} and @samp{#endif}. +* Else: #else Command. Including some text if the condition fails. +* Elif: #elif Command. Testing several alternative possibilities. +@end menu + +@node #if Command, #else Command, Conditional Syntax, Conditional Syntax +@subsubsection The @samp{#if} Command + +The @samp{#if} command in its simplest form consists of + +@example +#if @var{expression} +@var{controlled text} +#endif /* @var{expression} */ +@end example + +The comment following the @samp{#endif} is not required, but it is a good +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. + +@var{expression} is a C expression of integer type, subject to stringent +restrictions. It may contain + +@itemize @bullet +@item +Integer constants, which are all regarded as @code{long} or +@code{unsigned long}. + +@item +Character constants, which are interpreted according to the character +set and conventions of the machine and operating system on which the +preprocessor is running. The GNU C preprocessor uses the C data type +@samp{char} for these character constants; therefore, whether some +character codes are negative is determined by the C compiler used to +compile the preprocessor. If it treats @samp{char} as signed, then +character codes large enough to set the sign bit will be considered +negative; otherwise, no character code is considered negative. + +@item +Arithmetic operators for addition, subtraction, multiplication, +division, bitwise operations, shifts, comparisons, and @samp{&&} and +@samp{||}. + +@item +Identifiers that are not macros, which are all treated as zero(!). + +@item +Macro calls. All macro calls in the expression are expanded before +actual computation of the expression's value begins. +@end itemize + +Note that @samp{sizeof} operators and @code{enum}-type values are not allowed. +@code{enum}-type values, like all other identifiers that are not taken +as macro calls and expanded, are treated as zero. + +The text inside of a conditional can include preprocessor commands. Then +the commands inside the conditional are obeyed only if that branch of the +conditional succeeds. The text can also contain other conditional groups. +However, the @samp{#if}'s and @samp{#endif}'s must balance. + +@node #else Command, #elif Command, #if Command, Conditional Syntax +@subsubsection The @samp{#else} Command + +@findex #else +The @samp{#else} command can be added to a conditional to provide alternative +text to be used if the condition is false. This looks like + +@example +#if @var{expression} +@var{text-if-true} +#else /* Not @var{expression} */ +@var{text-if-false} +#endif /* Not @var{expression} */ +@end example + +If @var{expression} is nonzero, and the @var{text-if-true} is considered +included, then @samp{#else} acts like a failing conditional and the +@var{text-if-false} is ignored. Contrariwise, if the @samp{#if} +conditional fails, the @var{text-if-false} is considered included. + +@node #elif Command,, #else Command, Conditional Syntax +@subsubsection The @samp{#elif} Command + +@findex #elif +One common case of nested conditionals is used to check for more than two +possible alternatives. For example, you might have + +@example +#if X == 1 +@dots{} +#else /* X != 1 */ +#if X == 2 +@dots{} +#else /* X != 2 */ +@dots{} +#endif /* X != 2 */ +#endif /* X != 1 */ +@end example + +Another conditional command, @samp{#elif}, allows this to be abbreviated +as follows: + +@example +#if X == 1 +@dots{} +#elif X == 2 +@dots{} +#else /* X != 2 and X != 1*/ +@dots{} +#endif /* X != 2 and X != 1*/ +@end example + +@samp{#elif} stands for ``else if''. Like @samp{#else}, it goes in the +middle of a @samp{#if}-@samp{#endif} pair and subdivides it; it does not +require a matching @samp{#endif} of its own. Like @samp{#if}, the +@samp{#elif} command includes an expression to be tested. + +The text following the @samp{#elif} is processed only if the original +@samp{#if}-condition failed and the @samp{#elif} condition succeeeds. More +than one @samp{#elif} can go in the same @samp{#if}-@samp{#endif} group. +Then the text after each @samp{#elif} is processed only if the @samp{#elif} +condition succeeds after the original @samp{#if} and any previous +@samp{#elif}'s within it have failed. @samp{#else} is equivalent to +@samp{#elif 1}, and @samp{#else} is allowed after any number of +@samp{#elif}'s, but @samp{#elif} may not follow a @samp{#else}. + +@node Deleted Code, Conditionals-Macros, Conditional Syntax, Conditionals +@subsection Keeping Deleted Code for Future Reference + +If you replace or delete a part of the program but want to keep the old +code around as a comment for future reference, the easy way to do this is +to put @samp{#if 0} before it and @samp{#endif} after it. + +This works even if the code being turned off contains conditionals, but +they must be entire conditionals (balanced @samp{#if} and @samp{#endif}). + +@node Conditionals-Macros, #error Command, Deleted Code, Conditionals +@subsection Conditionals and Macros + +Conditionals are rarely useful except in connection with macros. A +@samp{#if} command whose expression uses no macros is equivalent to +@samp{#if 1} or @samp{#if 0}; you might as well determine which one, by +computing the value of the expression yourself, and then simplify the +program. But when the expression uses macros, its value can vary from +compilation to compilation. + +For example, here is a conditional that tests the expression +@samp{BUFSIZE == 1020}, where @samp{BUFSIZE} must be a macro. + +@example +#if BUFSIZE == 1020 + printf ("Large buffers!\n"); +#endif /* BUFSIZE is large */ +@end example + +@findex defined +The special operator @samp{defined} may be used in @samp{#if} expressions +to test whether a certain name is defined as a macro. Either @samp{defined +@var{name}} or @samp{defined (@var{name})} is an expression whose value is +1 if @var{name} is defined as macro at the current point in the program, +and 0 otherwise. For the @samp{defined} operator it makes no difference +what the definition of the macro is; all that matters is whether there is a +definition. Thus, for example,@refill + +@example +#if defined (vax) || defined (ns16000) +@end example + +@noindent +would include the following code if either of the names @samp{vax} and +@samp{ns16000} is defined as a macro. + +If a macro is defined and later undefined with @samp{#undef}, +subsequent use of the @samp{defined} operator will return 0, because +the name is no longer defined. If the macro is defined again with +another @samp{#define}, @samp{defined} will recommence returning 1. + +@findex #ifdef +@findex #ifndef +Conditionals that test just the definedness of one name are very common, so +there are two special short conditional commands for this case. They are + +@table @code +@item #ifdef @var{name} +is equivalent to @samp{#if defined (@var{name})}. + +@item #ifndef @var{name} +is equivalent to @samp{#if ! defined (@var{name})}. +@end table + +Macro definitions can vary between compilations for several reasons. + +@itemize @bullet +@item +Some macros are predefined on each kind of machine. For example, on a +Vax, the name @samp{vax} is a predefined macro. On other machines, it +would not be defined. + +@item +Many more macros are defined by system header files. Different +systems and machines define different macros, or give them different +values. It is useful to test these macros with conditionals to avoid +using a system feature on a machine where it is not implemented. + +@item +Macros are a common way of allowing users to customize a program for +different machines or applications. For example, the macro +@samp{BUFSIZE} might be defined in a configuration file for your +program that is included as a header file in each source file. You +would use @samp{BUFSIZE} in a preprocessor conditional in order to +generate different code depending on the chosen configuration. + +@item +Macros can be defined or undefined with @samp{-D} and @samp{-U} +command options when you compile the program. You can arrange to +compile the same source file into two different programs by choosing +a macro name to specify which program you want, writing conditionals +to test whether or how this macro is defined, and then controlling +the state of the macro with compiler command options. +@xref{Invocation}. +@end itemize + +@node #error Command,, Conditionals-Macros, Conditionals +@subsection The @samp{#error} Command + +@findex #error +The command @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. + +You would use @samp{#error} inside of a conditional that detects a +combination of parameters which you know the program does not properly +support. For example, if you know that the program will not run +properly on a Vax, you might write + +@example +#ifdef vax +#error Won't work on Vaxen. See comments at get_last_object. +#endif +@end example + +@noindent +@xref{Nonstandard Predefined}, for why this works. + +If you have several configuration parameters that must be set up by +the installation in a consistent way, you can use conditionals to detect +an inconsistency and report it with @samp{#error}. For example, + +@example +#if HASH_TABLE_SIZE % 2 == 0 || HASH_TABLE_SIZE % 3 == 0 \ + || HASH_TABLE_SIZE % 5 == 0 +#error HASH_TABLE_SIZE should not be divisible by a small prime +#endif +@end example + +@node Combining Sources, Other Commands, Conditionals, Top +@section Combining Source Files + +@cindex line control +@findex #line +One of the jobs of the C preprocessor is to inform the C compiler of where +each line of C code came from: which source file and which line number. + +C code can come from multiple source files if you use @samp{#include}; +both @samp{#include} and the use of conditionals and macros can cause +the line number of a line in the preprocessor output to be different +from the line's number in the original source file. You will appreciate +the value of making both the C compiler (in error messages) and symbolic +debuggers such as GDB use the line numbers in your source file. + +The C preprocessor builds on this feature by offering a command by which +you can control the feature explicitly. This is useful when a file for +input to the C preprocessor is the output from another program such as the +@code{bison} parser generator, which operates on another file that is the +true source file. Parts of the output from @code{bison} are generated from +scratch, other parts come from a standard parser file. The rest are copied +nearly verbatim from the source file, but their line numbers in the +@code{bison} output are not the same as their original line numbers. +Naturally you would like compiler error messages and symbolic debuggers to +know the original source file and line number of each line in the +@code{bison} output. + +@code{bison} arranges this by writing @samp{#line} commands into the output +file. @samp{#line} is a command that specifies the original line number +and source file name for subsequent input in the current preprocessor input +file. @samp{#line} has three variants: + +@table @code +@item #line @var{linenum} +Here @var{linenum} is a decimal integer constant. This specifies that +the line number of the following line of input, in its original source file, +was @var{linenum}. + +@item #line @var{linenum} @var{filename} +Here @var{linenum} is a decimal integer constant and @var{filename} +is a string constant. This specifies that the following line of input +came originally from source file @var{filename} and its line number there +was @var{linenum}. Keep in mind that @var{filename} is not just a +file name; it is surrounded by doublequote characters so that it looks +like a string constant. + +@item #line @var{anything else} +@var{anything else} is checked for macro calls, which are expanded. +The result should be a decimal integer constant followed optionally +by a string constant, as described above. +@end table + +@samp{#line} commands alter the results of the @samp{__FILE__} and +@samp{__LINE__} predefined macros from that point on. @xref{Standard +Predefined}. + +@node Other Commands, Output, Combining Sources, Top +@section Miscellaneous Preprocessor Commands + +@findex #pragma +@findex #ident +@cindex null command +This section describes three additional preprocessor commands. They are +not very useful, but are mentioned for completeness. + +The @dfn{null command} consists of a @samp{#} followed by a Newline, with +only whitespace (including comments) in between. A null command is +understood as a preprocessor command but has no effect on the preprocessor +output. The primary significance of the existence of the null command is +that an input line consisting of just a @samp{#} will produce no output, +rather than a line of output containing just a @samp{#}. Supposedly +some old C programs contain such lines. + +The @samp{#pragma} command is specified in the ANSI standard to have an +arbitrary implementation-defined effect. In the GNU C preprocessor, +@samp{#pragma} commands are ignored, except for @samp{#pragma once} +(@pxref{Once-Only}). + +The @samp{#ident} command is supported for compatibility with certain +other systems. It is followed by a line of text. On certain systems, +the text is copied into a special place in the object file; on most +systems, the text is ignored and this directive has no effect. + +@node Output, Invocation, Other Commands, Top +@section C Preprocessor Output + +@cindex output format +The output from the C preprocessor looks much like the input, except +that all preprocessor command 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. + +Source file name and line number information is conveyed by lines of +the form + +@example +# @var{linenum} @var{filename} @var{flag} +@end example + +@noindent +which are inserted as needed into the middle of the input (but never +within a string or character constant). Such a line means that the +following line originated in file @var{filename} at line @var{linenum}. + +The third field, @var{flag}, may be a number, or may be absent. It is +@samp{1} for the beginning of a new source file, and @samp{2} for return +to an old source file at the end of an included file. It is absent +otherwise. + +@node Invocation, Concept Index, Output, Top +@section Invoking the C Preprocessor + +Most often when you use the C preprocessor you will not have to invoke it +explicitly: the C compiler will do so automatically. However, the +preprocessor is sometimes useful individually. + +The C preprocessor expects two file names as arguments, @var{infile} and +@var{outfile}. The preprocessor reads @var{infile} together with any other +files it specifies with @samp{#include}. All the output generated by the +combined input files is written in @var{outfile}. + +Either @var{infile} or @var{outfile} may be @samp{-}, which as @var{infile} +means to read from standard input and as @var{outfile} means to write to +standard output. Also, if @var{outfile} or both file names are omitted, +the standard output and standard input are used for the omitted file names. + +@cindex options +Here is a table of command options accepted by the C preprocessor. Most +of them can also be given when compiling a C program; they are passed along +automatically to the preprocessor when it is invoked by the compiler. + +@table @samp +@item -P +@findex -P +Inhibit generation of @samp{#}-lines with line-number information in +the output from the preprocessor (@pxref{Output}). This might be +useful when running the preprocessor on something that is not C code +and will be sent to a program which might be confused by the +@samp{#}-lines + +@item -C +@findex -C +Do not discard comments: pass them through to the output file. +Comments appearing in arguments of a macro call will be copied to the +output before the expansion of the macro call. + +@item -trigraphs +@findex -trigraphs +Process ANSI standard trigraph sequences. These are three-character +sequences, all starting with @samp{??}, that are defined by ANSI C to +stand for single characters. For example, @samp{??/} stands for +@samp{\}, so @samp{'??/n'} is a character constant for a newline. +Strictly speaking, the GNU C preprocessor does not support all +programs in ANSI Standard C unless @samp{-trigraphs} is used, but if +you ever notice the difference it will be with relief. + +You don't want to know any more about trigraphs. + +@item -pedantic +@findex -pedantic +Issue warnings required by the ANSI C standard in certain cases such +as when text other than a comment follows @samp{#else} or @samp{#endif}. + +@item -I @var{directory} +@findex -I +Add the directory @var{directory} to the end of the list of +directories to be searched for header files (@pxref{Include Syntax}). +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. + +@item -I- +Any directories specified with @samp{-I} options before the @samp{-I-} +option are searched only for the case of @samp{#include "@var{file}"}; +they are not searched for @samp{#include <@var{file}>}. + +If additional directories are specified with @samp{-I} options after +the @samp{-I-}, these directories are searched for all @samp{#include} +directives. + +In addition, the @samp{-I-} option inhibits the use of the current +directory as the first search directory for @samp{#include "@var{file}"}. +Therefore, the current directory is searched only if it is requested +explicitly with @samp{-I.}. Specifying both @samp{-I-} and @samp{-I.} +allows you to control precisely which directories are searched before +the current one and which are searched after. + +@item -nostdinc +Do not search the standard system directories for header files. +Only the directories you have specified with @samp{-I} options +(and the current directory, if appropriate) are searched. + +@item -D @var{name} +@findex -D +Predefine @var{name} as a macro, with definition @samp{1}. + +@item -D @var{name}=@var{definition} +Predefine @var{name} as a macro, with definition @var{definition}. +There are no restrictions on the contents of @var{definition}, but if +you are invoking the preprocessor from a shell or shell-like program +you may need to use the shell's quoting syntax to protect characters +such as spaces that have a meaning in the shell syntax. + +@item -U @var{name} +@findex -U +Do not predefine @var{name}. If both @samp{-U} and @samp{-D} are +specified for one name, the @samp{-U} beats the @samp{-D} and the name +is not predefined. + +@item -undef +@findex -undef +Do not predefine any nonstandard macros. + +@item -d +@findex -d +Instead of outputting the result of preprocessing, output a list of +@samp{#define} commands for all the macros defined during the +execution of the preprocessor. + +@item -M +@findex -M +Instead of outputting the result of preprocessing, output a rule +suitable for @code{make} describing the dependencies of the main +source file. The preprocessor outputs one @code{make} rule containing +the object file name for that source file, a colon, and the names of +all the included files. If there are many included files then the +rule is split into several lines using @samp{\}-newline. + +This feature is used in automatic updating of makefiles. + +@item -MM +@findex -MM +Like @samp{-M} but mention only the files included with @samp{#include +"@var{file}"}. System header files included with @samp{#include +<@var{file}>} are omitted. + +@item -i @var{file} +@findex -i +Process @var{file} as input, discarding the resulting output, before +processing the regular input file. Because the output generated from +@var{file} is discarded, the only effect of @samp{-i @var{file}} is to +make the macros defined in @var{file} available for use in the main +input. +@end table + +@node Concept Index, Index, Invocation, Top +@unnumbered Concept Index +@printindex cp + +@node Index,, Concept Index, Top +@unnumbered Index of Commands, Macros and Options +@printindex fn + +@contents +@bye diff --git a/gcc-1.40/cse.c b/gcc-1.40/cse.c new file mode 100644 index 0000000..0807d2b --- /dev/null +++ b/gcc-1.40/cse.c @@ -0,0 +1,3936 @@ +/* Common subexpression elimination for GNU compiler. + Copyright (C) 1987, 1988, 1989 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 1, 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 "rtl.h" +#include "regs.h" +#include "hard-reg-set.h" +#include "flags.h" +#include "real.h" + +#include + +/* The basic idea of common subexpression elimination is to go + through the code, keeping a record of expressions that would + have the same value at the current scan point, and replacing + expressions encountered with the cheapest equivalent expression. + + It is too complicated to keep track of the different possibilities + when control paths merge; so, at each label, we forget all that is + known and start fresh. This can be described as processing each + basic block separately. Note, however, that these are not quite + the same as the basic blocks found by a later pass and used for + data flow analysis and register packing. We do not need to start fresh + after a conditional jump instruction if there is no label there. + + We use two data structures to record the equivalent expressions: + a hash table for most expressions, and several vectors together + with "quantity numbers" to record equivalent (pseudo) registers. + + The use of the special data structure for registers is desirable + because it is faster. It is possible because registers references + contain a fairly small number, the register number, taken from + a contiguously allocated series, and two register references are + identical if they have the same number. General expressions + do not have any such thing, so the only way to retrieve the + information recorded on an expression other than a register + is to keep it in a hash table. + +Registers and "quantity numbers": + + At the start of each basic block, all of the (hardware and pseudo) + registers used in the function are given distinct quantity + numbers to indicate their contents. During scan, when the code + copies one register into another, we copy the quantity number. + When a register is loaded in any other way, we allocate a new + quantity number to describe the value generated by this operation. + `reg_qty' records what quantity a register is currently thought + of as containing. + + We also maintain a bidirectional chain of registers for each + quantity number. `qty_first_reg', `qty_last_reg', + `reg_next_eqv' and `reg_prev_eqv' hold these chains. + + The first register in a chain is the one whose lifespan is least local. + Among equals, it is the one that was seen first. + We replace any equivalent register with that one. + +Constants and quantity numbers + + When a quantity has a known constant value, that value is stored + in the appropriate element of qty_const. This is in addition to + putting the constant in the hash table as is usual for non-regs. + + Regs are preferred to constants as they are to everything else, + but expressions containing constants can be simplified, by fold_rtx. + + When a quantity has a known nearly constant value (such as an address + of a stack slot), that value is stored in the appropriate element + of qty_const. + + Integer constants don't have a machine mode. However, cse + determines the intended machine mode from the destination + of the instruction that moves the constant. The machine mode + is recorded in the hash table along with the actual RTL + constant expression so that different modes are kept separate. + +Other expressions: + + To record known equivalences among expressions in general + we use a hash table called `table'. It has a fixed number of buckets + that contain chains of `struct table_elt' elements for expressions. + These chains connect the elements whose expressions have the same + hash codes. + + Other chains through the same elements connect the elements which + currently have equivalent values. + + Register references in an expression are canonicalized before hashing + the expression. This is done using `reg_qty' and `qty_first_reg'. + The hash code of a register reference is computed using the quantity + number, not the register number. + + When the value of an expression changes, it is necessary to remove from the + hash table not just that expression but all expressions whose values + could be different as a result. + + 1. If the value changing is in memory, except in special cases + ANYTHING referring to memory could be changed. That is because + nobody knows where a pointer does not point. + The function `invalidate_memory' removes what is necessary. + + The special cases are when the address is constant or is + a constant plus a fixed register such as the frame pointer + or a static chain pointer. When such addresses are stored in, + we can tell exactly which other such addresses must be invalidated + due to overlap. `invalidate' does this. + All expressions that refer to non-constant + memory addresses are also invalidated. `invalidate_memory' does this. + + 2. If the value changing is a register, all expressions + containing references to that register, and only those, + must be removed. + + Because searching the entire hash table for expressions that contain + a register is very slow, we try to figure out when it isn't necessary. + Precisely, this is necessary only when expressions have been + entered in the hash table using this register, and then the value has + changed, and then another expression wants to be added to refer to + the register's new value. This sequence of circumstances is rare + within any one basic block. + + The vectors `reg_tick' and `reg_in_table' are used to detect this case. + reg_tick[i] is incremented whenever a value is stored in register i. + reg_in_table[i] holds -1 if no references to register i have been + entered in the table; otherwise, it contains the value reg_tick[i] had + when the references were entered. If we want to enter a reference + and reg_in_table[i] != reg_tick[i], we must scan and remove old references. + Until we want to enter a new entry, the mere fact that the two vectors + don't match makes the entries be ignored if anyone tries to match them. + + Registers themselves are entered in the hash table as well as in + the equivalent-register chains. However, the vectors `reg_tick' + and `reg_in_table' do not apply to expressions which are simple + register references. These expressions are removed from the table + immediately when they become invalid, and this can be done even if + we do not immediately search for all the expressions that refer to + the register. + + A CLOBBER rtx in an instruction invalidates its operand for further + reuse. A CLOBBER or SET rtx whose operand is a MEM:BLK + invalidates everything that resides in memory. + +Related expressions: + + Constant expressions that differ only by an additive integer + are called related. When a constant expression is put in + the table, the related expression with no constant term + is also entered. These are made to point at each other + so that it is possible to find out if there exists any + register equivalent to an expression related to a given expression. */ + +/* One plus largest register number used in this function. */ + +static int max_reg; + +/* Length of vectors indexed by quantity number. + We know in advance we will not need a quantity number this big. */ + +static int max_qty; + +/* Next quantity number to be allocated. + This is 1 + the largest number needed so far. */ + +static int next_qty; + +/* Indexed by quantity number, gives the first (or last) (pseudo) register + in the chain of registers that currently contain this quantity. */ + +static int *qty_first_reg; +static int *qty_last_reg; + +/* Indexed by quantity number, gives the rtx of the constant value of the + quantity, or zero if it does not have a known value. + A sum of the frame pointer (or arg pointer) plus a constant + can also be entered here. */ + +static rtx *qty_const; + +/* Indexed by qty number, gives the insn that stored the constant value + recorded in `qty_const'. */ + +static rtx *qty_const_insn; + +/* Value stored in CC0 by previous insn: + 0 if previous insn didn't store in CC0. + else 0100 + (M&7)<<3 + (N&7) + where M is 1, 0 or -1 if result was >, == or < as signed number + and N is 1, 0 or -1 if result was >, == or < as unsigned number. + 0200 bit may also be set, meaning that only == and != comparisons + have known results. */ + +static int prev_insn_cc0; + +/* For machines where CC0 is one bit, we may see CC0 assigned a + constant value (after fold_rtx). + Record here the value stored in the previous insn (0 if none). */ + +static rtx prev_insn_explicit_cc0; + +/* Previous actual insn. 0 if at first insn of basic block. */ + +static rtx prev_insn; + +/* Insn being scanned. */ + +static rtx this_insn; + +/* Index by (pseudo) 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 + (pseudo) register in the chain of registers sharing the same value. + Or -1 if this register is at the end of the chain. */ + +static int *reg_next_eqv; + +/* Index by (pseudo) register number, gives the number of the previous + (pseudo) register in the chain of registers sharing the same value. + Or -1 if this register is at the beginning of the chain. */ + +static int *reg_prev_eqv; + +/* Index by (pseudo) register number, gives the latest rtx + to use to insert a ref to that register. */ + +static rtx *reg_rtx; + +/* Index by (pseudo) 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 + 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. + If this is -1, no expressions containing this register have been + entered in the table. */ + +static int *reg_in_table; + +/* Two vectors of max_reg ints: + one containing all -1's; in the other, element i contains i. + These are used to initialize various other vectors fast. */ + +static int *all_minus_one; +static int *consec_ints; + +/* Set nonzero in cse_insn to tell cse_basic_block to skip immediately + to the next basic block and treat it as a continuation of this one. */ + +static int cse_skip_to_next_block; + +/* CUID of insn that starts the basic block currently being cse-processed. */ + +static int cse_basic_block_start; + +/* CUID of insn that ends the basic block currently being cse-processed. */ + +static int cse_basic_block_end; + +/* Vector mapping INSN_UIDs to cuids. + The cuids are like uids but increase monononically always. + We use them to see whether a reg is used outside a given basic block. */ + +static short *uid_cuid; + +/* Get the cuid of an insn. */ + +#define INSN_CUID(INSN) (uid_cuid[INSN_UID (INSN)]) + +/* Nonzero if cse has altered conditional jump insns + in such a way that jump optimization should be redone. */ + +static int cse_jumps_altered; + +/* canon_hash stores 1 in do_not_record + if it notices a reference to CC0, CC1 or PC. */ + +static int do_not_record; + +/* canon_hash stores 1 in hash_arg_in_memory + if it notices a reference to memory within the expression being hashed. */ + +static int hash_arg_in_memory; + +/* canon_hash stores 1 in hash_arg_in_struct + if it notices a reference to memory that's part of a structure. */ + +static int hash_arg_in_struct; + +/* The hash table contains buckets which are chains of `struct table_elt's, + each recording one expression's information. + That expression is in the `exp' field. + + Those elements with the same hash code are chained in both directions + through the `next_same_hash' and `prev_same_hash' fields. + + Each set of expressions with equivalent values + are on a two-way chain through the `next_same_value' + and `prev_same_value' fields, and all point with + the `first_same_value' field at the first element in + that chain. The chain is in order of increasing cost. + Each element's cost value is in its `cost' field. + + The `in_memory' field is nonzero for elements that + involve any reference to memory. These elements are removed + whenever a write is done to an unidentified location in memory. + To be safe, we assume that a memory address is unidentified unless + the address is either a symbol constant or a constant plus + the frame pointer or argument pointer. + + The `in_struct' field is nonzero for elements that + involve any reference to memory inside a structure or array. + + The `equivalence_only' field means that this expression came from a + REG_EQUIV or REG_EQUAL note; it is not valid for substitution into an insn. + + The `related_value' field is used to connect related expressions + (that differ by adding an integer). + The related expressions are chained in a circular fashion. + `related_value' is zero for expressions for which this + chain is not useful. + + The `mode' field is usually the same as GET_MODE (`exp'), but + if `exp' is a CONST_INT and has no machine mode then the `mode' + field is the mode it was being used as. Each constant is + recorded separately for each mode it is used with. */ + + +struct table_elt +{ + rtx exp; + struct table_elt *next_same_hash; + struct table_elt *prev_same_hash; + struct table_elt *next_same_value; + struct table_elt *prev_same_value; + struct table_elt *first_same_value; + struct table_elt *related_value; + int cost; + enum machine_mode mode; + char in_memory; + char in_struct; + char equivalence_only; +}; + +#define HASH(x, m) (canon_hash (x, m) % NBUCKETS) +/* We don't want a lot of buckets, because we rarely have very many + things stored in the hash table, and a lot of buckets slows + down a lot of loops that happen frequently. */ +#define NBUCKETS 31 + +static struct table_elt *table[NBUCKETS]; + +/* Chain of `struct table_elt's made so far for this function + but currently removed from the table. */ + +static struct table_elt *free_element_chain; + +/* Number of `struct table_elt' structures made so far for this function. */ + +static int n_elements_made; + +/* Maximum value `n_elements_made' has had so far in this compilation + for functions previously processed. */ + +static int max_elements_made; + +/* 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. + 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 var : 1; /* Invalidate variable addresses. */ + int nonscalar : 1; /* Invalidate all but scalar variables. */ + int all : 1; /* Invalidate all memory refs. */ +}; + +/* Nonzero if X has the form (PLUS frame-pointer integer). */ + +#define FIXED_BASE_PLUS_P(X) \ + (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 1)) == CONST_INT \ + && (XEXP (X, 0) == frame_pointer_rtx || XEXP (X, 0) == arg_pointer_rtx)) + +static struct table_elt *lookup (); +static void free_element (); + +static void remove_invalid_refs (); +static int exp_equiv_p (); +int refers_to_p (); +int refers_to_mem_p (); +static void invalidate_from_clobbers (); +static int safe_hash (); +static int canon_hash (); +static rtx equiv_constant (); +static int get_integer_term (); +static rtx get_related_value (); +static void note_mem_written (); +static int cse_rtx_addr_varies_p (); +static int fold_cc0 (); + +/* Return an estimate of the cost of computing rtx X. + The only use of this is to compare the costs of two expressions + to decide whether to replace one with the other. */ + +static int +rtx_cost (x) + rtx x; +{ + register int i, j; + register enum rtx_code code; + register char *fmt; + register int total; + + if (x == 0) + return 0; + + code = GET_CODE (x); + switch (code) + { + case REG: + return 1; + case SUBREG: + return 2; + CONST_COSTS (x, code); + } + + total = 2; + if (code == MEM) + total = 2 * GET_MODE_SIZE (GET_MODE (x)) / UNITS_PER_WORD; + + /* Sum the costs of the sub-rtx's, plus 2 just put in. */ + + fmt = GET_RTX_FORMAT (code); + for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) + if (fmt[i] == 'e') + total += rtx_cost (XEXP (x, i)); + else if (fmt[i] == 'E') + for (j = 0; j < XVECLEN (x, i); j++) + total += rtx_cost (XVECEXP (x, i, j)); + + return total; +} + +/* Clear the hash table and initialize each register with its own quantity, + for a new basic block. */ + +static void +new_basic_block () +{ + register int i; + register int vecsize = max_reg * sizeof (rtx); + next_qty = max_reg; + + bzero (reg_rtx, vecsize); + bzero (reg_tick, vecsize); + + bcopy (all_minus_one, reg_in_table, vecsize); + bcopy (all_minus_one, reg_next_eqv, vecsize); + bcopy (all_minus_one, reg_prev_eqv, vecsize); + bcopy (consec_ints, reg_qty, vecsize); + + for (i = 0; i < max_qty; i++) + { + qty_first_reg[i] = i; + qty_last_reg[i] = i; + qty_const[i] = 0; + qty_const_insn[i] = 0; + } + + for (i = 0; i < NBUCKETS; i++) + { + register struct table_elt *this, *next; + for (this = table[i]; this; this = next) + { + next = this->next_same_hash; + free_element (this); + } + } + + bzero (table, sizeof table); + + prev_insn_cc0 = 0; + prev_insn_explicit_cc0 = 0; + prev_insn = 0; +} + +/* Say that register REG contains a quantity not in any register before. */ + +static void +make_new_qty (reg) + register int reg; +{ + register int q; + + q = reg_qty[reg] = next_qty++; + qty_first_reg[q] = reg; + qty_last_reg[q] = reg; +} + +/* Make reg NEW equivalent to reg OLD. + OLD is not changing; NEW is. */ + +static void +make_regs_eqv (new, old) + register int new, old; +{ + register int lastr, firstr; + register int q = reg_qty[old]; + + /* Nothing should become eqv until it has a "non-invalid" qty number. */ + if (q == old) + abort (); + + reg_qty[new] = q; + firstr = qty_first_reg[q]; + lastr = qty_last_reg[q]; + + /* Prefer pseudo regs to hard regs with the same value. + Among pseudos, if NEW will live longer than any other reg of the same qty, + and that is beyond the current basic block, + make it the new canonical replacement for this qty. */ + if (new >= FIRST_PSEUDO_REGISTER + && (firstr < FIRST_PSEUDO_REGISTER + || ((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]])))) + { + reg_prev_eqv[firstr] = new; + reg_next_eqv[new] = firstr; + reg_prev_eqv[new] = -1; + qty_first_reg[q] = new; + } + else + { + /* If NEW is a hard reg, insert at end. + Otherwise, insert before any hard regs that are at the end. */ + while (lastr < FIRST_PSEUDO_REGISTER && new >= FIRST_PSEUDO_REGISTER) + lastr = reg_prev_eqv[lastr]; + reg_next_eqv[new] = reg_next_eqv[lastr]; + if (reg_next_eqv[lastr] >= 0) + reg_prev_eqv[reg_next_eqv[lastr]] = new; + else + qty_last_reg[q] = new; + reg_next_eqv[lastr] = new; + reg_prev_eqv[new] = lastr; + } +} + +/* Discard the records of what is in register REG. */ + +static void +reg_invalidate (reg) + register int reg; +{ + register int n = reg_next_eqv[reg]; + register int p = reg_prev_eqv[reg]; + register int q = reg_qty[reg]; + + reg_tick[reg]++; + + if (q == reg) + { + /* Save time if already invalid */ + /* It shouldn't be linked to anything if it's invalid. */ + if (reg_prev_eqv[q] != -1) + abort (); + if (reg_next_eqv[q] != -1) + abort (); + return; + } + + if (n != -1) + reg_prev_eqv[n] = p; + else + qty_last_reg[q] = p; + if (p != -1) + reg_next_eqv[p] = n; + else + qty_first_reg[q] = n; + + reg_qty[reg] = reg; + qty_first_reg[reg] = reg; + qty_last_reg[reg] = reg; + reg_next_eqv[reg] = -1; + reg_prev_eqv[reg] = -1; +} + +/* Remove any invalid expressions from the hash table + that refer to any of the registers contained in expression X. + + Make sure that newly inserted references to those registers + as subexpressions will be considered valid. + + mention_regs is not called when a register itself + is being stored in the table. */ + +static void +mention_regs (x) + rtx x; +{ + register enum rtx_code code; + register int i, j; + register char *fmt; + + if (x == 0) + return; + + code = GET_CODE (x); + if (code == REG) + { + register int regno = REGNO (x); + reg_rtx[regno] = x; + + if (reg_in_table[regno] >= 0 && reg_in_table[regno] != reg_tick[regno]) + remove_invalid_refs (regno); + + reg_in_table[regno] = reg_tick[regno]; + + return; + } + + fmt = GET_RTX_FORMAT (code); + for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) + if (fmt[i] == 'e') + mention_regs (XEXP (x, i)); + else if (fmt[i] == 'E') + for (j = 0; j < XVECLEN (x, i); j++) + mention_regs (XVECEXP (x, i, j)); +} + +/* Update the register quantities for inserting X into the hash table + with a value equivalent to CLASSP. + (If CLASSP is not a REG or a SUBREG, it is irrelevant.) + If MODIFIED is nonzero, X is a destination; it is being modified. + Note that reg_invalidate should be called on a register + before insert_regs is done on that register with MODIFIED != 0. + + Nonzero value means that elements of reg_qty have changed + so X's hash code may be different. */ + +static int +insert_regs (x, classp, modified) + rtx x; + struct table_elt *classp; + int modified; +{ + if (GET_CODE (x) == REG) + { + register int regno = REGNO (x); + reg_rtx[regno] = x; + if (modified || reg_qty[regno] == regno) + { + if (classp && GET_CODE (classp->exp) == REG) + { + make_regs_eqv (regno, REGNO (classp->exp)); + /* Make sure reg_rtx is set up even for regs + not explicitly set (such as function value). */ + reg_rtx[REGNO (classp->exp)] = classp->exp; + } + else + make_new_qty (regno); + return 1; + } + } + /* Copying a subreg into a subreg makes the regs equivalent, + but only if the entire regs' mode is within one word. + Copying one reg of a DImode into one reg of another DImode + does not make them equivalent. */ + else if (GET_CODE (x) == SUBREG + && GET_CODE (SUBREG_REG (x)) == REG + && GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))) <= UNITS_PER_WORD + && (modified + || reg_qty[REGNO (SUBREG_REG (x))] == REGNO (SUBREG_REG (x)))) + { + if (classp && GET_CODE (classp->exp) == SUBREG + && GET_CODE (SUBREG_REG (classp->exp)) == REG + && GET_MODE (SUBREG_REG (classp->exp)) == GET_MODE (SUBREG_REG (x))) + { + int oregno = REGNO (SUBREG_REG (classp->exp)); + make_regs_eqv (REGNO (SUBREG_REG (x)), oregno); + /* Make sure reg_rtx is set up even for regs + not explicitly set (such as function value). */ + reg_rtx[oregno] = SUBREG_REG (classp->exp); + } + else + make_new_qty (REGNO (SUBREG_REG (x))); + return 1; + } + else + mention_regs (x); + return 0; +} + +/* Look in or update the hash table. */ + +/* Put the element ELT on the list of free elements. */ + +static void +free_element (elt) + struct table_elt *elt; +{ + elt->next_same_hash = free_element_chain; + free_element_chain = elt; +} + +/* Return an element that is free for use. */ + +static struct table_elt * +get_element () +{ + struct table_elt *elt = free_element_chain; + if (elt) + { + free_element_chain = elt->next_same_hash; + return elt; + } + n_elements_made++; + return (struct table_elt *) oballoc (sizeof (struct table_elt)); +} + +/* Remove table element ELT from use in the table. + HASH is its hash code, made using the HASH macro. + It's an argument because often that is known in advance + and we save much time not recomputing it. */ + +static void +remove (elt, hash) + register struct table_elt *elt; + int hash; +{ + if (elt == 0) + return; + + /* Mark this element as removed. See cse_insn. */ + elt->first_same_value = 0; + + /* Remove the table element from its equivalence class. */ + + { + register struct table_elt *prev = elt->prev_same_value; + register struct table_elt *next = elt->next_same_value; + + if (next) next->prev_same_value = prev; + + if (prev) + prev->next_same_value = next; + else + { + register struct table_elt *newfirst = next; + while (next) + { + next->first_same_value = newfirst; + next = next->next_same_value; + } + } + } + + /* Remove the table element from its hash bucket. */ + + { + register struct table_elt *prev = elt->prev_same_hash; + register struct table_elt *next = elt->next_same_hash; + + if (next) next->prev_same_hash = prev; + + if (prev) + prev->next_same_hash = next; + else + table[hash] = next; + } + + /* Remove the table element from its related-value circular chain. */ + + if (elt->related_value != 0 && elt->related_value != elt) + { + register struct table_elt *p = elt->related_value; + while (p->related_value != elt) + p = p->related_value; + p->related_value = elt->related_value; + if (p->related_value == p) + p->related_value = 0; + } + + free_element (elt); +} + +/* Look up X in the hash table and return its table element, + or 0 if X is not in the table. + + MODE is the machine-mode of X, or if X is an integer constant + with VOIDmode then MODE is the mode with which X will be used. + + Here we are satisfied to find an expression whose tree structure + looks like X. */ + +static struct table_elt * +lookup (x, hash, mode) + rtx x; + int hash; + enum machine_mode mode; +{ + register struct table_elt *p; + + for (p = table[hash]; p; p = p->next_same_hash) + if (mode == p->mode && (x == p->exp || exp_equiv_p (x, p->exp, 1))) + return p; + + return 0; +} + +/* Like `lookup' but don't care whether the table element uses invalid regs. + Also ignore discrepancies in the machine mode of a register. */ + +static struct table_elt * +lookup_for_remove (x, hash, mode) + rtx x; + int hash; + enum machine_mode mode; +{ + register struct table_elt *p; + + if (GET_CODE (x) == REG) + { + int regno = REGNO (x); + /* Don't check the machine mode when comparing registers; + invalidating (REG:SI 0) also invalidates (REG:DF 0). */ + for (p = table[hash]; p; p = p->next_same_hash) + if (GET_CODE (p->exp) == REG + && REGNO (p->exp) == regno) + return p; + } + else + { + for (p = table[hash]; p; p = p->next_same_hash) + if (mode == p->mode && (x == p->exp || exp_equiv_p (x, p->exp, 0))) + return p; + } + + return 0; +} + +/* Look for an expression equivalent to X and with code CODE. + If one is found, return that expression. */ + +static rtx +lookup_as_function (x, code) + rtx x; + enum rtx_code code; +{ + register struct table_elt *p = lookup (x, safe_hash (x, 0) % NBUCKETS, + GET_MODE (x)); + if (p == 0) + return 0; + + for (p = p->first_same_value; p; p = p->next_same_value) + { + if (GET_CODE (p->exp) == code + /* Make sure this is a valid entry in the table. */ + && (exp_equiv_p (XEXP (p->exp, 0), XEXP (p->exp, 0), 1))) + return p->exp; + } + + return 0; +} + +/* Insert X in the hash table, assuming HASH is its hash code + and CLASSP is the current first element of the class it should go in + (or 0 if a new class should be made). + It is inserted at the proper position to keep the class in + the order cheapest first. + + MODE is the machine-mode of X, or if X is an integer constant + with VOIDmode then MODE is the mode with which X will be used. + + For elements of equal cheapness, the most recent one + goes in front, except that the first element in the list + remains first unless a cheaper element is added. + + The in_memory field in the hash table element is set to 0. + The caller must set it nonzero if appropriate. + + You should call insert_regs (X, CLASSP, MODIFY) before calling here, + and if insert_regs returns a nonzero value + you must then recompute its hash code before calling here. + + If necessary, update table showing constant values of quantities. */ + +#define CHEAPER(X,Y) \ + (((X)->cost < (Y)->cost) || \ + ((X)->cost == (Y)->cost \ + && GET_CODE ((X)->exp) == REG && GET_CODE ((Y)->exp) == REG \ + && (uid_cuid[regno_last_uid[REGNO ((X)->exp)]] > cse_basic_block_end \ + || uid_cuid[regno_first_uid[REGNO ((X)->exp)]] < cse_basic_block_start) \ + && (uid_cuid[regno_last_uid[REGNO ((X)->exp)]] \ + > uid_cuid[regno_last_uid[REGNO ((Y)->exp)]]))) + +static struct table_elt * +insert (x, classp, hash, mode) + register rtx x; + register struct table_elt *classp; + int hash; + enum machine_mode mode; +{ + register struct table_elt *elt; + + /* Put an element for X into the right hash bucket. */ + + elt = get_element (); + elt->exp = x; + elt->cost = rtx_cost (x) * 2; + /* Make pseudo regs a little cheaper than hard regs. */ + if (GET_CODE (x) == REG && REGNO (x) >= FIRST_PSEUDO_REGISTER) + elt->cost -= 1; + elt->next_same_value = 0; + elt->prev_same_value = 0; + elt->next_same_hash = table[hash]; + elt->prev_same_hash = 0; + elt->related_value = 0; + elt->in_memory = 0; + elt->equivalence_only = 0; + elt->mode = mode; + if (table[hash]) + table[hash]->prev_same_hash = elt; + table[hash] = elt; + + /* Put it into the proper value-class. */ + if (classp) + { + if (CHEAPER (elt, classp)) + /** Insert at the head of the class */ + { + register struct table_elt *p; + elt->next_same_value = classp; + classp->prev_same_value = elt; + elt->first_same_value = elt; + + for (p = classp; p; p = p->next_same_value) + p->first_same_value = elt; + } + else + { + /* Insert not at head of the class. */ + /* Put it after the last element cheaper than X. */ + register struct table_elt *p, *next; + for (p = classp; (next = p->next_same_value) && CHEAPER (next, elt); + p = next); + /* Put it after P and before NEXT. */ + elt->next_same_value = next; + if (next) + next->prev_same_value = elt; + elt->prev_same_value = p; + p->next_same_value = elt; + elt->first_same_value = classp; + } + } + else + elt->first_same_value = elt; + + if ((CONSTANT_P (x) || GET_CODE (x) == CONST_DOUBLE || FIXED_BASE_PLUS_P (x)) + && GET_CODE (elt->first_same_value->exp) == REG) + { + qty_const[reg_qty[REGNO (elt->first_same_value->exp)]] = x; + qty_const_insn[reg_qty[REGNO (elt->first_same_value->exp)]] = this_insn; + } + + if (GET_CODE (x) == REG) + { + if (elt->next_same_value != 0 + && (CONSTANT_P (elt->next_same_value->exp) + || GET_CODE (elt->next_same_value->exp) == CONST_DOUBLE + || FIXED_BASE_PLUS_P (elt->next_same_value->exp))) + { + qty_const[reg_qty[REGNO (x)]] = elt->next_same_value->exp; + qty_const_insn[reg_qty[REGNO (x)]] = this_insn; + } + if (CONSTANT_P (elt->first_same_value->exp) + || GET_CODE (elt->first_same_value->exp) == CONST_DOUBLE + || FIXED_BASE_PLUS_P (elt->first_same_value->exp)) + { + qty_const[reg_qty[REGNO (x)]] = elt->first_same_value->exp; + qty_const_insn[reg_qty[REGNO (x)]] = this_insn; + } + } + + /* If this is a constant with symbolic value, + and it has a term with an explicit integer value, + link it up with related expressions. */ + if (GET_CODE (x) == CONST) + { + rtx subexp = get_related_value (x); + int subhash; + struct table_elt *subelt, *subelt_prev; + + if (subexp != 0) + { + /* Get the integer-free subexpression in the hash table. */ + subhash = safe_hash (subexp, mode) % NBUCKETS; + subelt = lookup (subexp, subhash, mode); + if (subelt == 0) + subelt = insert (subexp, 0, subhash, mode); + /* Initialize SUBELT's circular chain if it has none. */ + if (subelt->related_value == 0) + subelt->related_value = subelt; + /* Find the element in the circular chain that precedes SUBELT. */ + subelt_prev = subelt; + while (subelt_prev->related_value != subelt) + subelt_prev = subelt_prev->related_value; + /* Put new ELT into SUBELT's circular chain just before SUBELT. + This way the element that follows SUBELT is the oldest one. */ + elt->related_value = subelt_prev->related_value; + subelt_prev->related_value = elt; + } + } + + return elt; +} + +/* Remove from the hash table, or mark as invalid, + all expressions whose values could be altered by storing in X. + X is a register, a subreg, or a memory reference with nonvarying address + (because, when a memory reference with a varying address is stored in, + all memory references are removed by invalidate_memory + so specific invalidation is superfluous). + + A nonvarying address may be just a register or just + a symbol reference, or it may be either of those plus + a numeric offset. */ + +static void +invalidate (x) + rtx x; +{ + register int i; + register struct table_elt *p; + register rtx base; + register int start, end; + + /* If X is a register, dependencies on its contents + are recorded through the qty number mechanism. + Just change the qty number of the register, + mark it as invalid for expressions that refer to it, + and remove it itself. */ + + if (GET_CODE (x) == REG) + { + register int hash = HASH (x, 0); + reg_invalidate (REGNO (x)); + remove (lookup_for_remove (x, hash, GET_MODE (x)), hash); + return; + } + + if (GET_CODE (x) == SUBREG) + { + if (GET_CODE (SUBREG_REG (x)) != REG) + abort (); + invalidate (SUBREG_REG (x)); + 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. */ + + if (GET_CODE (x) != MEM) + abort (); + base = XEXP (x, 0); + start = 0; + + /* Registers with nonvarying addresses usually have constant equivalents; + but the frame pointer register is also possible. */ + if (GET_CODE (base) == REG + && qty_const[reg_qty[REGNO (base)]] != 0) + base = qty_const[reg_qty[REGNO (base)]]; + + if (GET_CODE (base) == CONST) + base = XEXP (base, 0); + if (GET_CODE (base) == PLUS + && GET_CODE (XEXP (base, 1)) == CONST_INT) + { + start = INTVAL (XEXP (base, 1)); + base = XEXP (base, 0); + } + + end = start + GET_MODE_SIZE (GET_MODE (x)); + 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)) + remove (p, i); + } + } +} + +/* Remove all expressions that refer to register REGNO, + since they are already invalid, and we are about to + mark that register valid again and don't want the old + expressions to reappear as valid. */ + +static void +remove_invalid_refs (regno) + int regno; +{ + register int i; + register struct table_elt *p, *next; + register rtx x = reg_rtx[regno]; + + for (i = 0; i < NBUCKETS; i++) + for (p = table[i]; p; p = next) + { + next = p->next_same_hash; + if (GET_CODE (p->exp) != REG && refers_to_p (p->exp, x)) + remove (p, i); + } +} + +/* 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 (p, i); + } +} + +/* Return the value of the integer term in X, if one is apparent; + otherwise return 0. + We do not check extremely carefully for the presence of integer terms + but rather consider only the cases that `insert' notices + for the `related_value' field. */ + +static int +get_integer_term (x) + rtx x; +{ + if (GET_CODE (x) == CONST) + x = XEXP (x, 0); + + if (GET_CODE (x) == MINUS + && GET_CODE (XEXP (x, 1)) == CONST_INT) + return - INTVAL (XEXP (x, 1)); + if (GET_CODE (x) != PLUS) + return 0; + if (GET_CODE (XEXP (x, 0)) == CONST_INT) + return INTVAL (XEXP (x, 0)); + if (GET_CODE (XEXP (x, 1)) == CONST_INT) + return INTVAL (XEXP (x, 1)); + return 0; +} + +static rtx +get_related_value (x) + rtx x; +{ + if (GET_CODE (x) != CONST) + return 0; + x = XEXP (x, 0); + if (GET_CODE (x) == PLUS) + { + if (GET_CODE (XEXP (x, 0)) == CONST_INT) + return XEXP (x, 1); + if (GET_CODE (XEXP (x, 1)) == CONST_INT) + return XEXP (x, 0); + } + else if (GET_CODE (x) == MINUS + && GET_CODE (XEXP (x, 1)) == CONST_INT) + return XEXP (x, 0); + return 0; +} + +/* Given an expression X of type CONST, + and ELT which is its table entry (or 0 if it + is not in the hash table), + return an alternate expression for X as a register plus integer. + If none can be found or it would not be a valid address, return 0. */ + +static rtx +use_related_value (x, elt) + rtx x; + struct table_elt *elt; +{ + register struct table_elt *relt = 0; + register struct table_elt *p; + int offset; + rtx addr; + + /* First, is there anything related known? + If we have a table element, we can tell from that. + Otherwise, must look it up. */ + + if (elt != 0 && elt->related_value != 0) + relt = elt; + else if (elt == 0 && GET_CODE (x) == CONST) + { + rtx subexp = get_related_value (x); + if (subexp != 0) + relt = lookup (subexp, + safe_hash (subexp, GET_MODE (subexp)) % NBUCKETS, + GET_MODE (subexp)); + } + + if (relt == 0) + return 0; + + /* Search all related table entries for one that has an + equivalent register. */ + + p = relt; + while (1) + { + if (p->first_same_value != 0 + && GET_CODE (p->first_same_value->exp) == REG) + break; + p = p->related_value; + + /* We went all the way around, so there is nothing to be found. + Return failure. */ + if (p == relt) + return 0; + /* Perhaps RELT was in the table for some other reason and + it has no related values recorded. */ + if (p == 0) + return 0; + } + + /* Note: OFFSET may be 0 if P->xexp and X are related by commutativity. */ + offset = (get_integer_term (x) - get_integer_term (p->exp)); + addr = plus_constant (p->first_same_value->exp, offset); + if (memory_address_p (QImode, addr)) + return addr; + return 0; +} + +/* Hash an rtx. We are careful to make sure the value is never negative. + Equivalent registers hash identically. + MODE is used in hashing for CONST_INTs only; + otherwise the mode of X is used. + + Store 1 in do_not_record if any subexpression is volatile. + + Store 1 in hash_arg_in_memory if X contains a MEM rtx + which does not have the RTX_UNCHANGING_P bit set. + In this case, also store 1 in hash_arg_in_struct + if there is a MEM rtx which has the MEM_IN_STRUCT_P bit set. + + Note that cse_insn knows that the hash code of a MEM expression + is just (int) MEM plus the hash code of the address. + It also knows it can use HASHREG to get the hash code of (REG n). */ + +#define HASHBITS 16 + +#define HASHREG(RTX) \ + ((((int) REG << 7) + reg_qty[REGNO (RTX)]) % NBUCKETS) + +static int +canon_hash (x, mode) + rtx x; + enum machine_mode mode; +{ + register int i, j; + register int hash = 0; + register enum rtx_code code; + register 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: + { + /* We do not invalidate anything on pushing or popping + because they cannot change anything but the stack pointer; + but that means we must consider the stack pointer volatile + since it can be changed "mysteriously". */ + + register int regno = REGNO (x); + if (regno == STACK_POINTER_REGNUM + || (regno < FIRST_PSEUDO_REGISTER && global_regs[regno])) + { + do_not_record = 1; + return 0; + } +#ifdef SMALL_REGISTER_CLASSES + if (regno < FIRST_PSEUDO_REGISTER) + { + do_not_record = 1; + return 0; + } +#endif + return hash + ((int) REG << 7) + reg_qty[regno]; + } + + case CONST_INT: + hash += ((int) mode + ((int) CONST_INT << 7) + + INTVAL (x) + (INTVAL (x) >> HASHBITS)); + return ((1 << HASHBITS) - 1) & hash; + + case CONST_DOUBLE: + /* This is like the general case, except that it only counts + the first two elements. */ + hash += (int) code + (int) GET_MODE (x); + { + int i; + for (i = 2; i < GET_RTX_LENGTH (CONST_DOUBLE); i++) + { + int tem = XINT (x, i); + hash += ((1 << HASHBITS) - 1) & (tem + (tem >> HASHBITS)); + } + } + return hash; + + /* Assume there is only one rtx object for any given label. */ + case LABEL_REF: + /* Use `and' to ensure a positive number. */ + return (hash + ((int) LABEL_REF << 7) + + ((int) XEXP (x, 0) & ((1 << HASHBITS) - 1))); + + case SYMBOL_REF: + return (hash + ((int) SYMBOL_REF << 7) + + ((int) XEXP (x, 0) & ((1 << HASHBITS) - 1))); + + case MEM: + if (MEM_VOLATILE_P (x)) + { + do_not_record = 1; + return 0; + } + if (! RTX_UNCHANGING_P (x)) + { + hash_arg_in_memory = 1; + if (MEM_IN_STRUCT_P (x)) hash_arg_in_struct = 1; + } + /* Now that we have already found this special case, + might as well speed it up as much as possible. */ + hash += (int) 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: + do_not_record = 1; + return 0; + + case ASM_OPERANDS: + if (MEM_VOLATILE_P (x)) + { + do_not_record = 1; + return 0; + } + } + + i = GET_RTX_LENGTH (code) - 1; + hash += (int) code + (int) GET_MODE (x); + fmt = GET_RTX_FORMAT (code); + for (; 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; + } + hash += canon_hash (XEXP (x, i), 0); + } + else if (fmt[i] == 'E') + for (j = 0; j < XVECLEN (x, i); j++) + hash += canon_hash (XVECEXP (x, i, j), 0); + else if (fmt[i] == 's') + { + register char *p = XSTR (x, i); + if (p) + while (*p) + { + register int tem = *p++; + hash += ((1 << HASHBITS) - 1) & (tem + (tem >> HASHBITS)); + } + } + else + { + register int tem = XINT (x, i); + hash += ((1 << HASHBITS) - 1) & (tem + (tem >> HASHBITS)); + } + } + return hash; +} + +/* Like canon_hash but with no side effects. */ + +static int +safe_hash (x, mode) + rtx x; + enum machine_mode mode; +{ + 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; + int hash = canon_hash (x, mode); + hash_arg_in_memory = save_hash_arg_in_memory; + hash_arg_in_struct = save_hash_arg_in_struct; + do_not_record = save_do_not_record; + return hash; +} + +/* Return 1 iff X and Y would canonicalize into the same thing, + without actually constructing the canonicalization of either one. + If VALIDATE is nonzero, + we assume X is an expression being processed from the rtl + and Y was found in the hash table. We check register refs + in Y for being marked as valid. */ + +static int +exp_equiv_p (x, y, validate) + rtx x, y; + int validate; +{ + register int i; + register enum rtx_code code; + register char *fmt; + + /* Note: it is incorrect to assume an expression is equivalent to itself + if VALIDATE is nonzero. */ + if (x == y && !validate) + return 1; + if (x == 0 || y == 0) + return x == y; + code = GET_CODE (x); + if (code != GET_CODE (y)) + return 0; + + switch (code) + { + case PC: + case CC0: + return x == y; + + case CONST_INT: + return XINT (x, 0) == XINT (y, 0); + + case LABEL_REF: + case SYMBOL_REF: + return XEXP (x, 0) == XEXP (y, 0); + + case REG: + return (reg_qty[REGNO (x)] == reg_qty[REGNO (y)] + && (!validate + || reg_in_table[REGNO (y)] == reg_tick[REGNO (y)])); + } + + /* (MULT:SI x y) and (MULT:HI x y) are NOT equivalent. */ + + if (GET_MODE (x) != GET_MODE (y)) + return 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--) + { + if (fmt[i] == 'e') + { + if (! exp_equiv_p (XEXP (x, i), XEXP (y, i), validate)) + return 0; + } + else if (fmt[i] == 'E') + { + int j; + if (XVECLEN (x, i) != XVECLEN (y, i)) + return 0; + for (j = 0; j < XVECLEN (x, i); j++) + if (! exp_equiv_p (XVECEXP (x, i, j), XVECEXP (y, i, j), validate)) + return 0; + } + else if (fmt[i] == 's') + { + if (strcmp (XSTR (x, i), XSTR (y, i))) + return 0; + } + else + { + if (XINT (x, i) != XINT (y, i)) + return 0; + } + } + return 1; +} + +/* Return 1 iff any subexpression of X matches Y. + Here we do not require that X or Y be valid (for registers referred to) + for being in the hash table. */ + +int +refers_to_p (x, y) + rtx x, y; +{ + register int i; + register enum rtx_code code; + register char *fmt; + + repeat: + if (x == y) + return 1; + if (x == 0 || y == 0) + return 0; + + code = GET_CODE (x); + /* If X as a whole has the same code as Y, they may match. + If so, return 1. */ + if (code == GET_CODE (y)) + { + if (exp_equiv_p (x, y, 0)) + return 1; + } + + /* 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_p (XEXP (x, i), y)) + return 1; + } + else if (fmt[i] == 'E') + { + int j; + for (j = 0; j < XVECLEN (x, i); j++) + if (refers_to_p (XVECEXP (x, i, j), y)) + return 1; + } + + return 0; +} + +/* Return 1 iff any subexpression of X refers to memory + at an address of REG 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. + 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. */ + +int +refers_to_mem_p (x, reg, start, end) + rtx x, reg; + int start, end; +{ + register int i; + register enum rtx_code code; + register char *fmt; + + if (GET_CODE (reg) == CONST_INT) + { + start += INTVAL (reg); + end += INTVAL (reg); + reg = const0_rtx; + } + + repeat: + if (x == 0) + return 0; + + code = GET_CODE (x); + if (code == MEM) + { + register rtx addr = XEXP (x, 0); /* Get the address. */ + int myend; + if (GET_CODE (addr) == REG + /* qty_const is 0 when outside the cse pass; + at such times, this info is not available. */ + && qty_const != 0 + && qty_const[reg_qty[REGNO (addr)]] != 0) + addr = qty_const[reg_qty[REGNO (addr)]]; + if (GET_CODE (addr) == CONST) + addr = XEXP (addr, 0); + + /* If ADDR is BASE, or BASE plus an integer, put + the integer in I. */ + if (addr == reg) + i = 0; + else if (GET_CODE (addr) == PLUS + && XEXP (addr, 0) == reg + && GET_CODE (XEXP (addr, 1)) == CONST_INT) + i = INTVAL (XEXP (addr, 1)); + else if (GET_CODE (addr) == CONST_INT && reg == const0_rtx) + i = INTVAL (addr); + else + return 0; + + myend = i + GET_MODE_SIZE (GET_MODE (x)); + return myend > start && i < 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), reg, 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), reg, 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. */ + +static int +cse_rtx_addr_varies_p (x) + rtx x; +{ + if (GET_CODE (x) == MEM + && GET_CODE (XEXP (x, 0)) == REG + && qty_const[reg_qty[REGNO (XEXP (x, 0))]] != 0) + return 0; + return rtx_addr_varies_p (x); +} + +/* Canonicalize an expression: + replace each register reference inside it + with the "oldest" equivalent register. */ + +static rtx +canon_reg (x) + rtx x; +{ + register int i; + register enum rtx_code code; + register char *fmt; + + if (x == 0) + return x; + + 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 x; + + case REG: + { + register rtx new; + /* Never replace a hard reg, because hard regs can appear + in more than one machine mode, and we must preserve the mode + of each occurrence. Also, some hard regs appear in + MEMs that are shared and mustn't be altered. */ + if (REGNO (x) < FIRST_PSEUDO_REGISTER) + return x; + new = reg_rtx[qty_first_reg[reg_qty[REGNO (x)]]]; + return new ? new : x; + } + } + + fmt = GET_RTX_FORMAT (code); + for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) + { + register int j; + + if (fmt[i] == 'e') + XEXP (x, i) = canon_reg (XEXP (x, i)); + else if (fmt[i] == 'E') + for (j = 0; j < XVECLEN (x, i); j++) + XVECEXP (x, i, j) = canon_reg (XVECEXP (x, i, j)); + } + + return x; +} + +/* If X is a nontrivial arithmetic operation on an argument + for which a constant value can be determined, return + the result of operating on that value, as a constant. + Otherwise, return X, possibly with one or more operands + modified by recursive calls to this function. + + If X is a register whose contents are known, we do NOT + return those contents. This is because an instruction that + uses a register is usually faster than one that uses a constant. + + COPYFLAG is nonzero for memory addresses and subexpressions thereof. + If COPYFLAG is nonzero, we avoid altering X itself + by creating new structure when necessary. In this case we + can risk creating invalid structure because it will be tested. + If COPYFLAG is zero, be careful not to substitute constants + into expressions that cannot be simplified. */ + +static rtx +fold_rtx (x, copyflag) + rtx x; + int copyflag; +{ + register enum rtx_code code; + register char *fmt; + register int i, val; + rtx new = 0; + int copied = ! copyflag; + int width; + + /* Constant equivalents of first three operands of X; + 0 when no such equivalent is known. */ + rtx const_arg0; + rtx const_arg1; + rtx const_arg2; + + if (x == 0) + return x; + + width = GET_MODE_BITSIZE (GET_MODE (x)); + + code = GET_CODE (x); + switch (code) + { + case CONST: + case CONST_INT: + case CONST_DOUBLE: + case SYMBOL_REF: + case LABEL_REF: + case PC: + case CC0: + case REG: + /* No use simplifying an EXPR_LIST + since they are used only for lists of args + in a function call's REG_EQUAL note. */ + case EXPR_LIST: + return x; + + /* We must be careful when folding a memory address + to avoid making it invalid. So fold nondestructively + and use the result only if it's valid. */ + case MEM: + { + rtx newaddr = fold_rtx (XEXP (x, 0), 1); + /* Save time if no change was made. */ + if (XEXP (x, 0) == newaddr) + return x; + + if (! memory_address_p (GET_MODE (x), newaddr) + && memory_address_p (GET_MODE (x), XEXP (x, 0))) + return x; + + /* Don't replace a value with a more expensive one. */ + if (rtx_cost (XEXP (x, 0)) < rtx_cost (newaddr)) + return x; + + if (copyflag) + return gen_rtx (MEM, GET_MODE (x), newaddr); + XEXP (x, 0) = newaddr; + return x; + } + } + + const_arg0 = 0; + const_arg1 = 0; + const_arg2 = 0; + + /* Try folding our operands. + Then see which ones have constant values known. */ + + fmt = GET_RTX_FORMAT (code); + for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) + if (fmt[i] == 'e') + { + register rtx tem = fold_rtx (XEXP (x, i), copyflag); + + /* If an operand has changed under folding, and we are not supposed to + alter the original structure, copy X if we haven't yet done so. */ + if (! copied && tem != XEXP (x, i)) + { + int j; + rtx new = rtx_alloc (code); + PUT_MODE (new, GET_MODE (x)); + for (j = 0; j < GET_RTX_LENGTH (code); j++) + XINT (new, j) = XINT (x, j); + x = new; + copied = 1; + } + + /* Install the possibly altered folded operand. */ + XEXP (x, i) = tem; + + /* For the first three operands, see if the operand + is constant or equivalent to a constant. */ + if (i < 3) + { + rtx const_arg = equiv_constant (tem); + + switch (i) + { + case 0: + const_arg0 = const_arg; + break; + case 1: + const_arg1 = const_arg; + break; + case 2: + const_arg2 = const_arg; + break; + } + } + } + else if (fmt[i] == 'E') + /* Don't try to fold inside of a vector of expressions. + Doing nothing is is harmless. */ + ; + + /* If a commutative operation, place a constant integer as the second + operand unless the first operand is also a constant integer. Otherwise, + place any constant second unless the first operand is also a constant. */ + + switch (code) + { + case PLUS: + case MULT: + case UMULT: + case AND: + case IOR: + case XOR: + case NE: + case EQ: + if (const_arg0 && const_arg0 == XEXP (x, 0) + && (! (const_arg1 && const_arg1 == XEXP (x, 1)) + || (GET_CODE (const_arg0) == CONST_INT + && GET_CODE (const_arg1) != CONST_INT))) + { + register rtx tem; + + if (! copied) + copied = 1, x = copy_rtx (x); + tem = XEXP (x, 0); XEXP (x, 0) = XEXP (x, 1); XEXP (x, 1) = tem; + tem = const_arg0; const_arg0 = const_arg1; const_arg1 = tem; + } + break; + } + + /* Now decode the kind of rtx X is + and then return X (if nothing can be done) + or return a folded rtx + or store a value in VAL and drop through + (to return a CONST_INT for the integer VAL). */ + + if (GET_RTX_LENGTH (code) == 1) + { + if (const_arg0 == 0) + return x; + + if (GET_CODE (const_arg0) == CONST_INT) + { + register int arg0 = INTVAL (const_arg0); + + switch (GET_CODE (x)) + { + case NOT: + val = ~ arg0; + break; + + case NEG: + val = - arg0; + break; + + case TRUNCATE: + val = arg0; + break; + + case ZERO_EXTEND: + { + enum machine_mode mode = GET_MODE (XEXP (x, 0)); + if (mode == VOIDmode) + return x; + if (GET_MODE_BITSIZE (mode) < HOST_BITS_PER_INT) + val = arg0 & ~((-1) << GET_MODE_BITSIZE (mode)); + else + return x; + break; + } + + case SIGN_EXTEND: + { + enum machine_mode mode = GET_MODE (XEXP (x, 0)); + if (mode == VOIDmode) + return x; + if (GET_MODE_BITSIZE (mode) < HOST_BITS_PER_INT) + { + val = arg0 & ~((-1) << GET_MODE_BITSIZE (mode)); + if (val & (1 << (GET_MODE_BITSIZE (mode) - 1))) + val -= 1 << GET_MODE_BITSIZE (mode); + } + else + return x; + break; + } + + default: + return x; + } + } +#if ! defined (REAL_IS_NOT_DOUBLE) || defined (REAL_ARITHMETIC) + else if (GET_CODE (const_arg0) == CONST_DOUBLE + && GET_CODE (x) == NEG + && GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT) + { + union real_extract u; + register REAL_VALUE_TYPE arg0; + jmp_buf handler; + + if (setjmp (handler)) + { + warning ("floating point trap in constant folding"); + return x; + } + set_float_handler (handler); + bcopy (&CONST_DOUBLE_LOW (const_arg0), &u, sizeof u); + arg0 = u.d; + + u.d = REAL_VALUE_NEGATE (arg0); + x = immed_real_const_1 (u.d, GET_MODE (x)); + set_float_handler (0); + return x; + } +#endif + else + return x; + } + else if (GET_RTX_LENGTH (code) == 2) + { + register int arg0, arg1, arg0s, arg1s; + int arithwidth = width; + + /* If 1st arg is the condition codes, 2nd must be zero + and this must be a comparison. + Decode the info on how the previous insn set the cc0 + and use that to deduce result of comparison. */ + if (XEXP (x, 0) == cc0_rtx + || GET_CODE (XEXP (x, 0)) == COMPARE) + { + if (XEXP (x, 0) == cc0_rtx) + arg0 = prev_insn_cc0; + else + arg0 = fold_cc0 (VOIDmode, XEXP (x, 0)); + + if (arg0 == 0 + || const_arg1 != const0_rtx + /* 0200 bit in arg0 means only zeroness is known, + and sign is not known. */ + || ((arg0 & 0200) != 0 && code != EQ && code != NE)) + return x; + + /* Extract either the signed or the unsigned digit from ARG0. */ + if (code == LEU || code == LTU || code == GEU || code == GTU) + arg0 = arg0 & 7; + else + arg0 = (arg0 >> 3) & 7; + if (arg0 == 7) arg0 = -1; + + switch (code) + { + case LE: + case LEU: + return (arg0 <= 0) ? const1_rtx : const0_rtx; + case LT: + case LTU: + return (arg0 < 0) ? const1_rtx : const0_rtx; + case GE: + case GEU: + return (arg0 >= 0) ? const1_rtx : const0_rtx; + case GT: + case GTU: + return (arg0 > 0) ? const1_rtx : const0_rtx; + case NE: + return (arg0 != 0) ? const1_rtx : const0_rtx; + case EQ: + return (arg0 == 0) ? const1_rtx : const0_rtx; + default: + abort (); + } + } + + if (const_arg0 == 0 || const_arg1 == 0 + || GET_CODE (const_arg0) != CONST_INT + || GET_CODE (const_arg1) != CONST_INT) + { + /* Even if we can't compute a constant result, + there are some cases worth simplifying. */ + /* Note that we cannot rely on constant args to come last, + even for commutative operators, + because that happens only when the constant is explicit. */ + switch (code) + { + case PLUS: + if (const_arg0 == const0_rtx + || const_arg0 == fconst0_rtx + || const_arg0 == dconst0_rtx) + return XEXP (x, 1); + if (const_arg1 == const0_rtx + || const_arg1 == fconst0_rtx + || const_arg1 == dconst0_rtx) + return XEXP (x, 0); + + /* Handle both-operands-constant cases. */ + if (const_arg0 != 0 && const_arg1 != 0 + && GET_CODE (const_arg0) != CONST_DOUBLE + && GET_CODE (const_arg1) != CONST_DOUBLE + && GET_MODE_CLASS (GET_MODE (x)) == MODE_INT) + { + if (GET_CODE (const_arg1) == CONST_INT) + new = plus_constant (const_arg0, INTVAL (const_arg1)); + else + { + new = gen_rtx (PLUS, GET_MODE (x), const0_rtx, const0_rtx); + XEXP (new, 0) = const_arg0; + if (GET_CODE (const_arg0) == CONST) + XEXP (new, 0) = XEXP (const_arg0, 0); + XEXP (new, 1) = const_arg1; + if (GET_CODE (const_arg1) == CONST) + XEXP (new, 1) = XEXP (const_arg1, 0); + new = gen_rtx (CONST, GET_MODE (new), new); + } + } + else if (const_arg1 != 0 + && GET_CODE (const_arg1) == CONST_INT + && GET_CODE (XEXP (x, 0)) == PLUS + && (CONSTANT_P (XEXP (XEXP (x, 0), 0)) + || CONSTANT_P (XEXP (XEXP (x, 0), 1)))) + /* constant + (variable + constant) + can result if an index register is made constant. + We simplify this by adding the constants. + If we did not, it would become an invalid address. */ + new = plus_constant (XEXP (x, 0), + INTVAL (const_arg1)); + break; + + case COMPARE: + if (const_arg1 == const0_rtx) + return XEXP (x, 0); + + if (XEXP (x, 0) == XEXP (x, 1) + || (const_arg0 != 0 && const_arg0 == const_arg1)) + { + /* We can't assume x-x is 0 with IEEE floating point. */ + if (GET_MODE_CLASS (GET_MODE (x)) == MODE_INT) + return const0_rtx; + } + break; + + case MINUS: + if (const_arg1 == const0_rtx + || const_arg1 == fconst0_rtx + || const_arg1 == dconst0_rtx) + return XEXP (x, 0); + + if (XEXP (x, 0) == XEXP (x, 1) + || (const_arg0 != 0 && const_arg0 == const_arg1)) + { + /* We can't assume x-x is 0 with IEEE floating point. */ + if (GET_MODE_CLASS (GET_MODE (x)) == MODE_INT) + return const0_rtx; + } + + /* Change subtraction from zero into negation. */ + if (const_arg0 == const0_rtx) + return gen_rtx (NEG, GET_MODE (x), XEXP (x, 1)); + + /* Don't let a relocatable value get a negative coeff. */ + if (const_arg0 != 0 && const_arg1 != 0 + && GET_CODE (const_arg1) == CONST_INT) + new = plus_constant (const_arg0, - INTVAL (const_arg1)); + break; + + case MULT: + case UMULT: + if (const_arg1 && GET_CODE (const_arg1) == CONST_INT + && INTVAL (const_arg1) == -1 + /* Don't do this in the case of widening multiplication. */ + && GET_MODE (XEXP (x, 0)) == GET_MODE (x)) + return gen_rtx (NEG, GET_MODE (x), XEXP (x, 0)); + if (const_arg0 && GET_CODE (const_arg0) == CONST_INT + && INTVAL (const_arg0) == -1 + && GET_MODE (XEXP (x, 1)) == GET_MODE (x)) + return gen_rtx (NEG, GET_MODE (x), XEXP (x, 1)); + if (const_arg1 == const0_rtx || const_arg0 == const0_rtx) + new = const0_rtx; + if (const_arg1 == fconst0_rtx || const_arg0 == fconst0_rtx) + new = fconst0_rtx; + if (const_arg1 == dconst0_rtx || const_arg0 == dconst0_rtx) + new = dconst0_rtx; + if (const_arg1 == const1_rtx) + return XEXP (x, 0); + if (const_arg0 == const1_rtx) + return XEXP (x, 1); + break; + + case IOR: + if (const_arg1 == const0_rtx) + return XEXP (x, 0); + if (const_arg0 == const0_rtx) + return XEXP (x, 1); + if (const_arg1 && GET_CODE (const_arg1) == CONST_INT + && (INTVAL (const_arg1) & GET_MODE_MASK (GET_MODE (x))) + == GET_MODE_MASK (GET_MODE (x))) + new = const_arg1; + if (const_arg0 && GET_CODE (const_arg0) == CONST_INT + && (INTVAL (const_arg0) & GET_MODE_MASK (GET_MODE (x))) + == GET_MODE_MASK (GET_MODE (x))) + new = const_arg0; + break; + + case XOR: + if (const_arg1 == const0_rtx) + return XEXP (x, 0); + if (const_arg0 == const0_rtx) + return XEXP (x, 1); + if (const_arg1 && GET_CODE (const_arg1) == CONST_INT + && (INTVAL (const_arg1) & GET_MODE_MASK (GET_MODE (x))) + == GET_MODE_MASK (GET_MODE (x))) + return gen_rtx (NOT, GET_MODE (x), XEXP (x, 0)); + if (const_arg0 && GET_CODE (const_arg0) == CONST_INT + && (INTVAL (const_arg0) & GET_MODE_MASK (GET_MODE (x))) + == GET_MODE_MASK (GET_MODE (x))) + return gen_rtx (NOT, GET_MODE (x), XEXP (x, 1)); + break; + + case AND: + if (const_arg1 == const0_rtx || const_arg0 == const0_rtx) + new = const0_rtx; + if (const_arg1 && GET_CODE (const_arg1) == CONST_INT + && (INTVAL (const_arg1) & GET_MODE_MASK (GET_MODE (x))) + == GET_MODE_MASK (GET_MODE (x))) + return XEXP (x, 0); + if (const_arg0 && GET_CODE (const_arg0) == CONST_INT + && (INTVAL (const_arg0) & GET_MODE_MASK (GET_MODE (x))) + == GET_MODE_MASK (GET_MODE (x))) + return XEXP (x, 1); + break; + + case DIV: + case UDIV: + if (const_arg1 == const1_rtx) + return XEXP (x, 0); + if (const_arg0 == const0_rtx) + new = const0_rtx; + break; + + case UMOD: + case MOD: + if (const_arg0 == const0_rtx || const_arg1 == const1_rtx) + new = const0_rtx; + break; + + case LSHIFT: + case ASHIFT: + case ROTATE: + case ASHIFTRT: + case LSHIFTRT: + case ROTATERT: + if (const_arg1 == const0_rtx) + return XEXP (x, 0); + if (const_arg0 == const0_rtx) + new = const_arg0; + break; + } + + if (new != 0 && LEGITIMATE_CONSTANT_P (new)) + return new; + return x; + } + + if (arithwidth == 0) + { + if (GET_MODE (XEXP (x, 0)) != VOIDmode) + arithwidth = GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0))); + if (GET_MODE (XEXP (x, 1)) != VOIDmode) + arithwidth = GET_MODE_BITSIZE (GET_MODE (XEXP (x, 1))); + } + + /* Get the integer argument values in two forms: + zero-extended in ARG0, ARG1 and sign-extended in ARG0S, ARG1S. */ + + arg0 = INTVAL (const_arg0); + arg1 = INTVAL (const_arg1); + + if (arithwidth < HOST_BITS_PER_INT && arithwidth > 0) + { + arg0 &= (1 << arithwidth) - 1; + arg1 &= (1 << arithwidth) - 1; + + arg0s = arg0; + if (arg0s & (1 << (arithwidth - 1))) + arg0s |= ((-1) << arithwidth); + + arg1s = arg1; + if (arg1s & (1 << (arithwidth - 1))) + arg1s |= ((-1) << arithwidth); + } + else + { + arg0s = arg0; + arg1s = arg1; + } + + /* Compute the value of the arithmetic. */ + + switch (code) + { + case PLUS: + val = arg0 + arg1; + break; + + case MINUS: + val = arg0 - arg1; + break; + + case MULT: + val = arg0s * arg1s; + break; + + case DIV: + if (arg1s == 0) + return x; + val = arg0s / arg1s; + break; + + case MOD: + if (arg1s == 0) + return x; + val = arg0s % arg1s; + break; + + case UMULT: + val = (unsigned) arg0 * arg1; + break; + + case UDIV: + if (arg1 == 0) + return x; + val = (unsigned) arg0 / arg1; + break; + + case UMOD: + if (arg1 == 0) + return x; + val = (unsigned) arg0 % arg1; + break; + + case AND: + val = arg0 & arg1; + break; + + case IOR: + val = arg0 | arg1; + break; + + case XOR: + val = arg0 ^ arg1; + break; + + case NE: + val = arg0 != arg1; + break; + + case EQ: + val = arg0 == arg1; + break; + + case LE: + val = arg0s <= arg1s; + break; + + case LT: + val = arg0s < arg1s; + break; + + case GE: + val = arg0s >= arg1s; + break; + + case GT: + val = arg0s > arg1s; + break; + + case LEU: + val = ((unsigned) arg0) <= ((unsigned) arg1); + break; + + case LTU: + val = ((unsigned) arg0) < ((unsigned) arg1); + break; + + case GEU: + val = ((unsigned) arg0) >= ((unsigned) arg1); + break; + + case GTU: + val = ((unsigned) arg0) > ((unsigned) arg1); + break; + + case LSHIFT: + /* If target machine uses negative shift counts + but host machine does not, simulate them. */ + if (arg1 < 0) + val = ((unsigned) arg0) >> -arg1; + else + val = ((unsigned) arg0) << arg1; + break; + + case ASHIFT: + if (arg1 < 0) + val = arg0s >> -arg1; + else + val = arg0s << arg1; + break; + + case ROTATERT: + arg1 = - arg1; + case ROTATE: + { + int size = GET_MODE_SIZE (GET_MODE (x)) * BITS_PER_UNIT; + if (arg1 > 0) + { + arg1 %= size; + val = ((((unsigned) arg0) << arg1) + | (((unsigned) arg0) >> (size - arg1))); + } + else if (arg1 < 0) + { + arg1 = (- arg1) % size; + val = ((((unsigned) arg0) >> arg1) + | (((unsigned) arg0) << (size - arg1))); + } + else + val = arg0; + } + break; + + case LSHIFTRT: + /* If target machine uses negative shift counts + but host machine does not, simulate them. */ + if (arg1 < 0) + val = ((unsigned) arg0) << -arg1; + else + val = ((unsigned) arg0) >> arg1; + break; + + case ASHIFTRT: + if (arg1 < 0) + val = arg0s << -arg1; + else + val = arg0s >> arg1; + break; + + default: + return x; + } + } + else if (code == IF_THEN_ELSE && const_arg0 != 0 + && GET_CODE (const_arg0) == CONST_INT) + return XEXP (x, ((INTVAL (const_arg0) != 0) ? 1 : 2)); + else if (code == IF_THEN_ELSE && XEXP (x, 0) == cc0_rtx + && prev_insn_explicit_cc0 != 0) + return XEXP (x, ((INTVAL (prev_insn_explicit_cc0) != 0) ? 1 : 2)); + else if (code == SIGN_EXTRACT || code == ZERO_EXTRACT) + { + if (const_arg0 != 0 && const_arg1 != 0 && const_arg2 != 0 + && GET_CODE (const_arg0) == CONST_INT + && GET_CODE (const_arg1) == CONST_INT + && GET_CODE (const_arg2) == CONST_INT) + { + /* Extracting a bit-field from a constant */ + val = INTVAL (const_arg0); +#ifdef BITS_BIG_ENDIAN + val >>= (GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0))) + - INTVAL (const_arg2) - INTVAL (const_arg1)); +#else + val >>= INTVAL (const_arg2); +#endif + if (HOST_BITS_PER_INT != INTVAL (const_arg1)) + { + /* First zero-extend. */ + val &= (1 << INTVAL (const_arg1)) - 1; + /* If desired, propagate sign bit. */ + if (code == SIGN_EXTRACT + && (val & (1 << (INTVAL (const_arg1) - 1)))) + val |= ~ (1 << INTVAL (const_arg1)); + } + } + else + return x; + } + else + return x; + + /* 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 (width < HOST_BITS_PER_INT && width > 0) + { + if ((val & ((-1) << (width - 1))) + != ((-1) << (width - 1))) + val &= (1 << width) - 1; + } + + /* Now make the new constant. */ + { + rtx new = gen_rtx (CONST_INT, VOIDmode, val); + return LEGITIMATE_CONSTANT_P (new) ? new : x; + } +} + +/* Return a constant value currently equivalent to X. + Return 0 if we don't know one. */ + +static rtx +equiv_constant (x) + rtx x; +{ + rtx tem1; + + if (CONSTANT_P (x) || GET_CODE (x) == CONST_DOUBLE) + return x; + else if (GET_CODE (x) == REG + && (tem1 = qty_const[reg_qty[REGNO (x)]]) != 0 + /* Make sure it is really a constant */ + && GET_CODE (tem1) != REG && GET_CODE (tem1) != PLUS) + return tem1; + /* If integer truncation is being done with SUBREG, + we can compute the result. */ + else if (GET_CODE (x) == SUBREG && SUBREG_WORD (x) == 0 + && (tem1 = qty_const[reg_qty[REGNO (SUBREG_REG (x))]]) != 0 + /* Make sure it is a known integer. */ + && GET_CODE (tem1) == CONST_INT + && GET_MODE_SIZE (GET_MODE (x)) <= HOST_BITS_PER_INT + /* Make sure this SUBREG is truncation. */ + && GET_MODE_SIZE (GET_MODE (x)) < GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))) + { + int value = INTVAL (tem1); + if (GET_MODE_BITSIZE (GET_MODE (x)) != HOST_BITS_PER_INT) + value &= (1 << GET_MODE_BITSIZE (GET_MODE (x))) - 1; + + if (value == INTVAL (tem1)) + return tem1; + else + return gen_rtx (CONST_INT, VOIDmode, value); + } + return 0; +} + +/* Given an expression X which is used to set CC0, + return an integer recording (in the encoding used for prev_insn_cc0) + how the condition codes would be set by that expression. + Return 0 if the value is not constant + or if there is any doubt what condition codes result from it. + + MODE is the machine mode to use to interpret X if it is a CONST_INT. */ + +static int +fold_cc0 (mode, x) + enum machine_mode mode; + rtx x; +{ + if (GET_CODE (x) == COMPARE) + { + rtx y0 = fold_rtx (XEXP (x, 0), 0); + rtx y1 = fold_rtx (XEXP (x, 1), 0); + int u0, u1, s0, s1; + enum machine_mode m; + rtx tem; + + m = GET_MODE (y0); + if (m == VOIDmode) + m = GET_MODE (y1); + if (m == VOIDmode) + return 0; + + tem = equiv_constant (y0); + if (tem != 0) + y0 = tem; + + if (y0 == 0) + return 0; + + tem = equiv_constant (y1); + if (tem != 0) + y1 = tem; + + if (y1 == 0) + return 0; + + /* Compare floats; report the result only for signed compares + since that's all there are for floats. */ + if (GET_CODE (y0) == CONST_DOUBLE + && GET_CODE (y1) == CONST_DOUBLE + && GET_MODE_CLASS (GET_MODE (y0)) == MODE_FLOAT) + { + union real_extract u0, u1; + int value; + jmp_buf handler; + + if (setjmp (handler)) + { + warning ("floating point trap in constant folding"); + return 0; + } + set_float_handler (handler); + bcopy (&CONST_DOUBLE_LOW (y0), &u0, sizeof u0); + bcopy (&CONST_DOUBLE_LOW (y1), &u1, sizeof u1); + value = 0100 + (REAL_VALUES_LESS (u0.d, u1.d) ? 7 << 3 + : REAL_VALUES_LESS (u1.d, u0.d) ? 1 << 3 : 0); + set_float_handler (0); + return value; + } + + /* Aside from that, demand explicit integers. */ + + if (GET_CODE (y0) != CONST_INT) + return 0; + + if (GET_CODE (y1) != CONST_INT) + return 0; + + s0 = u0 = INTVAL (y0); + s1 = u1 = INTVAL (y1); + + { + int width = GET_MODE_BITSIZE (m); + if (width < HOST_BITS_PER_INT) + { + s0 = u0 &= ~ ((-1) << width); + s1 = u1 &= ~ ((-1) << width); + if (u0 & (1 << (width - 1))) + s0 |= ((-1) << width); + if (u1 & (1 << (width - 1))) + s1 |= ((-1) << width); + } + } + + return 0100 + ((s0 < s1 ? 7 : s0 > s1) << 3) + + (((unsigned) u0 < (unsigned) u1) ? 7 + : ((unsigned) u0 > (unsigned) u1)); + } + { + rtx y0; + int u0, s0; + enum machine_mode m; + + y0 = fold_rtx (x, 0); + + m = GET_MODE (y0); + if (m == VOIDmode) + m = mode; + + if (GET_CODE (y0) == REG) + y0 = qty_const[reg_qty[REGNO (y0)]]; + + /* Register had no constant equivalent? We can't do anything. */ + if (y0 == 0) + return 0; + + /* If we don't know the mode, we can't test the sign. */ + if (m == VOIDmode) + return 0; + + /* Value is frame-pointer plus a constant? Or non-explicit constant? + That isn't zero, but we don't know its sign. */ + if (FIXED_BASE_PLUS_P (y0) + || GET_CODE (y0) == SYMBOL_REF || GET_CODE (y0) == CONST + || GET_CODE (y0) == LABEL_REF) + return 0300 + (1<<3) + 1; + + /* Otherwise, only integers enable us to optimize. */ + if (GET_CODE (y0) != CONST_INT) + return 0; + + s0 = u0 = INTVAL (y0); + { + int width = GET_MODE_BITSIZE (m); + if (width < HOST_BITS_PER_INT) + { + s0 = u0 &= ~ ((-1) << GET_MODE_BITSIZE (m)); + if (u0 & (1 << (GET_MODE_BITSIZE (m) - 1))) + s0 |= ((-1) << GET_MODE_BITSIZE (m)); + } + } + return 0100 + ((s0 < 0 ? 7 : s0 > 0) << 3) + (u0 != 0); + } +} + +/* Attempt to prove that a loop will be executed >= 1 times, + or prove it will be executed 0 times. + If either can be proved, delete some of the code. */ + +static void +predecide_loop_entry (insn) + register rtx insn; +{ + register rtx jump = NEXT_INSN (insn); + register rtx p; + register rtx loop_top_label = NEXT_INSN (jump); + enum anon1 { UNK, DELETE_LOOP, DELETE_JUMP } disposition = UNK; + int count = 0; + + /* Give up if we don't find a jump that enters the loop. */ + if (! simplejump_p (jump)) + return; + + /* Find the label at the top of the loop. */ + while (GET_CODE (loop_top_label) == BARRIER + || GET_CODE (loop_top_label) == NOTE) + { + loop_top_label = NEXT_INSN (loop_top_label); + /* No label? Give up. */ + if (loop_top_label == 0) + return; + } + if (GET_CODE (loop_top_label) != CODE_LABEL) + abort (); + + /* Find the label at which the loop is entered. */ + p = XEXP (SET_SRC (PATTERN (jump)), 0); + if (GET_CODE (p) != CODE_LABEL) + abort (); + + /* Trace the flow of control through the end test, + propagating constants, to see if result is determined. */ + prev_insn_cc0 = 0; + prev_insn_explicit_cc0 = 0; + /* Avoid infinite loop if we find a cycle of jumps. */ + while (count < 10) + { + /* At end of function? Means rtl is inconsistent, + but this can happen when stmt.c gets confused + by a syntax error. */ + if (p == 0) + break; + /* Arriving at end of loop means endtest will drop out. */ + if (GET_CODE (p) == NOTE + && NOTE_LINE_NUMBER (p) == NOTE_INSN_LOOP_END) + { + disposition = DELETE_LOOP; + break; + } + else if (GET_CODE (p) == CODE_LABEL || GET_CODE (p) == NOTE) + ; + /* We only know how to handle two kinds of insns: + conditional jumps, and those that set the condition codes. */ + else if (GET_CODE (p) == INSN && GET_CODE (PATTERN (p)) == SET + && SET_DEST (PATTERN (p)) == cc0_rtx) + { + prev_insn_cc0 = fold_cc0 (GET_MODE (SET_SRC (PATTERN (p))), + copy_rtx (SET_SRC (PATTERN (p)))); + if (GET_CODE (SET_SRC (PATTERN (p))) == CONST_INT) + prev_insn_explicit_cc0 = SET_SRC (PATTERN (p)); + } + else if (GET_CODE (p) == JUMP_INSN + && GET_CODE (PATTERN (p)) == SET + && SET_DEST (PATTERN (p)) == pc_rtx) + { + register rtx target + = fold_rtx (SET_SRC (PATTERN (p)), 1); + if (GET_CODE (target) == LABEL_REF) + p = XEXP (target, 0); + else if (target != pc_rtx) + /* If destination of jump is not fixed, give up. */ + break; + count++; + } + /* Any other kind of insn means we don't know + what result the test will have. */ + else + break; + + /* Arriving at top of loop means we can drop straight in. + Check here because we can arrive only via a jump insn + which would have changed P above. */ + if (p == loop_top_label) + { + disposition = DELETE_JUMP; + break; + } + /* We went past one insn; consider the next. */ + p = NEXT_INSN (p); + } + if (disposition == DELETE_JUMP) + { + /* We know the loop test will succeed the first time, + so delete the jump to the test; drop right into loop. + Note that one call to delete_insn gets the BARRIER as well. */ + delete_insn (jump); + } + if (disposition == DELETE_LOOP) + { + /* We know the endtest will fail and drop right out of the loop, + but it isn't safe to delete the loop here. + There could be jumps into it from outside. + So make the entry-jump jump around the loop. + This will cause find_basic_blocks to delete it if appropriate. */ + register rtx label = gen_label_rtx (); + emit_label_after (label, p); + redirect_jump (jump, label); + } +} + +/* CSE processing for one instruction. + First simplify sources and addresses of all assignments + in the instruction, using previously-computed equivalents values. + Then install the new sources and destinations in the table + of available values. */ + +/* Data on one SET contained in the instruction. */ + +struct set +{ + /* The SET rtx itself. */ + rtx rtl; + /* The hash-table element for the SET_SRC of the SET. */ + struct table_elt *src_elt; + /* Hash code for the SET_SRC. */ + int src_hash_code; + /* Hash code for the SET_DEST. */ + int dest_hash_code; + /* The SET_DEST, with SUBREG, etc., stripped. */ + rtx inner_dest; + /* Place where the pointer to the INNER_DEST was found. */ + rtx *inner_dest_loc; + /* Nonzero if the SET_SRC is in memory. */ + char src_in_memory; + /* Nonzero if the SET_SRC is in a structure. */ + char src_in_struct; + /* Nonzero if the SET_SRC contains something + whose value cannot be predicted and understood. */ + char src_volatile; + /* Original machine mode, in case it becomes a CONST_INT. */ + enum machine_mode mode; +}; + +static void +cse_insn (insn) + rtx insn; +{ + register rtx x = PATTERN (insn); + register int i; + register int n_sets = 0; + + /* Records what this insn does to set CC0, + using same encoding used for prev_insn_cc0. */ + int this_insn_cc0 = 0; + /* Likewise, what to store in prev_insn_explicit_cc0. */ + rtx this_insn_explicit_cc0 = 0; + struct write_data writes_memory; + static struct write_data init = {0, 0, 0}; + + rtx src_eqv = 0; + struct table_elt *src_eqv_elt = 0; + int src_eqv_in_memory; + int src_eqv_in_struct; + int src_eqv_hash_code; + + 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. + Also determine whether there is a CLOBBER that invalidates + all memory references, or all references at varying addresses. */ + + if (GET_CODE (x) == SET) + { + rtx tem; + n_sets = 1; + sets = (struct set *) alloca (sizeof (struct set)); + sets[0].rtl = x; + + if (REG_NOTES (insn) != 0) + { + /* Store the equivalent value (re REG_EQUAL or REG_EQUIV) in SRC_EQV. */ + tem = find_reg_note (insn, REG_EQUIV, 0); + if (tem == 0) + tem = find_reg_note (insn, REG_EQUAL, 0); + if (tem) src_eqv = XEXP (tem, 0); + + /* Ignore the REG_EQUAL or REG_EQUIV note if its contents + are the same as the source. */ + if (src_eqv && rtx_equal_p (src_eqv, SET_SRC (x))) + src_eqv = 0; + } + + /* Return now for unconditional jumps. + They never need cse processing, so this does not hurt. + The reason is not efficiency but rather + so that we can test at the end for instructions + that have been simplified to unconditional jumps + and not be misled by unchanged instructions + that were unconditional jumps to begin with. */ + if (SET_DEST (x) == pc_rtx + && GET_CODE (SET_SRC (x)) == LABEL_REF) + return; + + /* Return now for call-insns, (set (reg 0) (call ...)). + The hard function value register is used only once, to copy to + someplace else, so it isn't worth cse'ing (and on 80386 is unsafe)! */ + if (GET_CODE (SET_SRC (x)) == CALL) + { + canon_reg (SET_SRC (x)); + return; + } + } + else if (GET_CODE (x) == PARALLEL) + { + register int lim = XVECLEN (x, 0); + + sets = (struct set *) alloca (lim * sizeof (struct set)); + + /* Find all regs explicitly clobbered in this insn, + and ensure they are not replaced with any other regs + elsewhere in this insn. + When a reg that is clobbered is also used for input, + we should presume that that is for a reason, + and we should not substitute some other register + which is not supposed to be clobbered. */ + for (i = 0; i < lim; i++) + { + register rtx y = XVECEXP (x, 0, i); + if (GET_CODE (y) == CLOBBER && GET_CODE (XEXP (y, 0)) == REG) + invalidate (XEXP (y, 0)); + } + + for (i = 0; i < lim; i++) + { + register rtx y = XVECEXP (x, 0, i); + if (GET_CODE (y) == SET) + sets[n_sets++].rtl = y; + else if (GET_CODE (y) == CLOBBER) + { + /* If we clobber memory, take note of that, + and canon the address. + This does nothing when a register is clobbered + because we have already invalidated the reg. */ + canon_reg (y); + note_mem_written (XEXP (y, 0), &writes_memory); + } + else if (GET_CODE (y) == USE + && ! (GET_CODE (XEXP (y, 0)) == REG + && REGNO (XEXP (y, 0)) < FIRST_PSEUDO_REGISTER)) + canon_reg (y); + else if (GET_CODE (y) == CALL) + canon_reg (y); + } + } + else if (GET_CODE (x) == CLOBBER) + note_mem_written (XEXP (x, 0), &writes_memory); + else if (GET_CODE (x) == CALL) + canon_reg (x); + + if (n_sets == 0) + { + invalidate_from_clobbers (&writes_memory, x); + return; + } + + /* Canonicalize sources and addresses of destinations. + set sets[i].src_elt to the class each source belongs to. + Detect assignments from or to volatile things + and set set[i] to zero so they will be ignored + in the rest of this function. + + Nothing in this loop changes the hash table or the register chains. */ + + for (i = 0; i < n_sets; i++) + { + register rtx src, dest; + register struct table_elt *elt; + enum machine_mode mode; + + dest = SET_DEST (sets[i].rtl); + src = SET_SRC (sets[i].rtl); + + /* If SRC is a constant that has no machine mode, + hash it with the destination's machine mode. + This way we can keep different modes separate. */ + + mode = GET_MODE (src) == VOIDmode ? GET_MODE (dest) : GET_MODE (src); + sets[i].mode = mode; + + /* Replace each registers in SRC with oldest equivalent register, + but if DEST is a register do not replace it if it appears in SRC. */ + + if (GET_CODE (dest) == REG) + { + int tem = reg_qty[REGNO (dest)]; + reg_qty[REGNO (dest)] = REGNO (dest); + src = canon_reg (src); + + if (src_eqv) + src_eqv = canon_reg (src_eqv); + + reg_qty[REGNO (dest)] = tem; + } + else + { + src = canon_reg (src); + + if (src_eqv) + src_eqv = canon_reg (src_eqv); + } + + if (src_eqv) + { + enum machine_mode eqvmode = mode; + if (GET_CODE (dest) == STRICT_LOW_PART) + eqvmode = GET_MODE (SUBREG_REG (XEXP (dest, 0))); + do_not_record = 0; + hash_arg_in_memory = 0; + hash_arg_in_struct = 0; + src_eqv = fold_rtx (src_eqv, 0); + src_eqv_hash_code = HASH (src_eqv, eqvmode); + + /* Replace the src_eqv with its cheapest equivalent. */ + + if (!do_not_record) + { + elt = lookup (src_eqv, src_eqv_hash_code, eqvmode); + if (elt && elt != elt->first_same_value) + { + elt = elt->first_same_value; + /* Find the cheapest one that is still valid. */ + while ((GET_CODE (elt->exp) != REG + && !exp_equiv_p (elt->exp, elt->exp, 1)) + || elt->equivalence_only) + elt = elt->next_same_value; + src_eqv = copy_rtx (elt->exp); + hash_arg_in_memory = 0; + hash_arg_in_struct = 0; + src_eqv_hash_code = HASH (src_eqv, elt->mode); + } + src_eqv_elt = elt; + } + else + src_eqv = 0; + + src_eqv_in_memory = hash_arg_in_memory; + src_eqv_in_struct = hash_arg_in_struct; + } + + /* Compute SRC's hash code, and also notice if it + should not be recorded at all. In that case, + prevent any further processing of this assignment. */ + do_not_record = 0; + hash_arg_in_memory = 0; + hash_arg_in_struct = 0; + src = fold_rtx (src, 0); + /* If SRC is a subreg of a reg with a known value, + perform the truncation now. */ + if (GET_CODE (src) == SUBREG) + { + rtx temp = equiv_constant (src); + if (temp) + src = temp; + } + /* If we have (NOT Y), see if Y is known to be (NOT Z). + If so, (NOT Y) simplifies to Z. */ + if (GET_CODE (src) == NOT || GET_CODE (src) == NEG) + { + rtx y = lookup_as_function (XEXP (src, 0), GET_CODE (src)); + if (y != 0) + src = copy_rtx (XEXP (y, 0)); + } + + /* If storing a constant value in a register that + previously held the constant value 0, + record this fact with a REG_WAS_0 note on this insn. */ + if (GET_CODE (src) == CONST_INT + && GET_CODE (dest) == REG + && qty_const[reg_qty[REGNO (dest)]] == const0_rtx) + REG_NOTES (insn) = gen_rtx (INSN_LIST, REG_WAS_0, + qty_const_insn[reg_qty[REGNO (dest)]], + REG_NOTES (insn)); + + sets[i].src_hash_code = HASH (src, mode); + + sets[i].src_volatile = do_not_record; + +#if 0 + /* This code caused multiple hash-table entries + to be created for registers. Invalidation + would only get one, leaving others that didn't belong. + I don't know what good this ever did. */ + if (GET_CODE (src) == REG) + { + sets[i].src_in_memory = 0; + sets[i].src_elt = 0; + } + else ...; +#endif + /* If source is a perverse subreg (such as QI treated as an SI), + treat it as volatile. It may do the work of an SI in one context + where the extra bits are not being used, but cannot replace an SI + in general. */ + if (GET_CODE (src) == SUBREG + && (GET_MODE_SIZE (GET_MODE (src)) + > GET_MODE_SIZE (GET_MODE (SUBREG_REG (src))))) + sets[i].src_volatile = 1; + else if (!sets[i].src_volatile) + { + /* Replace the source with its cheapest equivalent. */ + + elt = lookup (src, sets[i].src_hash_code, mode); + if (elt && elt != elt->first_same_value) + { + elt = elt->first_same_value; + /* Find the cheapest one that is still valid. */ + while ((GET_CODE (elt->exp) != REG + && !exp_equiv_p (elt->exp, elt->exp, 1)) + || elt->equivalence_only) + elt = elt->next_same_value; + /* Don't replace with things that are not likely to be valid, + such as arithmetic expressions, unless the destination is + a register. */ + if (general_operand (elt->exp, VOIDmode) + || GET_CODE (dest) == REG) + { + src = copy_rtx (elt->exp); + hash_arg_in_memory = 0; + hash_arg_in_struct = 0; + sets[i].src_hash_code = HASH (src, elt->mode); + } + } + + /* If ELT is a constant, is there a register + linearly related to it? If so, replace it + with the sum of that register plus an offset. */ + + if (GET_CODE (src) == CONST && n_sets == 1 + && SET_DEST (sets[i].rtl) != cc0_rtx) + { + rtx newsrc = use_related_value (src, elt); + if (newsrc == 0 && src_eqv != 0) + newsrc = use_related_value (src_eqv, src_eqv_elt); + if (newsrc) + { + rtx oldsrc = src; + src = newsrc; + hash_arg_in_memory = 0; + hash_arg_in_struct = 0; + sets[i].src_hash_code = HASH (src, GET_MODE (src)); + /* The new expression for the SRC has the same value + as the previous one; so if the previous one is in + the hash table, put the new one in as equivalent. */ + if (elt != 0) + elt = insert (src, elt->first_same_value, sets[i].src_hash_code, + elt->mode); + else + { + /* Maybe the new expression is in the table already. */ + elt = lookup (src, sets[i].src_hash_code, mode); + /* And maybe a register contains the same value. */ + if (elt && elt != elt->first_same_value) + { + elt = elt->first_same_value; + /* Find the cheapest one that is still valid. */ + while ((GET_CODE (elt->exp) != REG + && !exp_equiv_p (elt->exp, elt->exp, 1)) + || elt->equivalence_only) + elt = elt->next_same_value; + src = copy_rtx (elt->exp); + hash_arg_in_memory = 0; + hash_arg_in_struct = 0; + sets[i].src_hash_code = HASH (src, elt->mode); + } + } + + /* This would normally be inhibited by the REG_EQUIV + note we are about to make. */ +#if 0 + /* Deleted because the inhibition was deleted. */ + SET_SRC (sets[i].rtl) = src; +#endif + + /* Record the actual constant value + in a REG_EQUIV or REG_EQUAL note. */ + if (GET_CODE (SET_DEST (sets[i].rtl)) == REG) + { + /* A REG_EQUIV note means the dest never changes. + Don't put one on unless there is already one. */ + rtx note = find_reg_note (insn, REG_EQUIV, 0); + if (note != 0) + XEXP (note, 0) = oldsrc; + else + REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_EQUAL, + oldsrc, REG_NOTES (insn)); + } + } + } + + sets[i].src_elt = elt; + sets[i].src_in_memory = hash_arg_in_memory; + sets[i].src_in_struct = hash_arg_in_struct; + } + + /* Either canon_reg or the copy_rtx may have changed this. */ + /* Note it is not safe to replace the sources if there + is more than one set. We could get an insn + [(set (reg) (reg)) (set (reg) (reg))], which is probably + not in the machine description. + This case we could handle by breaking into several insns. + Cases of partial substitution cannot win at all. */ + /* Also, if this insn is setting a "constant" register, + we may not replace the value that is given to it. */ + if (n_sets == 1) +#if 0 + /* Now that the REG_EQUIV contains the constant instead of the reg, + it should be ok to modify the insn's actual source. */ + if (REG_NOTES (insn) == 0 + || REG_NOTE_KIND (REG_NOTES (insn)) != REG_EQUIV) +#endif + SET_SRC (sets[0].rtl) = src; + + do_not_record = 0; + sets[i].inner_dest_loc = &SET_DEST (sets[0].rtl); + + /* Look within any SIGN_EXTRACT or ZERO_EXTRACT + to the MEM or REG within it. */ + while (1) + { + if (GET_CODE (dest) == SIGN_EXTRACT + || GET_CODE (dest) == ZERO_EXTRACT) + { + XEXP (dest, 1) = canon_reg (XEXP (dest, 1)); + XEXP (dest, 2) = canon_reg (XEXP (dest, 2)); + sets[i].inner_dest_loc = &XEXP (dest, 0); + dest = XEXP (dest, 0); + } + else if (GET_CODE (dest) == SUBREG + || GET_CODE (dest) == STRICT_LOW_PART) + { + sets[i].inner_dest_loc = &XEXP (dest, 0); + dest = XEXP (dest, 0); + } + else + break; + } + + sets[i].inner_dest = dest; + + /* If storing into memory, do cse on the memory address. + Also compute the hash code of the destination now, + before the effects of this instruction are recorded, + since the register values used in the address computation + are those before this instruction. */ + if (GET_CODE (dest) == MEM) + { + register rtx addr; + register int hash; + + canon_reg (dest); + dest = fold_rtx (dest, 0); + addr = XEXP (dest, 0); + + /* Pushing or popping does not invalidate anything. */ + 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) + ; + else + /* Otherwise, 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); + + /* Do not try to replace addresses of local and argument slots. + The MEM expressions for args and non-register local variables + are made only once and inserted in many instructions, + as well as being used to control symbol table output. + It is not safe to clobber them. It also doesn't do any good! */ + if ((GET_CODE (addr) == PLUS + && GET_CODE (XEXP (addr, 0)) == REG + && GET_CODE (XEXP (addr, 1)) == CONST_INT + && (hash = REGNO (XEXP (addr, 0)), + hash == FRAME_POINTER_REGNUM || hash == ARG_POINTER_REGNUM)) + || (GET_CODE (addr) == REG + && (hash = REGNO (addr), + hash == FRAME_POINTER_REGNUM || hash == ARG_POINTER_REGNUM))) + sets[i].dest_hash_code = ((int)MEM + canon_hash (addr, GET_MODE (dest))) % NBUCKETS; + else + { + /* Look for a simpler equivalent for the destination address. */ + hash = HASH (addr, Pmode); + if (! do_not_record) + { + elt = lookup (addr, hash, Pmode); + sets[i].dest_hash_code = ((int) MEM + hash) % NBUCKETS; + + if (elt && elt != elt->first_same_value) + { + elt = elt->first_same_value; + /* Find the cheapest one that is still valid. */ + while ((GET_CODE (elt->exp) != REG + && !exp_equiv_p (elt->exp, elt->exp, 1)) + || elt->equivalence_only) + elt = elt->next_same_value; + + addr = copy_rtx (elt->exp); + /* Create a new MEM rtx, in case the old one + is shared somewhere else. */ + dest = gen_rtx (MEM, GET_MODE (dest), addr); + MEM_VOLATILE_P (dest) + = MEM_VOLATILE_P (sets[i].inner_dest); + MEM_IN_STRUCT_P (dest) + = MEM_IN_STRUCT_P (sets[i].inner_dest); + *sets[i].inner_dest_loc = dest; + sets[i].inner_dest = dest; + } + } + } + } + + /* Don't enter a bit-field in the hash table + because the value in it after the store + may not equal what was stored, due to truncation. */ + + if (GET_CODE (SET_DEST (sets[i].rtl)) == ZERO_EXTRACT + || GET_CODE (SET_DEST (sets[i].rtl)) == SIGN_EXTRACT) + { + rtx width = XEXP (SET_DEST (sets[i].rtl), 1); + rtx value = equiv_constant (SET_SRC (sets[i].rtl)); + + if (value != 0 && GET_CODE (value) == CONST_INT + && GET_CODE (width) == CONST_INT + && INTVAL (width) < HOST_BITS_PER_INT + && ! (INTVAL (value) & (-1) << INTVAL (width))) + /* Exception: if the value is constant, + we can tell whether truncation would change it. */ + ; + else + sets[i].src_volatile = 1, src_eqv = 0; + } + + /* No further processing for this assignment + if destination is volatile or if the source and destination + are the same. */ + + else if (do_not_record + || (GET_CODE (dest) == REG + ? REGNO (dest) == STACK_POINTER_REGNUM + : GET_CODE (dest) != MEM) + || rtx_equal_p (SET_SRC (sets[i].rtl), SET_DEST (sets[i].rtl))) + sets[i].rtl = 0; + + if (sets[i].rtl != 0 && dest != SET_DEST (sets[i].rtl)) + sets[i].dest_hash_code = HASH (SET_DEST (sets[i].rtl), mode); + + if (dest == cc0_rtx + && (GET_CODE (src) == COMPARE + || CONSTANT_P (src) + || GET_CODE (src) == REG)) + this_insn_cc0 = fold_cc0 (sets[i].mode, src); + + if (dest == cc0_rtx && GET_CODE (src) == CONST_INT) + this_insn_explicit_cc0 = src; + } + + /* Now enter all non-volatile source expressions in the hash table + if they are not already present. + Record in src_elt the heads of their equivalence classes. + This way we can insert the corresponding destinations into + the same classes even if the actual sources are no longer in them + (having been invalidated). */ + + if (src_eqv && src_eqv_elt == 0 && sets[0].rtl != 0) + { + register struct table_elt *elt; + rtx dest = SET_DEST (sets[0].rtl); + enum machine_mode eqvmode = GET_MODE (dest); + + if (GET_CODE (dest) == STRICT_LOW_PART) + eqvmode = GET_MODE (SUBREG_REG (XEXP (dest, 0))); + if (insert_regs (src_eqv, 0, 0)) + src_eqv_hash_code = HASH (src_eqv, eqvmode); + elt = insert (src_eqv, 0, src_eqv_hash_code, eqvmode); + elt->in_memory = src_eqv_in_memory; + elt->in_struct = src_eqv_in_struct; + elt->equivalence_only = 1; + src_eqv_elt = elt->first_same_value; + } + + for (i = 0; i < n_sets; i++) + if (sets[i].rtl && ! sets[i].src_volatile) + { + if (GET_CODE (SET_DEST (sets[i].rtl)) == STRICT_LOW_PART) + { + /* REG_EQUAL in setting a STRICT_LOW_PART + gives an equivalent for the entire destination register, + not just for the subreg being stored in now. + This is a more interesting equivalent, so we arrange later + to treat the entire reg as the destination. */ + sets[i].src_elt = src_eqv_elt; + sets[i].src_hash_code = src_eqv_hash_code; + } + else if (sets[i].src_elt == 0) + { + register rtx src = SET_SRC (sets[i].rtl); + register rtx dest = SET_DEST (sets[i].rtl); + register struct table_elt *elt; + enum machine_mode mode + = GET_MODE (src) == VOIDmode ? GET_MODE (dest) : GET_MODE (src); + + /* Note that these insert_regs calls cannot remove + any of the src_elt's, because they would have failed to match + if not still valid. */ + if (insert_regs (src, 0, 0)) + sets[i].src_hash_code = HASH (src, mode); + elt = insert (src, src_eqv_elt, sets[i].src_hash_code, mode); + elt->in_memory = sets[i].src_in_memory; + elt->in_struct = sets[i].src_in_struct; + sets[i].src_elt = elt->first_same_value; + } + } + + invalidate_from_clobbers (&writes_memory, x); + + /* Now invalidate everything set by this instruction. + If a SUBREG or other funny destination is being set, + sets[i].rtl is still nonzero, so here we invalidate the reg + a part of which is being set. */ + + for (i = 0; i < n_sets; i++) + if (sets[i].rtl) + { + register rtx dest = sets[i].inner_dest; + + /* Needed for registers to remove the register from its + previous quantity's chain. + 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 + || (! writes_memory.all && ! cse_rtx_addr_varies_p (dest))) + invalidate (dest); + } + + /* Make sure registers mentioned in destinations + are safe for use in an expression to be inserted. + This removes from the hash table + any invalid entry that refers to one of these registers. */ + + for (i = 0; i < n_sets; i++) + if (sets[i].rtl && GET_CODE (SET_DEST (sets[i].rtl)) != REG) + mention_regs (SET_DEST (sets[i].rtl)); + + /* We may have just removed some of the src_elt's from the hash table. + So replace each one with the current head of the same class. */ + + for (i = 0; i < n_sets; i++) + if (sets[i].rtl) + { + /* If the source is volatile, its destination goes in + a class of its own. */ + if (sets[i].src_volatile) + sets[i].src_elt = 0; + + if (sets[i].src_elt && sets[i].src_elt->first_same_value == 0) + /* If elt was removed, find current head of same class, + or 0 if nothing remains of that class. */ + { + register struct table_elt *elt = sets[i].src_elt; + + while (elt && elt->first_same_value == 0) + elt = elt->next_same_value; + sets[i].src_elt = elt ? elt->first_same_value : 0; + } + } + + /* Now insert the destinations into their equivalence classes. */ + + for (i = 0; i < n_sets; i++) + if (sets[i].rtl) + { + register rtx dest = SET_DEST (sets[i].rtl); + register struct table_elt *elt; + + if (flag_float_store + && GET_CODE (dest) == MEM + && (GET_MODE (dest) == SFmode || GET_MODE (dest) == DFmode)) + continue; + + /* STRICT_LOW_PART isn't part of the value BEING set, + and neither is the SUBREG inside it. + Note that in this case SETS[I].SRC_ELT is really SRC_EQV_ELT. */ + if (GET_CODE (dest) == STRICT_LOW_PART) + dest = SUBREG_REG (XEXP (dest, 0)); + + if (GET_CODE (dest) == REG) + /* Registers must also be inserted into chains for quantities. */ + if (insert_regs (dest, sets[i].src_elt, 1)) + /* If `insert_regs' changes something, the hash code must be + recalculated. */ + sets[i].dest_hash_code = HASHREG (dest); + + if (GET_CODE (dest) == SUBREG) + /* Registers must also be inserted into chains for quantities. */ + if (insert_regs (dest, sets[i].src_elt, 1)) + /* If `insert_regs' changes something, the hash code must be + recalculated. */ + sets[i].dest_hash_code + = canon_hash (dest, GET_MODE (dest)) % NBUCKETS; + + elt = insert (dest, sets[i].src_elt, sets[i].dest_hash_code, GET_MODE (dest)); + elt->in_memory = GET_CODE (sets[i].inner_dest) == MEM; + if (elt->in_memory) + { + elt->in_struct = (MEM_IN_STRUCT_P (sets[i].inner_dest) + || sets[i].inner_dest != SET_DEST (sets[i].rtl)); + } + } + + /* Special handling for (set REG0 REG1) + where REG0 is the "cheapest", cheaper than REG1. + After cse, REG1 will probably not be used in the sequel, + so (if easily done) change this insn to (set REG1 REG0) and + replace REG1 with REG0 in the previous insn that computed their value. + Then REG1 will become a dead store and won't cloud the situation + for later optimizations. */ + if (n_sets == 1 && sets[0].rtl && GET_CODE (SET_DEST (sets[0].rtl)) == REG + && GET_CODE (SET_SRC (sets[0].rtl)) == REG + && rtx_equal_p (canon_reg (SET_SRC (sets[0].rtl)), SET_DEST (sets[0].rtl))) + { + rtx prev = PREV_INSN (insn); + while (prev && GET_CODE (prev) == NOTE) + prev = PREV_INSN (prev); + + if (prev && GET_CODE (prev) == INSN && GET_CODE (PATTERN (prev)) == SET + && SET_DEST (PATTERN (prev)) == SET_SRC (sets[0].rtl)) + { + rtx dest = SET_DEST (sets[0].rtl); + rtx note = find_reg_note (prev, REG_EQUIV, 0); + + SET_DEST (PATTERN (prev)) = dest; + SET_DEST (sets[0].rtl) = SET_SRC (sets[0].rtl); + SET_SRC (sets[0].rtl) = dest; + /* If REG1 was equivalent to a constant, REG0 is not. */ + if (note) + PUT_MODE (note, REG_EQUAL); + } + } + + /* Did this insn become an unconditional branch or become a no-op? */ + if (GET_CODE (insn) == JUMP_INSN + && GET_CODE (x) == SET + && SET_DEST (x) == pc_rtx) + { + if (SET_SRC (x) == pc_rtx) + { + PUT_CODE (insn, NOTE); + NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED; + NOTE_SOURCE_FILE (insn) = 0; + cse_jumps_altered = 1; + /* If previous insn just set CC0 for us, delete it too. */ + if (prev_insn_cc0 != 0 || prev_insn_explicit_cc0 != 0) + { + PUT_CODE (prev_insn, NOTE); + NOTE_LINE_NUMBER (prev_insn) = NOTE_INSN_DELETED; + NOTE_SOURCE_FILE (prev_insn) = 0; + } + /* One less use of the label this insn used to jump to. */ + --LABEL_NUSES (JUMP_LABEL (insn)); + } + else if (GET_CODE (SET_SRC (x)) == LABEL_REF) + { + rtx label; + + emit_barrier_after (insn); + cse_jumps_altered = 1; + /* If previous insn just set CC0 for us, delete it too. */ + if (prev_insn_cc0 != 0 || prev_insn_explicit_cc0 != 0) + { + PUT_CODE (prev_insn, NOTE); + NOTE_LINE_NUMBER (prev_insn) = NOTE_INSN_DELETED; + NOTE_SOURCE_FILE (prev_insn) = 0; + } + /* If jump target is the following label, and this is only use of it, + skip direct to that label and continue optimizing there. */ + label = insn; + while (label != 0 && GET_CODE (label) != CODE_LABEL) + label = NEXT_INSN (label); + if (label == XEXP (SET_SRC (x), 0) + && LABEL_NUSES (label) == 1) + cse_skip_to_next_block = 1; + } + } + + /* If this insn used to store a value based on CC0 but now value is constant, + and the previous insn just set CC0 for us, delete previous insn. + Here we use the fact that nothing expects CC0 to be valid over an insn, + which is true until the final pass. */ + if (GET_CODE (x) == SET && prev_insn_cc0 + && CONSTANT_P (SET_SRC (x))) + { + PUT_CODE (prev_insn, NOTE); + NOTE_LINE_NUMBER (prev_insn) = NOTE_INSN_DELETED; + NOTE_SOURCE_FILE (prev_insn) = 0; + } + + prev_insn_explicit_cc0 = this_insn_explicit_cc0; + prev_insn_cc0 = this_insn_cc0; + 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. */ + +static void +note_mem_written (written, writes_ptr) + rtx written; + struct write_data *writes_ptr; +{ + static struct write_data everything = {1, 1, 1}; + + if (written == 0) + *writes_ptr = everything; + else if (GET_CODE (written) == MEM) + { + /* Pushing or popping the stack invalidates nothing. */ + 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) + return; + if (GET_MODE (written) == BLKmode) + *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. */ + if (!(MEM_IN_STRUCT_P (written) + || GET_CODE (XEXP (written, 0)) == PLUS)) + writes_ptr->all = 1; + writes_ptr->nonscalar = 1; + } + writes_ptr->var = 1; + } +} + +/* Perform invalidation on the basis of everything about an insn + except for invalidating the actual places that are SET in it. + 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; + 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 (GET_CODE (x) == CLOBBER) + { + rtx ref = XEXP (x, 0); + if (ref + && (GET_CODE (ref) == REG || GET_CODE (ref) == SUBREG + || (GET_CODE (ref) == MEM && ! w->all))) + invalidate (ref); + } + else if (GET_CODE (x) == PARALLEL) + { + register int i; + for (i = XVECLEN (x, 0) - 1; i >= 0; i--) + { + register rtx y = XVECEXP (x, 0, i); + if (GET_CODE (y) == CLOBBER) + { + rtx ref = XEXP (y, 0); + if (ref + &&(GET_CODE (ref) == REG || GET_CODE (ref) == SUBREG + || (GET_CODE (ref) == MEM && !w->all))) + invalidate (ref); + } + } + } +} + +/* Find the end of INSN's basic block, and return the cuid of its last insn + and the total number of SETs in all the insns of the block. */ + +struct cse_basic_block_data { int cuid, nsets; rtx last; }; + +static struct cse_basic_block_data +cse_end_of_basic_block (insn) + rtx insn; +{ + rtx p = insn; + struct cse_basic_block_data val; + int nsets = 0; + int last_uid = 0; + + /* Scan to end of this basic block. */ + while (p && GET_CODE (p) != CODE_LABEL) + { + /* Don't cse out the end of a loop. This makes a difference + only for the unusual loops that always execute at least once; + all other loops have labels there so we will stop in any case. + Cse'ing out the end of the loop is dangerous because it + might cause an invariant expression inside the loop + to be reused after the end of the loop. This would make it + hard to move the expression out of the loop in loop.c, + especially if it is one of several equivalent expressions + and loop.c would like to eliminate it. + The occasional optimizations lost by this will all come back + if loop and cse are made to work alternatingly. */ + if (GET_CODE (p) == NOTE + && NOTE_LINE_NUMBER (p) == NOTE_INSN_LOOP_END) + break; + + /* Don't cse over a call to setjmp; on some machines (eg vax) + the regs restored by the longjmp come from + a later time than the setjmp. */ + if (GET_CODE (p) == NOTE + && NOTE_LINE_NUMBER (p) == NOTE_INSN_SETJMP) + break; + + /* A PARALLEL can have lots of SETs in it, + especially if it is really an ASM_OPERANDS. */ + if (GET_CODE (p) == INSN && GET_CODE (PATTERN (p)) == PARALLEL) + nsets += XVECLEN (PATTERN (p), 0); + else + nsets += 1; + + last_uid = INSN_UID (p); + p = NEXT_INSN (p); + } + val.cuid = uid_cuid[last_uid]; + val.nsets = nsets; + val.last = p; + + return val; +} + +static rtx cse_basic_block (); + +/* Perform cse on the instructions of a function. + F is the first instruction. + NREGS is one plus the highest pseudo-reg number used in the instruction. + + Returns 1 if jump_optimize should be redone due to simplifications + in conditional jump instructions. */ + +int +cse_main (f, nregs) + /* f is the first instruction of a chain of insns for one function */ + rtx f; + /* nregs is the total number of registers used in it */ + int nregs; +{ + register rtx insn = f; + register int i; + + cse_jumps_altered = 0; + + init_recog (); + + max_reg = nregs; + + all_minus_one = (int *) alloca (nregs * sizeof (int)); + consec_ints = (int *) alloca (nregs * sizeof (int)); + for (i = 0; i < nregs; i++) + { + all_minus_one[i] = -1; + consec_ints[i] = i; + } + + reg_next_eqv = (int *) alloca (nregs * sizeof (int)); + reg_prev_eqv = (int *) alloca (nregs * sizeof (int)); + reg_qty = (int *) alloca (nregs * sizeof (int)); + reg_rtx = (rtx *) alloca (nregs * sizeof (rtx)); + reg_in_table = (int *) alloca (nregs * sizeof (int)); + reg_tick = (int *) alloca (nregs * sizeof (int)); + + /* Discard all the free elements of the previous function + since they are allocated in the temporarily obstack. */ + bzero (table, sizeof table); + free_element_chain = 0; + n_elements_made = 0; + + /* Find the largest uid. */ + + for (insn = f, i = 0; insn; insn = NEXT_INSN (insn)) + if (INSN_UID (insn) > i) + i = INSN_UID (insn); + + uid_cuid = (short *) alloca ((i + 1) * sizeof (short)); + bzero (uid_cuid, (i + 1) * sizeof (short)); + + /* Compute the mapping from uids to cuids. + CUIDs are numbers assigned to insns, like uids, + except that cuids increase monotonically through the code. + Don't assign cuids to line-number NOTEs, so that the distance in cuids + between two insns is not affected by -g. */ + + for (insn = f, i = 0; insn; insn = NEXT_INSN (insn)) + { + if (GET_CODE (insn) != NOTE + || NOTE_LINE_NUMBER (insn) < 0) + INSN_CUID (insn) = ++i; + else + /* Give a line number note the same cuid as preceding insn. */ + INSN_CUID (insn) = i; + } + + /* Loop over basic blocks. + Compute the maximum number of qty's needed for each basic block + (which is 2 for each SET). */ + insn = f; + while (insn) + { + struct cse_basic_block_data val; + + val = cse_end_of_basic_block (insn); + + cse_basic_block_end = val.cuid; + cse_basic_block_start = INSN_CUID (insn); + max_qty = val.nsets * 2; + + /* Make MAX_QTY bigger to give us room to optimize + past the end of this basic block, if that should prove useful. */ + if (max_qty < 500) + max_qty = 500; + + max_qty += max_reg; + + insn = cse_basic_block (insn, val.last); +#ifdef USE_C_ALLOCA + alloca (0); +#endif + } + + /* Tell refers_to_mem_p that qty_const info is not available. */ + qty_const = 0; + + if (max_elements_made < n_elements_made) + max_elements_made = n_elements_made; + + return cse_jumps_altered; +} + +static rtx +cse_basic_block (from, to) + register rtx from, to; +{ + register rtx insn; + int *qv1 = (int *) alloca (max_qty * sizeof (int)); + int *qv2 = (int *) alloca (max_qty * sizeof (int)); + rtx *qv3 = (rtx *) alloca (max_qty * sizeof (rtx)); + + qty_first_reg = qv1; + qty_last_reg = qv2; + qty_const = qv3; + qty_const_insn = (rtx *) alloca (max_qty * sizeof (rtx)); + + new_basic_block (); + + cse_skip_to_next_block = 0; + + for (insn = from; insn != to; insn = NEXT_INSN (insn)) + { + register enum rtx_code code; + + code = GET_CODE (insn); + + if (code == INSN || code == JUMP_INSN || code == CALL_INSN) + cse_insn (insn); + /* Memory, and some registers, are invalidate by subroutine calls. */ + if (code == CALL_INSN) + { + register int i; + static struct write_data everything = {1, 1, 1}; + invalidate_memory (&everything); + for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) + if (call_used_regs[i] && reg_rtx[i] + && i != FRAME_POINTER_REGNUM + && i != ARG_POINTER_REGNUM) + invalidate (reg_rtx[i]); + } + /* Loop beginnings are often followed by jumps + (that enter the loop above the endtest). + See if we can prove the loop will be executed at least once; + if so, delete the jump. Also perhaps we can prove loop + will never be executed and delete the entire thing. */ + if (code == NOTE + && NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG + && GET_CODE (NEXT_INSN (insn)) == JUMP_INSN) + { + predecide_loop_entry (insn); + /* Whether that jump was deleted or not, + it certainly is the end of the basic block. + Since the jump is unconditional, + it requires no further processing here. */ + break; + } + + /* See if it is ok to keep on going past the label + which used to end our basic block. */ + if (cse_skip_to_next_block + || (to != 0 && NEXT_INSN (insn) == to && LABEL_NUSES (to) == 0)) + { + struct cse_basic_block_data val; + + /* Skip the remaining insns in this block. */ + cse_skip_to_next_block = 0; + insn = to; + if (insn == 0) + break; + + /* Find the end of the following block. */ + val = cse_end_of_basic_block (NEXT_INSN (insn)); + + /* If the tables we allocated have enough space left + to handle all the SETs in the next basic block, + continue through it. Otherwise, return, + and that block will be scanned individually. */ + if (val.nsets * 2 + next_qty > max_qty) + break; + + cse_basic_block_end = val.cuid; + to = val.last; + } + } + + if (next_qty > max_qty) + abort (); + + return to ? NEXT_INSN (to) : 0; +} diff --git a/gcc-1.40/dbranch.c b/gcc-1.40/dbranch.c new file mode 100644 index 0000000..bcf5e9c --- /dev/null +++ b/gcc-1.40/dbranch.c @@ -0,0 +1,449 @@ +/* Delayed branch scheduling pass. + Copyright (C) 1987, 1988, 1989 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY. No author or distributor +accepts responsibility to anyone for the consequences of using it +or for whether it serves any particular purpose or works at all, +unless he says so in writing. Refer to the GNU CC General Public +License for full details. + +Everyone is granted permission to copy, modify and redistribute +GNU CC, but only under the conditions described in the +GNU CC General Public License. A copy of this license is +supposed to have been given to you along with GNU CC so you +can know your rights and responsibilities. It should be in a +file named COPYING. Among other things, the copyright notice +and this notice must be preserved on all copies. */ + +/* Delayed Branch Scheduling Optimization + +If the HAVE_DELAYED_BRANCH macro is defined in the machine +description, this code is called by toplev.c during optimizing +compilation immediately after the final jump optimization pass +and just before assembler output generation, if delayed branch +scheduling is requested with the -fdelayed-branch switch. + +Machines with delayed branch allow one or more instructions +placed *after* a branch instruction to be executed while the +hardware is off fetching the next instruction. These instructions +are executed after the branch is issued, but before the branch +actually takes effect. The decision as to whether or not +the branch is to be taken, and the address of the branch target +are fixed at the time the branch is issued, so only instructions +that do not appear in the dependency graphs for computing the +branch decision and/or target address may be relocated "after" +the branch. Some machines might have additional restrictions, +such as not allowing memory instructions or condition code +modification in the delay sequence. + +Note that this scheduling pass occurs after register allocation, and +(of course) final jump optimization. This mechanism is *not* intended +to be hacked to deal with similar memory-latency pipeline scheduling +(i.e. slots after loads/stores), as tempting as that might be. The +right place to do load-store latency scheduling is prior to register +allocation, since allocation may introduce artificial dependencies +that could have been avoided; note that these artificial dependencies +are *not* reflected in the flow information, which is one reason for +the somewhat ad hoc analysis done in this pass. + +The strategy and methods used are as follows. The function DBR_SCHEDULE +is called from toplev.c if the scheduling pass is to be run. That function +sets up the dump file, then scans the current function from top to bottom +for "d-blocks", which are like basic blocks (single-entry, single-exit), +with the additional condition that the last instruction in the block has +delay slots. Note that if calls have slots, d-blocks can be smaller than +basic blocks. If a basic block does not end with a delay-instruction, +it is skipped. + +To re-order instructions in a d-block (see DBR_DBLOCK_SCHED), the scheduler +scans backward from the "d-instruction", trying to fill the slots. The +scheduler is somewhat conservative. Volatile memory references are +serialized (their order is never changed to avoid possible aliasing +problems). Definitions of registers are serialized (so there is no +possibility of deadlock). Since hard register dependencies are +not noted by flow analysis, the scheduler does its own simplified +tracking of the registers, memory, and condition code uses/defines +by the d-instruction and the instructions it depends on). Information +available from flow analysis is used to shortcut the analysis where +possible. + +Since only data dependencies are considered by the scheduler, any +machine-specific restrictions, e.g. to keep memory instructions from +being scheduled into slots, must be explicit in the definition of +DBR_INSN_ELIGIBLE_P. + +The scheduler scans backwards over the block, looking for eligible +insns to fill the slot(s). If none are found, nothing is done, and no +changes are made to the code. As eligible insns are found, they are +removed from the chain, and recorded in an INSN_LIST rtx. When all +slots are full (or the top of the d-block is reached), the *pattern* +of the d-insn is replaced with a SEQUENCE rtx, which consists of +a copy of the original d-insn followed by the slot fillers. Slot +filling instructions remain in the original relative order in the +sequence. + +When the SEQUENCE pattern is encountered by final, the instructions +are output "normally", though the output code for the instructions +may test for this and alter their behavior appropriately. + +*/ + +#include +#include "config.h" +#include "rtl.h" +#include "hard-reg-set.h" +#include "flags.h" + +FILE *dbr_dump_file; + +/* The number of unfilled delay slots in the current sequence. */ +static int slots_avail; + +/* A flag, nonzero indicating that some insn that could not + go in a slot writes to memory. */ + +static int memw; + +/* A flag, nonzero indicating that the condition code is written + by some insn that couldn't go in a delay slot. */ + +static int ccw; + +/* Each bit is nonzero if the corresponding hard register + is written by an insn that couldn't go in a delay slot. */ + +static HARD_REG_SET regw; + +/* A flag, set nonzero if ENOTE determines that + the current insn can't go in a delay slot because of a + data dependency detected by note_stores. */ + +static int eflag; + +/* The insn having delay slots. Global because of the calls through + note_stores that need it. */ + +static rtx dinsn; + +/* The insn being currently considered for a delay slot. */ + +static rtx insn; + +/* An INSN_LIST (just like the insn field) that we use to hold + LOG_LINKS of ineligible insns. We use what flow analysis + stuff we can - this prevents exhaustive searches for write-read + dependencies in most cases. This tactic only loses on reloads + and code generated with hard regs (instead of pseudos). */ + +static rtx dep_insn_list; + +/* Called by note_stores on "ineligible" insns to keep track of + pre-branch dependencies. */ +static void +pnote (x, in) + rtx x; + rtx in; +{ + switch (GET_CODE (x)) + { + case REG: + if (GET_CODE (in) != SET + || GET_CODE (SET_SRC (in)) != CALL) + SET_HARD_REG_BIT (regw, REGNO (x)); + return; + case MEM: + memw = TRUE; /* this might be relaxed somewhat later */ + return; + case CC0: + ccw = TRUE; + return; + case PC: + return; + default: + abort (); /* should never happen */ + } +} + +/* The d-block end insn is in DINSN. Initialize the flags to + start building the delay sequence. Calls PNOTE from note_stores + to track the written registers and memory. */ + +static void +init_flags () +{ + CLEAR_HARD_REG_SET (regw); + memw = ccw = 0; + note_stores (PATTERN (dinsn), pnote); + if (LOG_LINKS (dinsn)) + dep_insn_list = copy_rtx (LOG_LINKS (dinsn)); + else + dep_insn_list = 0; + slots_avail = DBR_SLOTS_AFTER (dinsn); +} + + +/* Called through note_stores on possibly eligible insn patterns. + Checks to see if a register written by the pattern is needed by an already + ineligible insn. Sets the global EFLAG nonzero if a dependency + is found. */ + +static void +enote (x, p) + rtx x; + rtx p; +{ + if (eflag == 0) + { + if (GET_CODE (x) == REG) + { + if (reg_used_between_p (x, insn, dinsn)) + goto lose; + if ((!FUNCTION_VALUE_REGNO_P (REGNO (x)) || + GET_CODE (dinsn) != CALL_INSN) && + reg_mentioned_p (x, (PATTERN (dinsn)))) + goto lose; + } + else if (x == cc0_rtx && + reg_used_between_p (x, insn, NEXT_INSN (dinsn))) + goto lose; + return; + lose: + eflag = 1; + } +} + +/* Search the current dependency list DEP_INSN_LIST for INSN, + return nonzero if found. */ + +static int +in_dep_list_p (insn) + rtx insn; +{ + rtx l; + for (l = dep_insn_list; l ; l = XEXP (l, 1)) + if (insn == XEXP (l, 0)) return 1; + return 0; +} + +/* Returns zero if INSN is ineligible to be put in a delay slot + of DINSN. INSN is ineligible if it: + - is in the dependency list of an ineligible insn. + - writes a hard register needed by an ineligible insn. + - reads a register written by an ineligible insn. + - refers to memory. + - sets the condition code. + - violates a machine-dependent constraint. */ + +static int +insn_eligible_p () +{ + rtx dest; + rtx pat = PATTERN (insn); + int i,s; + + /* See if there are any explicit dependencies on this insn. */ + if (in_dep_list_p (insn)) + return 0; + + /* Check for implicit dependencies by calling enote on each + store rtx. ENOTE makes sure that no ineligible instruction + refers to a register in a way that flow analysis + has missed or ignored. */ + eflag = 0; + note_stores (PATTERN (insn), enote); + if (eflag) + return 0; + + /* Check for volatile memory refs if any already ineligible. */ + + if (memw && volatile_refs_p (pat)) + { + memw = TRUE; + return 0; + } + + /* See if it refers to any regs that are clobbered by ineligibles. */ + + for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) + if (TEST_HARD_REG_BIT (regw, i) + && refers_to_regno_p (i, i + 1, pat, 0)) + return 0; + +#ifdef DBR_INSN_ELIGIBLE_P + /* Check for arbitrary machine constraints if any. */ + if (! DBR_INSN_ELIGIBLE_P (insn, dinsn)) + return 0; +#endif + + return 1; +} + +/* Add the links in LIST to the dependency list. We put them + at the front since this should make searches faster in long + d-blocks. +*/ +static void +prepend_to_dep_list (list) + rtx list; +{ + rtx l = copy_rtx (list); + while (XEXP (l, 1) != 0) + l = XEXP (l, 1); + XEXP (l, 1) = dep_insn_list; + dep_insn_list = l; +} + + + +/* Update the flags for ineligible INSN - it can't be put in a delay +slot. This involves setting bits to indicate the stores of INSN, and +adding any flow-analysis dependencies of INSN's insn-list to +the ineligible list. (Should ultimately catch reloads too.) */ + +static void +update_flags (insn) + rtx insn; +{ + rtx l; + note_stores (PATTERN (insn), pnote); + if (l = LOG_LINKS (insn)) + prepend_to_dep_list (l); +} + +/* Put INSN and LIST together in a SEQUENCE rtx of LENGTH, and replace + the pattern of INSN with the SEQUENCE. Include the available + slots AVAIL in the SEQUENCE insn. */ +static void +emit_delay_sequence (insn, list, length, avail) + rtx insn; + rtx list; + int length; + int avail; +{ + register int i = 1; + register rtx li, tem; + /* Allocate the the rtvec to hold the insns and the SEQUENCE. */ + rtvec seqv = rtvec_alloc (length + 1); + rtx seq = gen_rtx (SEQUENCE, VOIDmode, seqv); + + /* Make a copy of the insn having delay slots. */ + tem = copy_rtx (insn); + NEXT_INSN (tem) = 0; + PREV_INSN (tem) = 0; + /* Replace the original pattern with a sequence whose + first insn is the copy. */ + PATTERN (insn) = seq; + INSN_CODE (insn) = -1; + XVECEXP (seq, 0, 0) = tem; + /* Copy in the delay-slot filling insns. */ + for (li = list; li; li = XEXP (li, 1)) + { + XVECEXP (seq, 0, i) = XEXP (li, 0); + i++; + } +} + +/* Try to reorganize code in a d-block */ + +static void +dbr_dblock_sched (first, last) + rtx first, last; +{ + rtx delay_insn_list = 0; + int seq_len = 0; + dinsn = last; + if (first == last) return; + init_flags (); + insn = PREV_INSN (dinsn); + while (1) + { + rtx prev = PREV_INSN (insn); + rtx next = NEXT_INSN (insn); + if (GET_CODE (insn) == INSN + && GET_CODE (PATTERN (insn)) != USE + && GET_CODE (PATTERN (insn)) != CLOBBER + && GET_CODE (PATTERN (insn)) != ADDR_VEC + && GET_CODE (PATTERN (insn)) != ADDR_DIFF_VEC) + { + if (slots_avail >= DBR_INSN_SLOTS (insn) && insn_eligible_p ()) + { + /* Add this insn to the delay sequence and + update the number of slots available. */ + register rtx t = delay_insn_list; + delay_insn_list = gen_rtx (INSN_LIST, VOIDmode, insn, t); + seq_len++; + slots_avail -= DBR_INSN_SLOTS (insn); + + /* Now remove it from the chain. */ + NEXT_INSN (prev) = next; + PREV_INSN (next) = prev; + NEXT_INSN (insn) = PREV_INSN (insn) = 0; + } + else + update_flags (insn); + } + else + if (GET_CODE (insn) != NOTE) + abort (); + if (slots_avail == 0 || insn == first) + break; + else + insn = prev; + } + /* Done. If the delay list is non-empty, emit a sequence + in place of the dinsn. */ + if (delay_insn_list != 0) + emit_delay_sequence (dinsn, delay_insn_list, seq_len, slots_avail); +} + + +/* +Identify d-blocks of a function, which are sort of like basic +blocks, except that any instruction with delay slots defines the end +of a dblock, and dblocks that do not end in delay-instructions are +uninteresting degenerate cases. + +This function finds d-blocks in the code for a function, and calls +dbr_dblock_sched on non-degenerate blocks. Called from toplev.c +if HAVE_DELAYED_BRANCH is defined and we are doing optimizing +compilation. F is the first insn of the function, DUMP_FILE +is the file to output debugging info on if requested. */ + +void +dbr_schedule (f, dump_file) + rtx f; + FILE *dump_file; +{ + rtx first = f; + rtx insn; + /* Dump output if requested */ + if (dbr_dump_file = dump_file) + fprintf (dbr_dump_file, "Delayed-branch reordering dump.\n"); + + /* Search for d-blocks by scanning the insns from top to bottom. */ + for (insn = first; insn; insn = NEXT_INSN (insn)) + { + if (DBR_SLOTS_AFTER (insn) > 0) + { + /* An insn with delay slots always terminates a d-block. + Call the scheduler to fill in the slots if possible. */ + dbr_dblock_sched (first, insn); + + /* Resume scanning after the end of the sequence. */ + first = NEXT_INSN (dinsn); + } + else + /* Not an end of a real d-block, but need to check + if it is the end of a degenerate one. Note that + calls or jumps will only reach here if they aren't + delayed instructions. */ + + if (GET_CODE (insn) == CODE_LABEL || + GET_CODE (insn) == JUMP_INSN || + GET_CODE (insn) == CALL_INSN) + first = NEXT_INSN (insn); + } +} diff --git a/gcc-1.40/dbxout.c b/gcc-1.40/dbxout.c new file mode 100644 index 0000000..bf0856f --- /dev/null +++ b/gcc-1.40/dbxout.c @@ -0,0 +1,1201 @@ +/* Output dbx-format symbol table information from GNU compiler. + Copyright (C) 1987, 1988 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 1, 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. */ + + +/* Output dbx-format symbol table data. + This consists of many symbol table entries, each of them + a .stabs assembler pseudo-op with four operands: + a "name" which is really a description of one symbol and its type, + a "code", which is a symbol defined in stab.h whose name starts with N_, + an unused operand always 0, + and a "value" which is an address or an offset. + The name is enclosed in doublequote characters. + + Each function, variable, typedef, and structure tag + has a symbol table entry to define it. + The beginning and end of each level of name scoping within + a function are also marked by special symbol table entries. + + The "name" consists of the symbol name, a colon, a kind-of-symbol letter, + and a data type number. The data type number may be followed by + "=" and a type definition; normally this will happen the first time + the type number is mentioned. The type definition may refer to + other types by number, and those type numbers may be followed + by "=" and nested definitions. + + This can make the "name" quite long. + When a name is more than 80 characters, we split the .stabs pseudo-op + into two .stabs pseudo-ops, both sharing the same "code" and "value". + The first one is marked as continued with a double-backslash at the + end of its "name". + + The kind-of-symbol letter distinguished function names from global + variables from file-scope variables from parameters from auto + variables in memory from typedef names from register variables. + See `dbxout_symbol'. + + The "code" is mostly redundant with the kind-of-symbol letter + that goes in the "name", but not entirely: for symbols located + in static storage, the "code" says which segment the address is in, + which controls how it is relocated. + + The "value" for a symbol in static storage + is the core address of the symbol (actually, the assembler + label for the symbol). For a symbol located in a stack slot + it is the stack offset; for one in a register, the register number. + For a typedef symbol, it is zero. + + If DEBUG_SYMS_TEXT is defined, all debugging symbols must be + output while in the text section. + + For more on data type definitions, see `dbxout_type'. */ + +#include "config.h" +#include "tree.h" +#include "rtl.h" +#include "flags.h" +#include + +/* Typical USG systems don't have stab.h, and they also have + no use for DBX-format debugging info. */ + +#ifdef DBX_DEBUGGING_INFO + +#ifdef DEBUG_SYMS_TEXT +#define FORCE_TEXT text_section (); +#else +#define FORCE_TEXT +#endif + +#ifdef USG +#include "gstab.h" /* If doing DBX on sysV, use our own stab.h. */ +#else +#include /* On BSD, use the system's stab.h. */ +#endif /* not USG */ + +/* Stream for writing to assembler file. */ + +static FILE *asmfile; + +enum typestatus {TYPE_UNSEEN, TYPE_XREF, TYPE_DEFINED}; + +/* Vector recording the status of describing 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. */ + +enum typestatus *typevec; + +/* Number of elements of space allocated in `typevec'. */ + +static int typevec_len; + +/* In dbx output, each type gets a unique number. + This is the number for the next type output. + The number, once assigned, is in the TYPE_SYMTAB_ADDRESS field. */ + +static int next_type_number; + +/* 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 + end of the ranges of code in each block + with assembler labels LBBn and LBEn, where n is the block number. + The labels are generated in final, which assigns numbers to the + blocks in the same way. */ + +static int next_block_number; + +/* These variables are for dbxout_symbol to communicate to + dbxout_finish_symbol. + current_sym_code is the symbol-type-code, a symbol N_... define in stab.h. + current_sym_value and current_sym_addr are two ways to address the + value to store in the symtab entry. + current_sym_addr if nonzero represents the value as an rtx. + If that is zero, current_sym_value is used. This is used + when the value is an offset (such as for auto variables, + register variables and parms). */ + +static int current_sym_code; +static int current_sym_value; +static rtx current_sym_addr; + +/* Number of chars of symbol-description generated so far for the + current symbol. Used by CHARS and CONTIN. */ + +static int current_sym_nchars; + +/* Report having output N chars of the current symbol-description. */ + +#define CHARS(N) (current_sym_nchars += (N)) + +/* Break the current symbol-description, generating a continuation, + if it has become long. */ + +#ifndef DBX_CONTIN_LENGTH +#define DBX_CONTIN_LENGTH 80 +#endif + +#if DBX_CONTIN_LENGTH > 0 +#define CONTIN \ + do {if (current_sym_nchars > DBX_CONTIN_LENGTH) dbxout_continue ();} while (0) +#else +#define CONTIN +#endif + +void dbxout_types (); +void dbxout_tags (); +void dbxout_args (); +void dbxout_symbol (); +static void dbxout_type_name (); +static void dbxout_type (); +static void dbxout_finish_symbol (); +static void dbxout_continue (); + +/* At the beginning of compilation, start writing the symbol table. + Initialize `typevec' and output the standard data types of C. */ + +void +dbxout_init (asm_file, input_file_name) + FILE *asm_file; + char *input_file_name; +{ + asmfile = asm_file; + + typevec_len = 100; + typevec = (enum typestatus *) xmalloc (typevec_len * sizeof typevec[0]); + bzero (typevec, typevec_len * sizeof typevec[0]); + + /* Used to put `Ltext:' before the reference, but that loses on sun 4. */ + fprintf (asmfile, + "\t.stabs \"%s\",%d,0,0,Ltext\nLtext:\n", + input_file_name, N_SO); + + next_type_number = 1; + next_block_number = 2; + + /* Make sure that types `int' and `char' have numbers 1 and 2. + Definitions of other integer types will refer to those numbers. */ + + dbxout_symbol (TYPE_NAME (integer_type_node), 0); + dbxout_symbol (TYPE_NAME (char_type_node), 0); + + /* Get all permanent types not yet gotten, and output them. */ + + dbxout_types (get_permanent_types ()); +} + +/* 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 + .stabs "start......\\",code,0,value + .stabs "...rest",code,0,value */ + +static void +dbxout_continue () +{ +#ifdef DBX_CONTIN_CHAR + fprintf (asmfile, "%c", DBX_CONTIN_CHAR); +#else + fprintf (asmfile, "\\\\"); +#endif + dbxout_finish_symbol (); + fprintf (asmfile, ".stabs \""); + current_sym_nchars = 0; +} + +/* Output a reference to a type. If the type has not yet been + described in the dbx output, output its definition now. + For a type already defined, just refer to its definition + using the type number. + + If FULL is nonzero, and the type has been described only with + a forward-reference, output the definition now. + If FULL is zero in this case, just refer to the forward-reference + using the number previously allocated. */ + +static void +dbxout_type (type, full) + tree type; + int full; +{ + register tree tem; + + /* If there was an input error and we don't really have a type, + avoid crashing and write something that is at least valid + by assuming `int'. */ + if (type == error_mark_node) + type = integer_type_node; + else + type = TYPE_MAIN_VARIANT (type); + + if (TYPE_SYMTAB_ADDRESS (type) == 0) + { + /* Type has no dbx number assigned. Assign next available number. */ + TYPE_SYMTAB_ADDRESS (type) = next_type_number++; + + /* Make sure type vector is long enough to record about this type. */ + + if (next_type_number == typevec_len) + { + typevec = (enum typestatus *) xrealloc (typevec, typevec_len * 2 * sizeof typevec[0]); + bzero (typevec + typevec_len, typevec_len * sizeof typevec[0]); + typevec_len *= 2; + } + } + + /* Output the number of this type, to refer to it. */ + fprintf (asmfile, "%d", TYPE_SYMTAB_ADDRESS (type)); + CHARS (3); + + /* If this type's definition has been output or is now being output, + that is all. */ + + switch (typevec[TYPE_SYMTAB_ADDRESS (type)]) + { + case TYPE_UNSEEN: + break; + case TYPE_XREF: + if (! full) + return; + break; + case TYPE_DEFINED: + return; + } + +#ifdef DBX_NO_XREFS + /* For systems where dbx output does not allow the `=xsNAME:' syntax, + leave the type-number completely undefined rather than output + a cross-reference. */ + if (TREE_CODE (type) == RECORD_TYPE || TREE_CODE (type) == UNION_TYPE + || TREE_CODE (type) == ENUMERAL_TYPE) + + if ((TYPE_NAME (type) != 0 && !full) + || TYPE_SIZE (type) == 0) + { + typevec[TYPE_SYMTAB_ADDRESS (type)] = TYPE_XREF; + return; + } +#endif + + /* Output a definition now. */ + + fprintf (asmfile, "="); + CHARS (1); + + /* 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; + + switch (TREE_CODE (type)) + { + case VOID_TYPE: + /* For a void type, just define it as itself; ie, "5=5". + This makes us consider it defined + 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); + 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. */ + fprintf (asmfile, "r2;0;127;"); + else + /* Output other integer types as subranges of `int'. */ + fprintf (asmfile, "r1;%d;%d;", + TREE_INT_CST_LOW (TYPE_MIN_VALUE (type)), + TREE_INT_CST_LOW (TYPE_MAX_VALUE (type))); + CHARS (25); + break; + + case REAL_TYPE: + /* This must be magic. */ + fprintf (asmfile, "r1;%d;0;", + TREE_INT_CST_LOW (size_in_bytes (type))); + CHARS (16); + break; + + case ARRAY_TYPE: + /* 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 an array of type M and size N. */ + fprintf (asmfile, "ar1;0;%d;", + (TYPE_DOMAIN (type) + ? TREE_INT_CST_LOW (TYPE_MAX_VALUE (TYPE_DOMAIN (type))) + : -1)); + CHARS (17); + dbxout_type (TREE_TYPE (type), 0); + break; + + case RECORD_TYPE: + case UNION_TYPE: + /* Output a structure type. */ + if ((TYPE_NAME (type) != 0 && !full) + || TYPE_SIZE (type) == 0) + { + /* If the type is just a cross reference, output one + and mark the type as partially described. + If it later becomes defined, we will output + its real definition. + If the type has a name, don't nest its definition within + another type's definition; instead, output an xref + and let the definition come when the name is defined. */ + fprintf (asmfile, (TREE_CODE (type) == RECORD_TYPE) ? "xs" : "xu"); + CHARS (3); +#if 0 /* This assertion is legitimately false in C++. */ + /* We shouldn't be outputting a reference to a type before its + definition unless the type has a tag name. + A typedef name without a tag name should be impossible. */ + if (TREE_CODE (TYPE_NAME (type)) != IDENTIFIER_NODE) + abort (); +#endif + dbxout_type_name (type); + fprintf (asmfile, ":"); + typevec[TYPE_SYMTAB_ADDRESS (type)] = TYPE_XREF; + break; + } + tem = size_in_bytes (type); + fprintf (asmfile, (TREE_CODE (type) == RECORD_TYPE) ? "s%d" : "u%d", + TREE_INT_CST_LOW (tem)); + + if (TYPE_BASETYPES (type) && use_gdb_dbx_extensions) + { + putc ('!', asmfile); + putc ((TREE_PUBLIC (TYPE_BASETYPES (type)) ? '2' : '0'), + asmfile); + dbxout_type (TREE_VALUE (TYPE_BASETYPES (type)), 0); + putc (',', asmfile); + CHARS (3); + } + CHARS (11); + + for (tem = TYPE_FIELDS (type); tem; tem = TREE_CHAIN (tem)) + /* Output the name, type, position (in bits), size (in bits) + of each field. */ + /* Omit here the nameless fields that are used to skip bits. */ + if (DECL_NAME (tem) != 0) + { + /* Continue the line if necessary, + but not before the first field. */ + if (tem != TYPE_FIELDS (type)) + CONTIN; + fprintf (asmfile, "%s:", IDENTIFIER_POINTER (DECL_NAME (tem))); + CHARS (2 + IDENTIFIER_LENGTH (DECL_NAME (tem))); +#ifdef TREE_PRIVATE + if (use_gdb_dbx_extensions + && (TREE_PRIVATE (tem) || TREE_PROTECTED (tem) + || TREE_CODE (tem) != FIELD_DECL)) + { + putc ('/', asmfile); + putc ((TREE_PRIVATE (tem) ? '0' + : TREE_PROTECTED (tem) ? '1' : '2'), + asmfile); + CHARS (2); + if (TREE_CODE (tem) == FUNCTION_DECL) + { + putc (':', asmfile); + CHARS (1); + dbxout_type (TREE_TYPE (tem), 0); /* FUNCTION_TYPE */ + dbxout_args (TYPE_ARG_TYPES (TREE_TYPE (tem))); +#ifdef TREE_VIRTUAL + fprintf (asmfile, ":%s;%c", + XSTR (XEXP (DECL_RTL (tem), 0), 0), + TREE_VIRTUAL (tem) ? '*' : '.'); +#endif + CHARS (3 + strlen (XSTR (XEXP (DECL_RTL (tem), 0), 0))); + } + else + dbxout_type (TREE_TYPE (tem), 0); + } + else +#endif + dbxout_type (TREE_TYPE (tem), 0); + + if (TREE_CODE (tem) == VAR_DECL) + { + if (use_gdb_dbx_extensions) + { + fprintf (asmfile, ":%s", + XSTR (XEXP (DECL_RTL (tem), 0), 0)); + CHARS (2 + strlen (XSTR (XEXP (DECL_RTL (tem), 0), 0))); + } + else + { + fprintf (asmfile, ",0,0;"); + CHARS (5); + } + } + else + { + fprintf (asmfile, ",%d,%d;", DECL_OFFSET (tem), + (TREE_INT_CST_LOW (DECL_SIZE (tem)) + * DECL_SIZE_UNIT (tem))); + CHARS (23); + } + } + + putc (';', asmfile); + CHARS (1); + break; + + case ENUMERAL_TYPE: + if ((TYPE_NAME (type) != 0 && !full) + || TYPE_SIZE (type) == 0) + { + fprintf (asmfile, "xe"); + CHARS (3); + dbxout_type_name (type); + typevec[TYPE_SYMTAB_ADDRESS (type)] = TYPE_XREF; + fprintf (asmfile, ":"); + return; + } + putc ('e', asmfile); + CHARS (1); + for (tem = TYPE_VALUES (type); tem; tem = TREE_CHAIN (tem)) + { + fprintf (asmfile, "%s:%d,", IDENTIFIER_POINTER (TREE_PURPOSE (tem)), + TREE_INT_CST_LOW (TREE_VALUE (tem))); + CHARS (11 + IDENTIFIER_LENGTH (TREE_PURPOSE (tem))); + if (TREE_CHAIN (tem) != 0) + CONTIN; + } + putc (';', asmfile); + CHARS (1); + break; + + case POINTER_TYPE: + putc ('*', asmfile); + CHARS (1); + dbxout_type (TREE_TYPE (type), 0); + break; + + case METHOD_TYPE: + if (use_gdb_dbx_extensions) + { + putc ('@', asmfile); + CHARS (1); + dbxout_type (TYPE_METHOD_BASETYPE (type), 0); + putc (',', asmfile); + CHARS (1); + dbxout_type (TREE_TYPE (type), 0); + } + else + { + /* Treat it as a function type. */ + dbxout_type (TREE_TYPE (type), 0); + } + break; + + case OFFSET_TYPE: + if (use_gdb_dbx_extensions) + { + putc ('@', asmfile); + CHARS (1); + dbxout_type (TYPE_OFFSET_BASETYPE (type), 0); + putc (',', asmfile); + CHARS (1); + dbxout_type (TREE_TYPE (type), 0); + } + else + { + /* Treat it as a function type. */ + dbxout_type (TREE_TYPE (type), 0); + } + break; + + case REFERENCE_TYPE: + putc (use_gdb_dbx_extensions ? '&' : '*', asmfile); + CHARS (1); + dbxout_type (TREE_TYPE (type), 0); + break; + + case FUNCTION_TYPE: + putc ('f', asmfile); + CHARS (1); + dbxout_type (TREE_TYPE (type), 0); + break; + + default: + abort (); + } +} + +/* Output the name of type TYPE, with no punctuation. + Such names can be set up either by typedef declarations + or by struct, enum and union tags. */ + +static void +dbxout_type_name (type) + register tree type; +{ + tree t; + if (TYPE_NAME (type) == 0) + abort (); + if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE) + { + t = TYPE_NAME (type); + } + else if (TREE_CODE (TYPE_NAME (type)) == TYPE_DECL) + { + t = DECL_NAME (TYPE_NAME (type)); + } + else + abort (); + + fprintf (asmfile, "%s", IDENTIFIER_POINTER (t)); + CHARS (IDENTIFIER_LENGTH (t)); +} + +/* Output a .stabs for the symbol defined by DECL, + which must be a ..._DECL node in the normal namespace. + It may be a CONST_DECL, a FUNCTION_DECL, a PARM_DECL or a VAR_DECL. + LOCAL is nonzero if the scope is less than the entire file. */ + +void +dbxout_symbol (decl, local) + tree decl; + int local; +{ + int letter = 0; + tree type = TREE_TYPE (decl); + + /* If global, first output all types and all + struct, enum and union tags that have been created + and not yet output. */ + + if (local == 0) + { + dbxout_tags (gettags ()); + dbxout_types (get_permanent_types ()); + } + + current_sym_code = 0; + current_sym_value = 0; + current_sym_addr = 0; + + /* The output will always start with the symbol name, + so count that always in the length-output-so-far. */ + + current_sym_nchars = 2 + IDENTIFIER_LENGTH (DECL_NAME (decl)); + + switch (TREE_CODE (decl)) + { + case CONST_DECL: + /* Enum values are defined by defining the enum type. */ + break; + + case FUNCTION_DECL: + if (DECL_RTL (decl) == 0) + return; + if (TREE_EXTERNAL (decl)) + break; + if (GET_CODE (DECL_RTL (decl)) != MEM + || GET_CODE (XEXP (DECL_RTL (decl), 0)) != SYMBOL_REF) + break; + FORCE_TEXT; + fprintf (asmfile, ".stabs \"%s:%c", + IDENTIFIER_POINTER (DECL_NAME (decl)), + TREE_PUBLIC (decl) ? 'F' : 'f'); + + current_sym_code = N_FUN; + current_sym_addr = XEXP (DECL_RTL (decl), 0); + + if (TREE_TYPE (TREE_TYPE (decl))) + dbxout_type (TREE_TYPE (TREE_TYPE (decl)), 0); + else + dbxout_type (void_type_node, 0); + dbxout_finish_symbol (); + break; + + case TYPE_DECL: +#if 0 + /* This seems all wrong. Outputting most kinds of types gives no name + at all. A true definition gives no name; a cross-ref for a + structure can give the tag name, but not a type name. + It seems that no typedef name is defined by outputting a type. */ + + /* If this typedef name was defined by outputting the type, + don't duplicate it. */ + if (typevec[TYPE_SYMTAB_ADDRESS (type)] == TYPE_DEFINED + && TYPE_NAME (TREE_TYPE (decl)) == decl) + return; +#endif + /* Don't output the same typedef twice. */ + if (TREE_ASM_WRITTEN (decl)) + return; + + /* Output typedef name. */ + FORCE_TEXT; + fprintf (asmfile, ".stabs \"%s:t", + IDENTIFIER_POINTER (DECL_NAME (decl))); + + current_sym_code = N_LSYM; + + dbxout_type (TREE_TYPE (decl), 1); + dbxout_finish_symbol (); + + /* Prevent duplicate output of a typedef. */ + TREE_ASM_WRITTEN (decl) = 1; + break; + + case PARM_DECL: + /* Parm decls go in their own separate chains + and are output by dbxout_reg_parms and dbxout_parms. */ + abort (); + + case VAR_DECL: + if (DECL_RTL (decl) == 0) + return; + /* Don't mention a variable that is external. + Let the file that defines it describe it. */ + if (TREE_EXTERNAL (decl)) + break; + + /* Don't mention a variable at all + if it was completely optimized into nothingness. */ + if (GET_CODE (DECL_RTL (decl)) == REG + && (REGNO (DECL_RTL (decl)) < 0 + || REGNO (DECL_RTL (decl)) >= FIRST_PSEUDO_REGISTER)) + break; + + /* The kind-of-variable letter depends on where + the variable is and on the scope of its name: + G and N_GSYM for static storage and global scope, + S for static storage and file scope, + V for static storage and local scope, + for those two, use N_LCSYM if data is in bss segment, + N_STSYM if in data segment, N_FUN otherwise. + (We used N_FUN originally, then changed to N_STSYM + to please GDB. However, it seems that confused ld. + Now GDB has been fixed to like N_FUN, says Kingdon.) + no letter at all, and N_LSYM, for auto variable, + r and N_RSYM for register variable. */ + + if (GET_CODE (DECL_RTL (decl)) == MEM + && GET_CODE (XEXP (DECL_RTL (decl), 0)) == SYMBOL_REF) + { + if (TREE_PUBLIC (decl)) + { + letter = 'G'; + current_sym_code = N_GSYM; + } + else + { + current_sym_addr = XEXP (DECL_RTL (decl), 0); + + letter = TREE_PERMANENT (decl) ? 'S' : 'V'; + + if (!DECL_INITIAL (decl)) + current_sym_code = N_LCSYM; + else if (TREE_READONLY (decl) && ! TREE_VOLATILE (decl)) + /* This is not quite right, but it's the closest + of all the codes that Unix defines. */ + current_sym_code = N_FUN; + else + { +/* Ultrix `as' seems to need this. */ +#ifdef DBX_STATIC_STAB_DATA_SECTION + data_section (); +#endif + current_sym_code = N_STSYM; + } + } + } + else if (GET_CODE (DECL_RTL (decl)) == REG) + { + letter = 'r'; + current_sym_code = N_RSYM; + current_sym_value = DBX_REGISTER_NUMBER (REGNO (DECL_RTL (decl))); + } + else if (GET_CODE (DECL_RTL (decl)) == SUBREG) + { + rtx value = DECL_RTL (decl); + int offset = 0; + while (GET_CODE (value) == SUBREG) + { + offset += SUBREG_WORD (value); + value = SUBREG_REG (value); + } + letter = 'r'; + current_sym_code = N_RSYM; + current_sym_value = DBX_REGISTER_NUMBER (REGNO (value) + offset); + } + else if (GET_CODE (DECL_RTL (decl)) == MEM + && (GET_CODE (XEXP (DECL_RTL (decl), 0)) == MEM + || (GET_CODE (XEXP (DECL_RTL (decl), 0)) == REG + && REGNO (XEXP (DECL_RTL (decl), 0)) != FRAME_POINTER_REGNUM))) + /* 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 + that register or stack slot. DBX has no way to represent this + so all we can do is output the variable as a pointer. + If it's not a parameter, ignore it. + (VAR_DECLs like this can be made by integrate.c.) */ + { + if (GET_CODE (XEXP (DECL_RTL (decl), 0)) == REG) + { + letter = 'r'; + current_sym_code = N_RSYM; + current_sym_value = DBX_REGISTER_NUMBER (REGNO (XEXP (DECL_RTL (decl), 0))); + } + else + { + current_sym_code = N_LSYM; + /* DECL_RTL looks like (MEM (MEM (PLUS (REG...) (CONST_INT...)))). + We want the value of that CONST_INT. */ + current_sym_value = INTVAL (XEXP (XEXP (XEXP (DECL_RTL (decl), 0), 0), 1)); + } + + /* Effectively do build_pointer_type, but don't cache this type, + since it might be temporary whereas the type it points to + might have been saved for inlining. */ + type = make_node (POINTER_TYPE); + TREE_TYPE (type) = TREE_TYPE (decl); + } + else if (GET_CODE (DECL_RTL (decl)) == MEM + && GET_CODE (XEXP (DECL_RTL (decl), 0)) == REG) + { + current_sym_code = N_LSYM; + current_sym_value = 0; + } + else if (GET_CODE (DECL_RTL (decl)) == MEM + && GET_CODE (XEXP (DECL_RTL (decl), 0)) == PLUS + && GET_CODE (XEXP (XEXP (DECL_RTL (decl), 0), 1)) == CONST_INT) + { + current_sym_code = N_LSYM; + /* DECL_RTL looks like (MEM (PLUS (REG...) (CONST_INT...))) + We want the value of that CONST_INT. */ + current_sym_value = INTVAL (XEXP (XEXP (DECL_RTL (decl), 0), 1)); + } + else + /* Address might be a MEM, when DECL is a variable-sized object. + Or it might be const0_rtx, meaning previous passes + want us to ignore this variable. */ + break; + + /* Ok, start a symtab entry and output the variable name. */ + FORCE_TEXT; + fprintf (asmfile, ".stabs \"%s:", + IDENTIFIER_POINTER (DECL_NAME (decl))); + if (letter) putc (letter, asmfile); + dbxout_type (type, 0); + dbxout_finish_symbol (); + break; + } +} + +static void +dbxout_finish_symbol () +{ + fprintf (asmfile, "\",%d,0,0,", current_sym_code); + if (current_sym_addr) + output_addr_const (asmfile, current_sym_addr); + else + fprintf (asmfile, "%d", current_sym_value); + putc ('\n', asmfile); +} + +/* Output definitions of all the decls in a chain. */ + +static void +dbxout_syms (syms) + tree syms; +{ + while (syms) + { + dbxout_symbol (syms, 1); + syms = TREE_CHAIN (syms); + } +} + +/* The following two functions output definitions of function parameters. + Each parameter gets a definition locating it in the parameter list. + Each parameter that is a register variable gets a second definition + locating it in the register. + + Printing or argument lists in gdb uses the definitions that + locate in the parameter list. But reference to the variable in + expressions uses preferentially the definition as a register. */ + +/* Output definitions, referring to storage in the parmlist, + of all the parms in PARMS, which is a chain of PARM_DECL nodes. */ + +static void +dbxout_parms (parms) + tree parms; +{ + for (; parms; parms = TREE_CHAIN (parms)) + { + if (DECL_OFFSET (parms) >= 0) + { + current_sym_code = N_PSYM; + current_sym_value = DECL_OFFSET (parms) / BITS_PER_UNIT; + current_sym_addr = 0; + current_sym_nchars = 2 + strlen (IDENTIFIER_POINTER (DECL_NAME (parms))); + + FORCE_TEXT; + fprintf (asmfile, ".stabs \"%s:p", + IDENTIFIER_POINTER (DECL_NAME (parms))); + + if (GET_CODE (DECL_RTL (parms)) == REG + && REGNO (DECL_RTL (parms)) >= 0 + && REGNO (DECL_RTL (parms)) < FIRST_PSEUDO_REGISTER) + dbxout_type (DECL_ARG_TYPE (parms), 0); + else + { + /* 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. */ +#ifdef BYTES_BIG_ENDIAN + if (TREE_TYPE (parms) != DECL_ARG_TYPE (parms)) + current_sym_value += (GET_MODE_SIZE (TYPE_MODE (DECL_ARG_TYPE (parms))) + - GET_MODE_SIZE (GET_MODE (DECL_RTL (parms)))); +#endif + + if (GET_CODE (DECL_RTL (parms)) == MEM + && GET_CODE (XEXP (DECL_RTL (parms), 0)) == PLUS + && GET_CODE (XEXP (XEXP (DECL_RTL (parms), 0), 1)) == CONST_INT + && INTVAL (XEXP (XEXP (DECL_RTL (parms), 0), 1)) == current_sym_value) + dbxout_type (TREE_TYPE (parms), 0); + else + { + current_sym_value = DECL_OFFSET (parms) / BITS_PER_UNIT; + dbxout_type (DECL_ARG_TYPE (parms), 0); + } + } + dbxout_finish_symbol (); + } + /* Parm was passed in registers. + If it lives in a hard register, output a "regparm" symbol + for the register it lives in. */ + else if (GET_CODE (DECL_RTL (parms)) == REG + && REGNO (DECL_RTL (parms)) >= 0 + && REGNO (DECL_RTL (parms)) < FIRST_PSEUDO_REGISTER) + { + current_sym_code = N_RSYM; + current_sym_value = DBX_REGISTER_NUMBER (REGNO (DECL_RTL (parms))); + current_sym_addr = 0; + current_sym_nchars = 2 + strlen (IDENTIFIER_POINTER (DECL_NAME (parms))); + + FORCE_TEXT; + fprintf (asmfile, ".stabs \"%s:P", + IDENTIFIER_POINTER (DECL_NAME (parms))); + + dbxout_type (DECL_ARG_TYPE (parms), 0); + dbxout_finish_symbol (); + } + else if (GET_CODE (DECL_RTL (parms)) == MEM + && XEXP (DECL_RTL (parms), 0) != const0_rtx) + { + current_sym_code = N_LSYM; + /* DECL_RTL looks like (MEM (PLUS (REG...) (CONST_INT...))). + We want the value of that CONST_INT. */ + current_sym_value = INTVAL (XEXP (XEXP (DECL_RTL (parms), 0), 1)); + current_sym_addr = 0; + current_sym_nchars = 2 + strlen (IDENTIFIER_POINTER (DECL_NAME (parms))); + + FORCE_TEXT; + fprintf (asmfile, ".stabs \"%s:p", + IDENTIFIER_POINTER (DECL_NAME (parms))); + +#if 0 /* This is actually the case in which a parameter + is passed in registers but lives on the stack in a local slot. + The address we are using is already correct, so don't change it. */ + + /* 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. */ +#ifdef BYTES_BIG_ENDIAN + if (TREE_TYPE (parms) != DECL_ARG_TYPE (parms)) + current_sym_value += (GET_MODE_SIZE (TYPE_MODE (DECL_ARG_TYPE (parms))) + - GET_MODE_SIZE (GET_MODE (DECL_RTL (parms)))); +#endif +#endif /* 0 */ + + dbxout_type (TREE_TYPE (parms), 0); + dbxout_finish_symbol (); + } + } +} + +/* Output definitions, referring to registers, + of all the parms in PARMS which are stored in registers during the function. + PARMS is a chain of PARM_DECL nodes. */ + +static void +dbxout_reg_parms (parms) + tree parms; +{ + while (parms) + { + /* Report parms that live in registers during the function. */ + if (GET_CODE (DECL_RTL (parms)) == REG + && REGNO (DECL_RTL (parms)) >= 0 + && REGNO (DECL_RTL (parms)) < FIRST_PSEUDO_REGISTER + && DECL_OFFSET (parms) >= 0) + { + current_sym_code = N_RSYM; + current_sym_value = DBX_REGISTER_NUMBER (REGNO (DECL_RTL (parms))); + current_sym_addr = 0; + current_sym_nchars = 2 + IDENTIFIER_LENGTH (DECL_NAME (parms)); + FORCE_TEXT; + fprintf (asmfile, ".stabs \"%s:r", + IDENTIFIER_POINTER (DECL_NAME (parms))); + dbxout_type (TREE_TYPE (parms), 0); + dbxout_finish_symbol (); + } + /* Report parms that live in memory but outside the parmlist. */ + else if (GET_CODE (DECL_RTL (parms)) == MEM + && GET_CODE (XEXP (DECL_RTL (parms), 0)) == PLUS + && GET_CODE (XEXP (XEXP (DECL_RTL (parms), 0), 1)) == CONST_INT) + { + int offset = DECL_OFFSET (parms) / BITS_PER_UNIT; + /* A parm declared char is really passed as an int, + so it occupies the least significant bytes. + On a big-endian machine those are not the low-numbered ones. */ +#ifdef BYTES_BIG_ENDIAN + if (offset != -1 && TREE_TYPE (parms) != DECL_ARG_TYPE (parms)) + offset += (GET_MODE_SIZE (TYPE_MODE (DECL_ARG_TYPE (parms))) + - GET_MODE_SIZE (GET_MODE (DECL_RTL (parms)))); +#endif + if (INTVAL (XEXP (XEXP (DECL_RTL (parms), 0), 1)) != offset) + { + current_sym_code = N_LSYM; + current_sym_value = INTVAL (XEXP (XEXP (DECL_RTL (parms), 0), 1)); + current_sym_addr = 0; + current_sym_nchars = 2 + IDENTIFIER_LENGTH (DECL_NAME (parms)); + FORCE_TEXT; + fprintf (asmfile, ".stabs \"%s:", + IDENTIFIER_POINTER (DECL_NAME (parms))); + dbxout_type (TREE_TYPE (parms), 0); + dbxout_finish_symbol (); + } + } + parms = TREE_CHAIN (parms); + } +} + +/* Given a chain of ..._TYPE nodes (as come in a parameter list), + output definitions of those names, in raw form */ + +void +dbxout_args (args) + tree args; +{ + while (args) + { + putc (',', asmfile); + dbxout_type (TREE_VALUE (args), 0); + CHARS (1); + args = TREE_CHAIN (args); + } +} + +/* Given a chain of ..._TYPE nodes, + find those which have typedef names and output those names. + This is to ensure those types get output. */ + +void +dbxout_types (types) + register tree types; +{ + while (types) + { + if (TYPE_NAME (types) + && TREE_CODE (TYPE_NAME (types)) == TYPE_DECL + && ! TREE_ASM_WRITTEN (TYPE_NAME (types))) + dbxout_symbol (TYPE_NAME (types), 1); + types = TREE_CHAIN (types); + } +} + +/* Output the tags (struct, union and enum definitions with names) for a block, + given a list of them (a chain of TREE_LIST nodes) in TAGS. + We must check to include those that have been mentioned already with + only a cross-reference. */ + +void +dbxout_tags (tags) + tree tags; +{ + register tree link; + for (link = tags; link; link = TREE_CHAIN (link)) + { + register tree type = TYPE_MAIN_VARIANT (TREE_VALUE (link)); + if (TREE_PURPOSE (link) != 0 + && ! TREE_ASM_WRITTEN (link) + && TYPE_SIZE (type) != 0) + { + TREE_ASM_WRITTEN (link) = 1; + current_sym_code = N_LSYM; + current_sym_value = 0; + current_sym_addr = 0; + current_sym_nchars = 2 + IDENTIFIER_LENGTH (TREE_PURPOSE (link)); + + FORCE_TEXT; + fprintf (asmfile, ".stabs \"%s:T", + IDENTIFIER_POINTER (TREE_PURPOSE (link))); + dbxout_type (type, 1); + dbxout_finish_symbol (); + } + } +} + +/* Output everything about a symbol block (that is to say, a LET_STMT node + that represents a scope level), + including recursive output of contained blocks. + + STMT is the LET_STMT node. + DEPTH is its depth within containing symbol blocks. + ARGS is usually zero; but for the outermost block of the + body of a function, it is a chain of PARM_DECLs for the function parameters. + We output definitions of all the register parms + as if they were local variables of that block. + + Actually, STMT may be several statements chained together. + We handle them all in sequence. */ + +static void +dbxout_block (stmt, depth, args) + register tree stmt; + int depth; + tree args; +{ + int blocknum; + + while (stmt) + { + switch (TREE_CODE (stmt)) + { + case COMPOUND_STMT: + case LOOP_STMT: + dbxout_block (STMT_BODY (stmt), depth, 0); + break; + + case IF_STMT: + dbxout_block (STMT_THEN (stmt), depth, 0); + dbxout_block (STMT_ELSE (stmt), depth, 0); + break; + + case LET_STMT: + /* Ignore LET_STMTs for blocks never really used to make RTL. */ + if (! TREE_USED (stmt)) + break; + /* In dbx format, the syms of a block come before the N_LBRAC. */ + dbxout_tags (STMT_TYPE_TAGS (stmt)); + dbxout_syms (STMT_VARS (stmt)); + if (args) + dbxout_reg_parms (args); + + /* Now output an N_LBRAC symbol to represent the beginning of + the block. Use the block's tree-walk order to generate + the assembler symbols LBBn and LBEn + that final will define around the code in this block. */ + if (depth > 0) + { + char buf[20]; + blocknum = next_block_number++; + ASM_GENERATE_INTERNAL_LABEL (buf, "LBB", blocknum); + fprintf (asmfile, ".stabn %d,0,0,", N_LBRAC); + assemble_name (asmfile, buf); + fprintf (asmfile, "\n"); + } + + /* Output the subblocks. */ + dbxout_block (STMT_SUBBLOCKS (stmt), depth + 1, 0); + + /* Refer to the marker for the end of the block. */ + if (depth > 0) + { + char buf[20]; + ASM_GENERATE_INTERNAL_LABEL (buf, "LBE", blocknum); + fprintf (asmfile, ".stabn %d,0,0,", N_RBRAC); + assemble_name (asmfile, buf); + fprintf (asmfile, "\n"); + } + } + stmt = TREE_CHAIN (stmt); + } +} + +/* Output dbx data for a function definition. + This includes a definition of the function name itself (a symbol), + definitions of the parameters (locating them in the parameter list) + and then output the block that makes up the function's body + (including all the auto variables of the function). */ + +void +dbxout_function (decl) + tree decl; +{ + dbxout_symbol (decl, 0); + dbxout_parms (DECL_ARGUMENTS (decl)); + dbxout_block (DECL_INITIAL (decl), 0, DECL_ARGUMENTS (decl)); + + /* If we made any temporary types in this fn that weren't + output, output them now. */ + dbxout_types (get_temporary_types ()); +} + +#else /* not DBX_DEBUGGING_INFO */ + +void +dbxout_init (asm_file, input_file_name) + FILE *asm_file; + char *input_file_name; +{} + +void +dbxout_symbol (decl, local) + tree decl; + int local; +{} + +void +dbxout_types (types) + register tree types; +{} + +void +dbxout_tags (tags) + tree tags; +{} + +void +dbxout_function (decl) + tree decl; +{} + +#endif /* DBX_DEBUGGING_INFO */ diff --git a/gcc-1.40/ecoff-cmp b/gcc-1.40/ecoff-cmp new file mode 100755 index 0000000..d7842f1 --- /dev/null +++ b/gcc-1.40/ecoff-cmp @@ -0,0 +1,12 @@ +#!/bin/sh +# +# ecoff-cmp file1.o file2.o +# +cp $1 /tmp/foo1.$$ +cp $2 /tmp/foo2.$$ +strip /tmp/foo1.$$ +strip /tmp/foo2.$$ +tail +10c /tmp/foo1.$$ > /tmp/foo3.$$ +tail +10c /tmp/foo2.$$ > /tmp/foo4.$$ +cmp /tmp/foo3.$$ /tmp/foo4.$$ +rm -f /tmp/foo[1234].$$ diff --git a/gcc-1.40/emit-rtl.c b/gcc-1.40/emit-rtl.c new file mode 100644 index 0000000..6d1ea3b --- /dev/null +++ b/gcc-1.40/emit-rtl.c @@ -0,0 +1,1633 @@ +/* Emit RTL for the GNU C-Compiler expander. + Copyright (C) 1987, 1988 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 1, 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. */ + + +/* Middle-to-low level generation of rtx code and insns. + + This file contains the functions `gen_rtx', `gen_reg_rtx' + and `gen_label_rtx' that are the usual ways of creating rtl + expressions for most purposes. + + It also has the functions for creating insns and linking + them in the doubly-linked chain. + + The patterns of the insns are created by machine-dependent + routines in insn-emit.c, which is generated automatically from + the machine description. These routines use `gen_rtx' to make + the individual rtx's of the pattern; what is machine dependent + is the kind of rtx's they make and what arguments they use. */ + +#include "config.h" +#include +#include "gvarargs.h" +#include "rtl.h" +#include "regs.h" +#include "insn-config.h" +#include "real.h" + +#define max(A,B) ((A) > (B) ? (A) : (B)) +#define min(A,B) ((A) < (B) ? (A) : (B)) + +/* This is reset to FIRST_PSEUDO_REGISTER at the start each function. + After rtl generation, it is 1 plus the largest register number used. */ + +int reg_rtx_no = FIRST_PSEUDO_REGISTER; + +/* This is *not* reset after each function. It gives each CODE_LABEL + in the entire compilation a unique label number. */ + +static int label_num = 1; + +/* Value of `label_num' at start of current function. */ + +static int first_label_num; + +/* Nonzero means do not generate NOTEs for source line numbers. */ + +static int no_line_numbers; + +/* Commonly used rtx's, so that we only need space for one copy. + These are initialized once for the entire compilation. + All of these except perhaps fconst0_rtx and dconst0_rtx + 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 fconst0_rtx; /* (CONST_DOUBLE:SF 0) */ +rtx dconst0_rtx; /* (CONST_DOUBLE:DF 0) */ + +/* All references to the following fixed hard registers go through + these unique rtl objects. On machines where the frame-pointer and + arg-pointer are the same register, they use the same unique object. + + After register allocation, other rtl objects which used to be pseudo-regs + may be clobbered to refer to the frame-pointer register. + But references that were originally to the frame-pointer can be + distinguished from the others because they contain frame_pointer_rtx. + + 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 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) */ + +/* 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. + + start_sequence saves both of these on `sequence_stack' and then + starts a new, nested sequence of insns. */ + +static rtx first_insn = NULL; +static rtx last_insn = NULL; + +/* Stack of pending (incomplete) sequences saved by `start_sequence'. + This looks like + (INSN_LIST saved-first-insn + (INSN_LIST saved-last-insn ...more saved sequences...)). + The main insn-chain is saved in the last two links of the chain, + unless the chain is empty. */ + +rtx sequence_stack = 0; + +/* INSN_UID for next insn emitted. + Reset to 1 for each function compiled. */ + +static int cur_insn_uid = 1; + +/* Line number and source file of the last line-number NOTE emitted. + This is used to avoid generating duplicates. */ + +static int last_linenum = 0; +static char *last_filename = 0; + +/* A vector indexed by pseudo reg number. The allocated length + of this vector is regno_pointer_flag_length. Since this + vector is needed during the expansion phase when the total + number of registers in the function is not yet known, + it is copied and made bigger when necessary. */ + +char *regno_pointer_flag; +int regno_pointer_flag_length; + +/* Indexed by pseudo register number, gives the rtx for that pseudo. + Allocated in parallel with regno_pointer_flag. */ + +rtx *regno_reg_rtx; + +/* Filename and line number of last line-number note, + whether we actually emitted it or not. */ +extern char *emit_filename; +extern int emit_lineno; + +rtx change_address (); + +/* rtx gen_rtx (code, mode, [element1, ..., elementn]) +** +** This routine generates an RTX of the size specified by +** , which is an RTX code. The RTX structure is initialized +** from the arguments through , which are +** interpreted according to the specific RTX type's format. The +** special machine mode associated with the rtx (if any) is specified +** in . +** +** gen_rtx() can be invoked in a way which resembles the lisp-like +** rtx it will generate. For example, the following rtx structure: +** +** (plus:QI (mem:QI (reg:SI 1)) +** (mem:QI (plusw:SI (reg:SI 2) (reg:SI 3)))) +** +** ...would be generated by the following C code: +** +** gen_rtx (PLUS, QImode, +** gen_rtx (MEM, QImode, +** gen_rtx (REG, SImode, 1)), +** gen_rtx (MEM, QImode, +** gen_rtx (PLUS, SImode, +** gen_rtx (REG, SImode, 2), +** gen_rtx (REG, SImode, 3)))), +*/ + +/*VARARGS2*/ +rtx +gen_rtx (va_alist) + va_dcl +{ + va_list p; + enum rtx_code code; + enum machine_mode mode; + register int i; /* Array indices... */ + register char *fmt; /* Current rtx's format... */ + register rtx rt_val; /* RTX to return to caller... */ + + va_start (p); + code = va_arg (p, enum rtx_code); + mode = va_arg (p, enum machine_mode); + + if (code == CONST_INT) + { + int arg = va_arg (p, int); + if (arg == 0) + return const0_rtx; + if (arg == 1) + return const1_rtx; + rt_val = rtx_alloc (code); + INTVAL (rt_val) = arg; + } + else + { + rt_val = rtx_alloc (code); /* Allocate the storage space. */ + rt_val->mode = mode; /* Store the machine mode... */ + + fmt = GET_RTX_FORMAT (code); /* Find the right format... */ + for (i = 0; i < GET_RTX_LENGTH (code); i++) + { + switch (*fmt++) + { + case '0': /* Unused field. */ + break; + + case 'i': /* An integer? */ + XINT (rt_val, i) = va_arg (p, int); + break; + + case 's': /* A string? */ + XSTR (rt_val, i) = va_arg (p, char *); + break; + + case 'e': /* An expression? */ + case 'u': /* An insn? Same except when printing. */ + XEXP (rt_val, i) = va_arg (p, rtx); + break; + + case 'E': /* An RTX vector? */ + XVEC (rt_val, i) = va_arg (p, rtvec); + break; + + default: + abort(); + } + } + } + va_end (p); + return rt_val; /* Return the new RTX... */ +} + +/* gen_rtvec (n, [rt1, ..., rtn]) +** +** This routine creates an rtvec and stores within it the +** pointers to rtx's which are its arguments. +*/ + +/*VARARGS1*/ +rtvec +gen_rtvec (va_alist) + va_dcl +{ + int n, i; + va_list p; + rtx *vector; + + va_start (p); + n = va_arg (p, int); + + if (n == 0) + return NULL_RTVEC; /* Don't allocate an empty rtvec... */ + + vector = (rtx *) alloca (n * sizeof (rtx)); + for (i = 0; i < n; i++) + vector[i] = va_arg (p, rtx); + va_end (p); + + return gen_rtvec_v (n, vector); +} + +rtvec +gen_rtvec_v (n, argp) + int n; + rtx *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++; + + return rt_val; +} + +/* Generate a REG rtx for a new pseudo register of mode MODE. + This pseudo is assigned the next sequential register number. */ + +rtx +gen_reg_rtx (mode) + enum machine_mode mode; +{ + register rtx val; + + /* Make sure regno_pointer_flag and regno_reg_rtx are large + enough to have an element for this pseudo reg number. */ + + if (reg_rtx_no == regno_pointer_flag_length) + { + rtx *new1; + char *new = + (char *) oballoc (regno_pointer_flag_length * 2); + bzero (new, regno_pointer_flag_length * 2); + bcopy (regno_pointer_flag, new, regno_pointer_flag_length); + regno_pointer_flag = new; + + new1 = (rtx *) oballoc (regno_pointer_flag_length * 2 * sizeof (rtx)); + bzero (new1, regno_pointer_flag_length * 2 * sizeof (rtx)); + bcopy (regno_reg_rtx, new1, regno_pointer_flag_length * sizeof (rtx)); + regno_reg_rtx = new1; + + regno_pointer_flag_length *= 2; + } + + val = gen_rtx (REG, mode, reg_rtx_no); + regno_reg_rtx[reg_rtx_no++] = val; + return val; +} + +/* Identify REG as a probable pointer register. */ + +void +mark_reg_pointer (reg) + rtx reg; +{ + REGNO_POINTER_FLAG (REGNO (reg)) = 1; +} + +/* Return 1 plus largest pseudo reg number used in the current function. */ + +int +max_reg_num () +{ + return reg_rtx_no; +} + +/* Return 1 + the largest label number used so far. */ + +int +max_label_num () +{ + return label_num; +} + +/* Return first label number used in this function (if any were used). */ + +int +get_first_label_num () +{ + return first_label_num; +} + +/* Assuming that X is an rtx (MEM, REG or SUBREG) for a fixed-point number, + return a MEM or SUBREG rtx that refers to the least-significant part of X. + MODE specifies how big a part of X to return; + it must not be larger than a word. + If X is a MEM whose address is a QUEUED, the value may be so also. */ + +rtx +gen_lowpart (mode, x) + enum machine_mode mode; + register rtx x; +{ + /* This case loses if X is a subreg. To catch bugs early, + complain if an invalid MODE is used even in other cases. */ + if (GET_MODE_SIZE (mode) > UNITS_PER_WORD + && GET_MODE_SIZE (mode) != GET_MODE_UNIT_SIZE (GET_MODE (x))) + abort (); + if (GET_MODE (x) == mode) + return x; + if (GET_CODE (x) == CONST_INT) + return gen_rtx (CONST_INT, VOIDmode, INTVAL (x) & GET_MODE_MASK (mode)); + if (GET_CODE (x) == CONST_DOUBLE) +/* In version 1.37, try this: */ +/* if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT) abort (); */ + /* Assume it's an int, so ..._LOW means the low-order word. */ + return gen_rtx (CONST_INT, VOIDmode, + CONST_DOUBLE_LOW (x) & GET_MODE_MASK (mode)); + if (GET_CODE (x) == MEM) + { + register int offset = 0; +#ifdef WORDS_BIG_ENDIAN + offset = (max (GET_MODE_SIZE (GET_MODE (x)), UNITS_PER_WORD) + - max (GET_MODE_SIZE (mode), UNITS_PER_WORD)); +#endif +#ifdef BYTES_BIG_ENDIAN + /* Adjust the address so that the address-after-the-data + is unchanged. */ + offset -= (min (UNITS_PER_WORD, GET_MODE_SIZE (mode)) + - min (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (x)))); +#endif + return change_address (x, mode, plus_constant (XEXP (x, 0), offset)); + } + else if (GET_CODE (x) == SUBREG) + return (GET_MODE (SUBREG_REG (x)) == mode && SUBREG_WORD (x) == 0 + ? SUBREG_REG (x) + : gen_rtx (SUBREG, mode, SUBREG_REG (x), SUBREG_WORD (x))); + else if (GET_CODE (x) == REG) + { +#ifdef WORDS_BIG_ENDIAN + if (GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD) + { + return gen_rtx (SUBREG, mode, x, + ((GET_MODE_SIZE (GET_MODE (x)) + - max (GET_MODE_SIZE (mode), UNITS_PER_WORD)) + / UNITS_PER_WORD)); + } +#endif + return gen_rtx (SUBREG, mode, x, 0); + } + else + abort (); +} + +/* Like `gen_lowpart', but refer to the most significant part. */ + +rtx +gen_highpart (mode, x) + enum machine_mode mode; + register rtx x; +{ + if (GET_CODE (x) == MEM) + { + register int offset = 0; +#ifndef WORDS_BIG_ENDIAN + offset = (max (GET_MODE_SIZE (GET_MODE (x)), UNITS_PER_WORD) + - max (GET_MODE_SIZE (mode), UNITS_PER_WORD)); +#endif +#ifndef BYTES_BIG_ENDIAN + if (GET_MODE_SIZE (mode) < UNITS_PER_WORD) + offset -= (GET_MODE_SIZE (mode) + - min (UNITS_PER_WORD, + GET_MODE_SIZE (GET_MODE (x)))); +#endif + return change_address (x, mode, plus_constant (XEXP (x, 0), offset)); + } + else if (GET_CODE (x) == REG) + { +#ifndef WORDS_BIG_ENDIAN + if (GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD) + { + return gen_rtx (SUBREG, mode, x, + ((GET_MODE_SIZE (GET_MODE (x)) + - max (GET_MODE_SIZE (mode), UNITS_PER_WORD)) + / UNITS_PER_WORD)); + } +#endif + return gen_rtx (SUBREG, mode, x, 0); + } + else + abort (); +} + +/* Return 1 iff X, assumed to be a SUBREG, + refers to the least significant part of its containing reg. + If X is not a SUBREG, always return 1 (it is its own low part!). */ + +int +subreg_lowpart_p (x) + rtx x; +{ + if (GET_CODE (x) != SUBREG) + return 1; +#ifdef WORDS_BIG_ENDIAN + if (GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD) + { + register enum machine_mode mode = GET_MODE (SUBREG_REG (x)); + return (SUBREG_WORD (x) + == ((GET_MODE_SIZE (GET_MODE (x)) + - max (GET_MODE_SIZE (mode), UNITS_PER_WORD)) + / UNITS_PER_WORD)); + } +#endif + return SUBREG_WORD (x) == 0; +} + +/* Return a memory reference like MEMREF, but with its mode changed + to MODE and its address changed to ADDR. + (VOIDmode means don't change the mode. + NULL for ADDR means don't change the address.) */ + +rtx +change_address (memref, mode, addr) + rtx memref; + enum machine_mode mode; + rtx addr; +{ + rtx new; + + if (GET_CODE (memref) != MEM) + abort (); + if (mode == VOIDmode) + mode = GET_MODE (memref); + if (addr == 0) + addr = XEXP (memref, 0); + + new = gen_rtx (MEM, mode, memory_address (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); + return new; +} + +/* Return a newly created CODE_LABEL rtx with a unique label number. */ + +rtx +gen_label_rtx () +{ + register rtx label = gen_rtx (CODE_LABEL, VOIDmode, 0, 0, 0, label_num++); + LABEL_NUSES (label) = 0; + return label; +} + +/* For procedure integration. */ + +/* Return a newly created INLINE_HEADER rtx. Should allocate this + from a permanent obstack when the opportunity arises. */ + +rtx +gen_inline_header_rtx (insn, last_insn, + first_labelno, last_labelno, + max_parm_regnum, max_regnum, args_size, + stack_slots) + rtx insn, last_insn; + int first_labelno, last_labelno, max_parm_regnum, max_regnum, args_size; + rtx stack_slots; +{ + rtx header = gen_rtx (INLINE_HEADER, VOIDmode, + cur_insn_uid++, NULL, + insn, last_insn, + first_labelno, last_labelno, + max_parm_regnum, max_regnum, args_size, stack_slots); + return header; +} + +/* Install new pointers to the first and last insns in the chain. + Used for an inline-procedure after copying the insn chain. */ + +void +set_new_first_and_last_insn (first, last) + rtx first, last; +{ + first_insn = first; + last_insn = last; +} + +/* Go through all the RTL insn bodies and copy any invalid shared structure. + It does not work to do this twice, because the mark bits set here + are not cleared afterwards. */ + +static int unshare_copies = 0; /* Count rtx's that were copied. */ + +static rtx copy_rtx_if_shared (); + +void +unshare_all_rtl (insn) + register rtx insn; +{ + extern rtx stack_slot_list; + + for (; insn; insn = NEXT_INSN (insn)) + if (GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN + || GET_CODE (insn) == CALL_INSN) + { + PATTERN (insn) = copy_rtx_if_shared (PATTERN (insn)); + REG_NOTES (insn) = copy_rtx_if_shared (REG_NOTES (insn)); + LOG_LINKS (insn) = copy_rtx_if_shared (LOG_LINKS (insn)); + } + + /* Make sure the addresses of stack slots are not shared + with anything in the insn chain. That could happen if + the stack slot is referenced only by its address. */ + copy_rtx_if_shared (stack_slot_list); +} + +/* Mark ORIG as in use, and return a copy of it if it was already in use. + Recursively does the same for subexpressions. */ + +static rtx +copy_rtx_if_shared (orig) + rtx orig; +{ + register rtx x = orig; + register int i; + register enum rtx_code code; + register char *format_ptr; + int copied = 0; + + if (x == 0) + return 0; + + code = GET_CODE (x); + + /* These types may be freely shared. */ + + switch (code) + { + case REG: + case QUEUED: + case CONST_INT: + case CONST_DOUBLE: + case SYMBOL_REF: + case CODE_LABEL: + case PC: + case CC0: + return x; + + case INSN: + case JUMP_INSN: + case CALL_INSN: + case NOTE: + case LABEL_REF: + case BARRIER: + /* The chain of insns is not being copied. */ + return x; + + case MEM: + /* A MEM is allowed to be shared if its address is constant + or is a constant plus one of the special registers. */ + if (CONSTANT_ADDRESS_P (XEXP (x, 0))) + return x; + if (GET_CODE (XEXP (x, 0)) == PLUS + && (XEXP (XEXP (x, 0), 0) == frame_pointer_rtx + || XEXP (XEXP (x, 0), 0) == arg_pointer_rtx) + && CONSTANT_ADDRESS_P (XEXP (XEXP (x, 0), 1))) + { + /* This MEM can appear in more than one place, + but its address better not be shared with anything else. */ + if (! x->used) + XEXP (x, 0) = copy_rtx_if_shared (XEXP (x, 0)); + x->used = 1; + return x; + } + if (XEXP (x, 0) == frame_pointer_rtx + || XEXP (x, 0) == arg_pointer_rtx) + return x; + } + + /* This rtx may not be shared. If it has already been seen, + replace it with a copy of itself. */ + + if (x->used) + { + register rtx copy; + + unshare_copies++; + + copy = rtx_alloc (code); + bcopy (x, copy, (sizeof (*copy) - sizeof (copy->fld) + + sizeof (copy->fld[0]) * GET_RTX_LENGTH (code))); + x = copy; + copied = 1; + } + x->used = 1; + + /* Now scan the subexpressions recursively. + We can store any replaced subexpressions directly into X + since we know X is not shared! Any vectors in X + must be copied if X was copied. */ + + format_ptr = GET_RTX_FORMAT (code); + + for (i = 0; i < GET_RTX_LENGTH (code); i++) + { + switch (*format_ptr++) + { + case 'e': + XEXP (x, i) = copy_rtx_if_shared (XEXP (x, i)); + break; + + case 'E': + if (XVEC (x, i) != NULL) + { + register int j; + + if (copied) + XVEC (x, i) = gen_rtvec_v (XVECLEN (x, i), &XVECEXP (x, i, 0)); + for (j = 0; j < XVECLEN (x, i); j++) + XVECEXP (x, i, j) + = copy_rtx_if_shared (XVECEXP (x, i, j)); + } + break; + } + } + return x; +} + +/* Copy X if necessary so that it won't be altered by changes in OTHER. + Return X or the rtx for the pseudo reg the value of X was copied into. + OTHER must be valid as a SET_DEST. */ + +rtx +make_safe_from (x, other) + rtx x, other; +{ + while (1) + switch (GET_CODE (other)) + { + case SUBREG: + other = SUBREG_REG (other); + break; + case STRICT_LOW_PART: + case SIGN_EXTEND: + case ZERO_EXTEND: + other = XEXP (other, 0); + break; + default: + goto done; + } + done: + if ((GET_CODE (other) == MEM + && ! CONSTANT_P (x) + && GET_CODE (x) != CONST_DOUBLE + && GET_CODE (x) != REG + && GET_CODE (x) != SUBREG) + || (GET_CODE (other) == REG + && (REGNO (other) < FIRST_PSEUDO_REGISTER + || reg_mentioned_p (other, x)))) + { + rtx temp = gen_reg_rtx (GET_MODE (x)); + emit_move_insn (temp, x); + return temp; + } + return x; +} + +/* Emission of insns (adding them to the doubly-linked list). */ + +/* Return the first insn of the current sequence or current function. */ + +rtx +get_insns () +{ + return first_insn; +} + +/* Return the last insn emitted in current sequence or current function. */ + +rtx +get_last_insn () +{ + return last_insn; +} + +/* Specify a new insn as the last in the chain. */ + +void +set_last_insn (insn) + rtx insn; +{ + if (NEXT_INSN (insn) != 0) + abort (); + last_insn = insn; +} + +/* Return a number larger than any instruction's uid in this function. */ + +int +get_max_uid () +{ + return cur_insn_uid; +} + +rtx +next_insn (insn) + rtx insn; +{ + if (insn) return NEXT_INSN (insn); + return 0; +} + +rtx +previous_insn (insn) + rtx insn; +{ + if (insn) return PREV_INSN (insn); + return 0; +} + +/* Make and return an INSN rtx, initializing all its slots. + Store PATTERN in the pattern slots. + PAT_FORMALS is an idea that never really went anywhere. */ + +static rtx +make_insn_raw (pattern, pat_formals) + rtx pattern; + rtvec pat_formals; +{ + register rtx insn; + + insn = rtx_alloc(INSN); + INSN_UID(insn) = cur_insn_uid++; + + PATTERN (insn) = pattern; + INSN_CODE (insn) = -1; + LOG_LINKS(insn) = NULL; + REG_NOTES(insn) = NULL; + + return insn; +} + +/* Like `make_insn' but make a JUMP_INSN instead of an insn. */ + +static rtx +make_jump_insn_raw (pattern, pat_formals) + rtx pattern; + rtvec pat_formals; +{ + register rtx insn; + + insn = rtx_alloc(JUMP_INSN); + INSN_UID(insn) = cur_insn_uid++; + + PATTERN (insn) = pattern; + INSN_CODE (insn) = -1; + LOG_LINKS(insn) = NULL; + REG_NOTES(insn) = NULL; + JUMP_LABEL(insn) = NULL; + + return insn; +} + +/* Add INSN to the end of the doubly-linked list. + INSN may be an INSN, JUMP_INSN, CALL_INSN, CODE_LABEL, BARRIER or NOTE. */ + +static void +add_insn (insn) + register rtx insn; +{ + PREV_INSN (insn) = last_insn; + NEXT_INSN (insn) = 0; + + if (NULL != last_insn) + NEXT_INSN (last_insn) = insn; + + if (NULL == first_insn) + first_insn = insn; + + last_insn = insn; +} + +/* Add INSN, an rtx of code INSN, into the doubly-linked list + after insn AFTER. */ + +static void +add_insn_after (insn, after) + rtx insn, after; +{ + NEXT_INSN (insn) = NEXT_INSN (after); + PREV_INSN (insn) = after; + + if (NEXT_INSN (insn)) + PREV_INSN (NEXT_INSN (insn)) = insn; + else if (last_insn == after) + last_insn = insn; + else + { + rtx stack = sequence_stack; + /* Scan all pending sequences too. */ + for (; stack; stack = XEXP (XEXP (stack, 1), 1)) + if (after == XEXP (XEXP (stack, 1), 0)) + XEXP (XEXP (stack, 1), 0) = insn; + } + + NEXT_INSN (after) = insn; +} + +/* Delete all insns made since FROM. + FROM becomes the new last instruction. */ + +void +delete_insns_since (from) + rtx from; +{ + if (from == 0) + first_insn = 0; + else + NEXT_INSN (from) = 0; + last_insn = from; +} + +/* Move a consecutive bunch of insns to a different place in the chain. + The insns to be moved are those between FROM and TO. + They are moved to a new position after the insn AFTER. */ + +void +reorder_insns (from, to, after) + rtx from, to, after; +{ + /* Splice this bunch out of where it is now. */ + if (PREV_INSN (from)) + NEXT_INSN (PREV_INSN (from)) = NEXT_INSN (to); + if (NEXT_INSN (to)) + PREV_INSN (NEXT_INSN (to)) = PREV_INSN (from); + if (last_insn == to) + last_insn = PREV_INSN (from); + if (first_insn == from) + first_insn = NEXT_INSN (to); + + /* Make the new neighbors point to it and it to them. */ + if (NEXT_INSN (after)) + { + PREV_INSN (NEXT_INSN (after)) = to; + NEXT_INSN (to) = NEXT_INSN (after); + } + PREV_INSN (from) = after; + NEXT_INSN (after) = from; + if (after == last_insn) + last_insn = to; +} + +/* Emit an insn of given code and pattern + at a specified place within the doubly-linked list. */ + +/* Make an instruction with body PATTERN + and output it before the instruction BEFORE. */ + +rtx +emit_insn_before (pattern, before) + register rtx pattern, before; +{ + register rtx insn; + + if (GET_CODE (pattern) == SEQUENCE) + { + register int i; + /* For an empty sequence, emit nothing. */ + if (XVEC (pattern, 0)) + for (i = 0; i < XVECLEN (pattern, 0); i++) + add_insn_after (XVECEXP (pattern, 0, i), PREV_INSN (before)); + return PREV_INSN (before); + } + + insn = make_insn_raw (pattern, 0); + + PREV_INSN (insn) = PREV_INSN (before); + NEXT_INSN (insn) = before; + + if (PREV_INSN (insn)) + NEXT_INSN (PREV_INSN (insn)) = insn; + else + first_insn = insn; + PREV_INSN (before) = insn; + + return insn; +} + +/* Make an instruction with body PATTERN and code JUMP_INSN + and output it before the instruction BEFORE. */ + +rtx +emit_jump_insn_before (pattern, before) + register rtx pattern, before; +{ + register rtx insn = make_jump_insn_raw (pattern, 0); + + PREV_INSN (insn) = PREV_INSN (before); + NEXT_INSN (insn) = before; + + if (PREV_INSN (insn)) + NEXT_INSN (PREV_INSN (insn)) = insn; + else + first_insn = insn; + PREV_INSN (before) = insn; + + return insn; +} + +/* Make an instruction with body PATTERN and code CALL_INSN + and output it before the instruction BEFORE. */ + +rtx +emit_call_insn_before (pattern, before) + register rtx pattern, before; +{ + rtx insn = emit_insn_before (pattern, before); + PUT_CODE (insn, CALL_INSN); + return insn; +} + +/* Make an insn of code INSN with body PATTERN + and output it after the insn AFTER. */ + +rtx +emit_insn_after (pattern, after) + register rtx pattern, after; +{ + if (GET_CODE (pattern) == SEQUENCE) + { + register int i; + /* For an empty sequence, emit nothing. */ + if (XVEC (pattern, 0)) + for (i = 0; i < XVECLEN (pattern, 0); i++) + { + add_insn_after (XVECEXP (pattern, 0, i), after); + after = NEXT_INSN (after); + } + return after; + } + else + { + register rtx insn = make_insn_raw (pattern, 0); + add_insn_after (insn, after); + return insn; + } +} + +/* Make an insn of code JUMP_INSN with body PATTERN + and output it after the insn AFTER. */ + +rtx +emit_jump_insn_after (pattern, after) + register rtx pattern, after; +{ + register rtx insn = make_jump_insn_raw (pattern, 0); + + add_insn_after (insn, after); + return insn; +} + +/* Make an insn of code BARRIER + and output it after the insn AFTER. */ + +rtx +emit_barrier_after (after) + register rtx after; +{ + register rtx insn = rtx_alloc (BARRIER); + + INSN_UID (insn) = cur_insn_uid++; + + add_insn_after (insn, after); + return insn; +} + +/* Emit the label LABEL after the insn AFTER. */ + +void +emit_label_after (label, after) + rtx label, after; +{ + /* This can be called twice for the same label + as a result of the confusion that follows a syntax error! + So make it harmless. */ + if (INSN_UID (label) == 0) + { + INSN_UID (label) = cur_insn_uid++; + add_insn_after (label, after); + } +} + +/* Emit a note of subtype SUBTYPE after the insn AFTER. */ + +void +emit_note_after (subtype, after) + int subtype; + rtx after; +{ + register rtx note = rtx_alloc (NOTE); + INSN_UID (note) = cur_insn_uid++; + XSTR (note, 3) = 0; + XINT (note, 4) = subtype; + add_insn_after (note, after); +} + +/* Make an insn of code INSN with pattern PATTERN + and add it to the end of the doubly-linked list. + If PATTERN is a SEQUENCE, take the elements of it + and emit an insn for each element. + + Returns the last insn emitted. */ + +rtx +emit_insn (pattern) + rtx pattern; +{ + rtx insn; + + if (GET_CODE (pattern) == SEQUENCE) + { + register int i; + /* For an empty sequence, emit nothing. */ + if (XVEC (pattern, 0)) + for (i = 0; i < XVECLEN (pattern, 0); i++) + add_insn (insn = XVECEXP (pattern, 0, i)); + } + else + { + insn = make_insn_raw (pattern, NULL); + add_insn (insn); + } + return insn; +} + +/* Emit the insns in a chain starting with INSN. */ + +rtx +emit_insns (insn) + rtx insn; +{ + while (insn) + { + rtx next = NEXT_INSN (insn); + add_insn (insn); + insn = next; + } +} + +/* Make an insn of code JUMP_INSN with pattern PATTERN + and add it to the end of the doubly-linked list. */ + +rtx +emit_jump_insn (pattern) + rtx pattern; +{ + if (GET_CODE (pattern) == SEQUENCE) + return emit_insn (pattern); + else + { + register rtx insn = make_jump_insn_raw (pattern, NULL); + add_insn (insn); + return insn; + } +} + +/* Make an insn of code CALL_INSN with pattern PATTERN + and add it to the end of the doubly-linked list. */ + +rtx +emit_call_insn (pattern) + rtx pattern; +{ + if (GET_CODE (pattern) == SEQUENCE) + return emit_insn (pattern); + else + { + register rtx insn = make_insn_raw (pattern, NULL); + add_insn (insn); + PUT_CODE (insn, CALL_INSN); + return insn; + } +} + +/* Add the label LABEL to the end of the doubly-linked list. */ + +rtx +emit_label (label) + rtx label; +{ + /* This can be called twice for the same label + as a result of the confusion that follows a syntax error! + So make it harmless. */ + if (INSN_UID (label) == 0) + { + INSN_UID (label) = cur_insn_uid++; + add_insn (label); + } + return label; +} + +/* Make an insn of code BARRIER + and add it to the end of the doubly-linked list. */ + +rtx +emit_barrier () +{ + register rtx barrier = rtx_alloc (BARRIER); + INSN_UID (barrier) = cur_insn_uid++; + add_insn (barrier); + return barrier; +} + +/* Make an insn of code NOTE + with data-fields specified by FILE and LINE + and add it to the end of the doubly-linked list, + but only if line-numbers are desired for debugging info. */ + +rtx +emit_line_note (file, line) + char *file; + int line; +{ + emit_filename = file; + emit_lineno = line; + +#if 0 + if (no_line_numbers) + return 0; +#endif + + return emit_note (file, line); +} + +/* Make an insn of code NOTE + with data-fields specified by FILE and LINE + and add it to the end of the doubly-linked list. + If it is a line-number NOTE, omit it if it matches the previous one. */ + +rtx +emit_note (file, line) + char *file; + int line; +{ + register rtx note; + + if (line > 0) + { + if (file && last_filename && !strcmp (file, last_filename) + && line == last_linenum) + return 0; + last_filename = file; + last_linenum = line; + } + + if (no_line_numbers && line > 0) + { + cur_insn_uid++; + return 0; + } + + note = rtx_alloc (NOTE); + INSN_UID (note) = cur_insn_uid++; + XSTR (note, 3) = file; + XINT (note, 4) = line; + add_insn (note); + return note; +} + +/* Emit a NOTE, and don't omit it even if LINE it the previous note. */ + +rtx +emit_line_note_force (file, line) + char *file; + int line; +{ + last_linenum = -1; + return emit_line_note (file, line); +} + +/* Cause next statement to emit a line note even if the line number + has not changed. This is used at the beginning of a function. */ + +void +force_next_line_note () +{ + last_linenum = -1; +} + +/* Return an indication of which type of insn should have X as a body. + The value is CODE_LABEL, INSN, CALL_INSN or JUMP_INSN. */ + +enum rtx_code +classify_insn (x) + rtx x; +{ + if (GET_CODE (x) == CODE_LABEL) + return CODE_LABEL; + if (GET_CODE (x) == CALL) + return CALL_INSN; + if (GET_CODE (x) == RETURN) + return JUMP_INSN; + if (GET_CODE (x) == SET) + { + if (SET_DEST (x) == pc_rtx) + return JUMP_INSN; + else if (GET_CODE (SET_SRC (x)) == CALL) + return CALL_INSN; + else + return INSN; + } + if (GET_CODE (x) == PARALLEL) + { + register int j; + for (j = XVECLEN (x, 0) - 1; j >= 0; j--) + if (GET_CODE (XVECEXP (x, 0, j)) == CALL) + return CALL_INSN; + else if (GET_CODE (XVECEXP (x, 0, j)) == SET + && SET_DEST (XVECEXP (x, 0, j)) == pc_rtx) + return JUMP_INSN; + else if (GET_CODE (XVECEXP (x, 0, j)) == SET + && GET_CODE (SET_SRC (XVECEXP (x, 0, j))) == CALL) + return CALL_INSN; + } + return INSN; +} + +/* Emit the rtl pattern X as an appropriate kind of insn. + If X is a label, it is simply added into the insn chain. */ + +void +emit (x) + rtx x; +{ + enum rtx_code code = classify_insn (x); + + if (code == CODE_LABEL) + emit_label (x); + else if (code == INSN) + emit_insn (x); + else if (code == JUMP_INSN) + { + register rtx insn = emit_jump_insn (x); + if (simplejump_p (insn) || GET_CODE (x) == RETURN) + emit_barrier (); + } + else if (code == CALL_INSN) + emit_call_insn (x); +} + +/* Begin emitting insns to a sequence which can be packaged in an RTL_EXPR. + Return an rtx containing data on any sequence already in progress. */ + +rtx +start_sequence () +{ + sequence_stack + = gen_rtx (INSN_LIST, VOIDmode, + first_insn, gen_rtx (INSN_LIST, VOIDmode, + last_insn, sequence_stack)); + first_insn = 0; + last_insn = 0; + return sequence_stack; +} + +/* Set up the insn chain starting with FIRST + as the current sequence, saving the previously current one. */ + +void +push_to_sequence (first) + rtx first; +{ + rtx last; + for (last = first; last && NEXT_INSN (last); last = NEXT_INSN (last)); + sequence_stack + = gen_rtx (INSN_LIST, VOIDmode, + first_insn, gen_rtx (INSN_LIST, VOIDmode, + last_insn, sequence_stack)); + first_insn = first; + last_insn = last; +} + +/* After emitting to a sequence, restore previous saved state. + The argument SAVED is no longer used. + + To get the contents of the sequence just made, + you must call `gen_sequence' *before* calling here. */ + +void +end_sequence (saved) + rtx saved; +{ + first_insn = XEXP (sequence_stack, 0); + last_insn = XEXP (XEXP (sequence_stack, 1), 0); + sequence_stack = XEXP (XEXP (sequence_stack, 1), 1); +} + +/* Generate a SEQUENCE rtx containing the insns already emitted + to the current sequence. + + This is how the gen_... function from a DEFINE_EXPAND + constructs the SEQUENCE that it returns. */ + +rtx +gen_sequence () +{ + rtx tem; + rtvec newvec; + int i; + int len; + + /* Count the insns in the chain. */ + len = 0; + for (tem = first_insn; tem; tem = NEXT_INSN (tem)) + len++; + + /* For an empty sequence... */ + if (len == 0) + return gen_rtx (SEQUENCE, VOIDmode, NULL); + + /* If only one insn, return its pattern rather than a SEQUENCE. */ + if (len == 1 + && (GET_CODE (first_insn) == INSN + || GET_CODE (first_insn) == JUMP_INSN + || GET_CODE (first_insn) == CALL_INSN)) + return PATTERN (first_insn); + + /* Put them in a vector. */ + newvec = rtvec_alloc (len); + i = 0; + for (tem = first_insn; tem; tem = NEXT_INSN (tem), i++) + newvec->elem[i].rtx = tem; + + /* Make a SEQUENCE from this vector. */ + return gen_rtx (SEQUENCE, VOIDmode, newvec); +} + +/* 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. */ + for (i = FIRST_PSEUDO_REGISTER; i < reg_rtx_no; i++) + if (regno_reg_rtx[i] == 0) + regno_reg_rtx[i] = gen_rtx (REG, SImode, 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 (new1, newlen * sizeof (rtx)); + bcopy (regno_reg_rtx, 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. + WRITE_SYMBOLS is nonzero if any kind of debugging info + is to be generated. */ + +void +init_emit (write_symbols) + int write_symbols; +{ + first_insn = NULL; + last_insn = NULL; + sequence_stack = NULL; + cur_insn_uid = 1; + reg_rtx_no = FIRST_PSEUDO_REGISTER; + last_linenum = 0; + last_filename = 0; + first_label_num = label_num; + + no_line_numbers = ! write_symbols; + + /* Init the tables that describe all the pseudo regs. */ + + regno_pointer_flag_length = FIRST_PSEUDO_REGISTER + 100; + + regno_pointer_flag + = (char *) oballoc (regno_pointer_flag_length); + bzero (regno_pointer_flag, regno_pointer_flag_length); + + regno_reg_rtx + = (rtx *) oballoc (regno_pointer_flag_length * sizeof (rtx)); + bzero (regno_reg_rtx, regno_pointer_flag_length * sizeof (rtx)); +} + +/* Create some permanent unique rtl objects shared between all functions. */ + +void +init_emit_once () +{ + /* 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. */ + const0_rtx = rtx_alloc (CONST_INT); + INTVAL (const0_rtx) = 0; + const1_rtx = rtx_alloc (CONST_INT); + INTVAL (const1_rtx) = 1; + + fconst0_rtx = rtx_alloc (CONST_DOUBLE); + dconst0_rtx = rtx_alloc (CONST_DOUBLE); + { + union real_extract u; +#ifdef REAL_IS_NOT_DOUBLE + bzero (&u, sizeof u); + u.d = REAL_VALUE_ATOF ("0"); +#else + u.d = 0; +#endif + + bcopy (&u, &CONST_DOUBLE_LOW (fconst0_rtx), sizeof u); + CONST_DOUBLE_MEM (fconst0_rtx) = cc0_rtx; + PUT_MODE (fconst0_rtx, SFmode); + + bcopy (&u, &CONST_DOUBLE_LOW (dconst0_rtx), sizeof u); + CONST_DOUBLE_MEM (dconst0_rtx) = cc0_rtx; + PUT_MODE (dconst0_rtx, DFmode); + } + + stack_pointer_rtx = gen_rtx (REG, Pmode, STACK_POINTER_REGNUM); + frame_pointer_rtx = gen_rtx (REG, Pmode, FRAME_POINTER_REGNUM); +#ifdef STRUCT_VALUE + struct_value_rtx = STRUCT_VALUE; +#else + struct_value_rtx = gen_rtx (REG, Pmode, STRUCT_VALUE_REGNUM); +#endif + +#ifdef STRUCT_VALUE_INCOMING + struct_value_incoming_rtx = STRUCT_VALUE_INCOMING; +#else +#ifdef STRUCT_VALUE_INCOMING_REGNUM + struct_value_incoming_rtx + = gen_rtx (REG, Pmode, STRUCT_VALUE_INCOMING_REGNUM); +#else + struct_value_incoming_rtx = struct_value_rtx; +#endif +#endif + + 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); + else +#endif + static_chain_incoming_rtx = static_chain_rtx; + + if (FRAME_POINTER_REGNUM == ARG_POINTER_REGNUM) + arg_pointer_rtx = frame_pointer_rtx; + else + arg_pointer_rtx = gen_rtx (REG, Pmode, ARG_POINTER_REGNUM); +} diff --git a/gcc-1.40/explow.c b/gcc-1.40/explow.c new file mode 100644 index 0000000..7b7ae2d --- /dev/null +++ b/gcc-1.40/explow.c @@ -0,0 +1,575 @@ +/* Subroutines for manipulating rtx's in semantically interesting ways. + Copyright (C) 1987 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 1, 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 "rtl.h" +#include "tree.h" +#include "flags.h" +#include "expr.h" + +/* Return an rtx for the sum of X and the integer C. */ + +rtx +plus_constant (x, c) + register rtx x; + register int c; +{ + register RTX_CODE code = GET_CODE (x); + register enum machine_mode mode = GET_MODE (x); + int all_constant = 0; + + if (c == 0) + return x; + + if (code == CONST_INT) + return gen_rtx (CONST_INT, VOIDmode, (INTVAL (x) + c)); + + /* If adding to something entirely constant, set a flag + so that we can add a CONST around the result. */ + if (code == CONST) + { + x = XEXP (x, 0); + all_constant = 1; + } + else if (code == SYMBOL_REF || code == LABEL_REF) + all_constant = 1; + + /* The interesting case is adding the integer to a sum. + Look for constant term in the sum and combine + with C. For an integer constant term, we make a combined + integer. For a constant term that is not an explicit integer, + we cannot really combine, but group them together anyway. */ + + if (GET_CODE (x) == PLUS) + { + if (GET_CODE (XEXP (x, 0)) == CONST_INT) + { + c += INTVAL (XEXP (x, 0)); + x = XEXP (x, 1); + } + else if (GET_CODE (XEXP (x, 1)) == CONST_INT) + { + c += INTVAL (XEXP (x, 1)); + x = XEXP (x, 0); + } + else if (CONSTANT_P (XEXP (x, 0))) + { + 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)); + } +#ifdef OLD_INDEXING + /* Detect adding a constant to an indexed address + of the form (PLUS (MULT (REG) (CONST)) regs-and-constants). + Keep the (MULT ...) at the top level of addition so that + the result is still suitable for indexing and constants + are combined. */ + else if (GET_CODE (XEXP (x, 0)) == MULT) + { + return gen_rtx (PLUS, mode, XEXP (x, 0), + plus_constant (XEXP (x, 1), c)); + } + else if (GET_CODE (XEXP (x, 1)) == MULT) + { + return gen_rtx (PLUS, mode, plus_constant (XEXP (x, 0), c), + XEXP (x, 1)); + } +#endif + } + if (c != 0) + x = gen_rtx (PLUS, mode, x, gen_rtx (CONST_INT, VOIDmode, c)); + + if (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF) + return x; + else if (all_constant) + return gen_rtx (CONST, mode, x); + else + return x; +} + +/* If X is a sum, return a new sum like X but lacking any constant terms. + Add all the removed constant terms into *CONSTPTR. + X itself is not altered. The result != X if and only if + it is not isomorphic to X. */ + +rtx +eliminate_constant_term (x, constptr) + rtx x; + int *constptr; +{ + int c; + register rtx x0, x1; + + if (GET_CODE (x) != PLUS) + return x; + + /* First handle constants appearing at this level explicitly. */ + if (GET_CODE (XEXP (x, 0)) == CONST_INT) + { + *constptr += INTVAL (XEXP (x, 0)); + return eliminate_constant_term (XEXP (x, 1), constptr); + } + + if (GET_CODE (XEXP (x, 1)) == CONST_INT) + { + *constptr += INTVAL (XEXP (x, 1)); + return eliminate_constant_term (XEXP (x, 0), constptr); + } + + c = 0; + x0 = eliminate_constant_term (XEXP (x, 0), &c); + x1 = eliminate_constant_term (XEXP (x, 1), &c); + if (x1 != XEXP (x, 1) || x0 != XEXP (x, 0)) + { + *constptr += c; + return gen_rtx (PLUS, GET_MODE (x), x0, x1); + } + return x; +} + +/* Return an rtx for the size in bytes of the value of EXP. */ + +rtx +expr_size (exp) + tree exp; +{ + return expand_expr (size_in_bytes (TREE_TYPE (exp)), 0, SImode, 0); +} + +/* Not yet really written since C does not need it. */ + +rtx +lookup_static_chain (context) + rtx context; +{ + abort (); +} + +/* Return a copy of X in which all memory references + and all constants that involve symbol refs + have been replaced with new temporary registers. + Also emit code to load the memory locations and constants + into those registers. + + If X contains no such constants or memory references, + X itself (not a copy) is returned. + + X may contain no arithmetic except addition, subtraction and multiplication. + Values returned by expand_expr with 1 for sum_ok fit this constraint. */ + +static rtx +break_out_memory_refs (x) + register rtx x; +{ + if (GET_CODE (x) == MEM || GET_CODE (x) == CONST + || GET_CODE (x) == SYMBOL_REF) + { + register rtx temp = force_reg (Pmode, x); + mark_reg_pointer (temp); + x = temp; + } + else if (GET_CODE (x) == PLUS || GET_CODE (x) == MINUS + || GET_CODE (x) == MULT) + { + register rtx op0 = break_out_memory_refs (XEXP (x, 0)); + 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); + } + return x; +} + +/* Given a memory address or facsimile X, construct a new address, + currently equivalent, that is stable: future stores won't change it. + + X must be composed of constants, register and memory references + combined with addition, subtraction and multiplication: + in other words, just what you can get from expand_expr if sum_ok is 1. + + Works by making copies of all regs and memory locations used + by X and combining them the same way X does. + You could also stabilize the reference to this address + by copying the address to a register with copy_to_reg; + but then you wouldn't get indexed addressing in the reference. */ + +rtx +copy_all_regs (x) + register rtx x; +{ + if (GET_CODE (x) == REG) + { + if (REGNO (x) != FRAME_POINTER_REGNUM) + x = copy_to_reg (x); + } + else if (GET_CODE (x) == MEM) + x = copy_to_reg (x); + else if (GET_CODE (x) == PLUS || GET_CODE (x) == MINUS + || GET_CODE (x) == MULT) + { + 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); + } + return x; +} + +/* Return something equivalent to X but valid as a memory address + for something of mode MODE. When X is not itself valid, this + works by copying X or subexpressions of it into registers. */ + +rtx +memory_address (mode, x) + enum machine_mode mode; + register rtx x; +{ + register rtx oldx; + + /* By passing constant addresses thru registers + we get a chance to cse them. */ + if (! cse_not_expected && CONSTANT_P (x)) + return force_reg (Pmode, x); + + /* Accept a QUEUED that refers to a REG + even though that isn't a valid address. + On attempting to put this in an insn we will call protect_from_queue + which will turn it into a REG, which is valid. */ + if (GET_CODE (x) == QUEUED + && GET_CODE (QUEUED_VAR (x)) == REG) + return x; + + /* We get better cse by rejecting indirect addressing at this stage. + Let the combiner create indirect addresses where appropriate. + For now, generate the code so that the subexpressions useful to share + are visible. But not if cse won't be done! */ + oldx = x; + if (! cse_not_expected && GET_CODE (x) != REG) + x = break_out_memory_refs (x); + + /* At this point, any valid address is accepted. */ + GO_IF_LEGITIMATE_ADDRESS (mode, x, win); + + /* If it was valid before but breaking out memory refs invalidated it, + use it the old way. */ + if (memory_address_p (mode, oldx)) + goto win2; + + /* Perform machine-dependent transformations on X + in certain cases. This is not necessary since the code + below can handle all possible cases, but machine-dependent + transformations can make better code. */ + LEGITIMIZE_ADDRESS (x, oldx, mode, win); + + /* PLUS and MULT can appear in special ways + as the result of attempts to make an address usable for indexing. + Usually they are dealt with by calling force_operand, below. + But a sum containing constant terms is special + if removing them makes the sum a valid address: + then we generate that address in a register + and index off of it. We do this because it often makes + shorter code, and because the addresses thus generated + in registers often become common subexpressions. */ + if (GET_CODE (x) == PLUS) + { + int constant_term = 0; + rtx y = eliminate_constant_term (x, &constant_term); + if (constant_term == 0 + || ! memory_address_p (mode, y)) + return force_operand (x, 0); + + y = plus_constant (copy_to_reg (y), constant_term); + if (! memory_address_p (mode, y)) + return force_operand (x, 0); + return y; + } + if (GET_CODE (x) == MULT || GET_CODE (x) == MINUS) + return force_operand (x, 0); + + /* If we have a register that's an invalid address, + it must be a hard reg of the wrong class. Copy it to a pseudo. */ + if (GET_CODE (x) == REG) + return copy_to_reg (x); + + /* Last resort: copy the value to a register, since + the register is a valid address. */ + return force_reg (Pmode, x); + + win2: + x = oldx; + win: + if (flag_force_addr && optimize && GET_CODE (x) != REG + /* Don't copy an addr via a reg if it is one of our stack slots. + If we did, it would cause invalid REG_EQUIV notes for parms. */ + && ! (GET_CODE (x) == PLUS + && (XEXP (x, 0) == frame_pointer_rtx + || XEXP (x, 0) == arg_pointer_rtx))) + { + if (general_operand (x, Pmode)) + return force_reg (Pmode, x); + else + return force_operand (x, 0); + } + return x; +} + +/* Like `memory_address' but pretend `flag_force_addr' is 0. */ + +rtx +memory_address_noforce (mode, x) + enum machine_mode mode; + rtx x; +{ + int ambient_force_addr = flag_force_addr; + rtx val; + + flag_force_addr = 0; + val = memory_address (mode, x); + flag_force_addr = ambient_force_addr; + return val; +} + +/* Return a modified copy of X with its memory address copied + into a temporary register to protect it from side effects. + If X is not a MEM, it is returned unchanged (and not copied). + Perhaps even if it is a MEM, if there is no need to change it. */ + +rtx +stabilize (x) + rtx x; +{ + register rtx addr; + if (GET_CODE (x) != MEM) + return x; + addr = XEXP (x, 0); + if (rtx_unstable_p (addr)) + { + rtx temp = copy_all_regs (addr); + rtx mem; + if (GET_CODE (temp) != REG) + temp = copy_to_reg (temp); + mem = gen_rtx (MEM, GET_MODE (x), temp); + /* Mark returned memref with in_struct + if it's in an array or structure. */ + if (GET_CODE (addr) == PLUS || MEM_IN_STRUCT_P (x)) + MEM_IN_STRUCT_P (mem) = 1; + return mem; + } + return x; +} + +/* Copy the value or contents of X to a new temp reg and return that reg. */ + +rtx +copy_to_reg (x) + rtx x; +{ + register rtx temp = gen_reg_rtx (GET_MODE (x)); + + /* If not an operand, must be an address with PLUS and MULT so + do the computation. */ + if (! general_operand (x, VOIDmode)) + x = force_operand (x, temp); + + if (x != temp) + emit_move_insn (temp, x); + + return temp; +} + +/* Like copy_to_reg but always give the new register mode Pmode + in case X is a constant. */ + +rtx +copy_addr_to_reg (x) + rtx x; +{ + return copy_to_mode_reg (Pmode, x); +} + +/* Like copy_to_reg but always give the new register mode MODE + in case X is a constant. */ + +rtx +copy_to_mode_reg (mode, x) + enum machine_mode mode; + rtx x; +{ + register rtx temp = gen_reg_rtx (mode); + + /* If not an operand, must be an address with PLUS and MULT so + do the computation. */ + if (! general_operand (x, VOIDmode)) + x = force_operand (x, temp); + + if (GET_MODE (x) != mode && GET_MODE (x) != VOIDmode) + abort (); + if (x != temp) + emit_move_insn (temp, x); + return temp; +} + +/* Load X into a register if it is not already one. + Use mode MODE for the register. + X should be valid for mode MODE, but it may be a constant which + is valid for all integer modes; that's why caller must specify MODE. + + The caller must not alter the value in the register we return, + since we mark it as a "constant" register. */ + +rtx +force_reg (mode, x) + enum machine_mode mode; + rtx x; +{ + register rtx temp, insn; + + if (GET_CODE (x) == REG) + return x; + temp = gen_reg_rtx (mode); + insn = emit_move_insn (temp, x); + /* Let optimizers know that TEMP's value never changes + and that X can be substituted for it. */ + if (CONSTANT_P (x)) + REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_EQUIV, x, REG_NOTES (insn)); + return temp; +} + +/* If X is a memory ref, copy its contents to a new temp reg and return + that reg. Otherwise, return X. */ + +rtx +force_not_mem (x) + rtx x; +{ + register rtx temp; + if (GET_CODE (x) != MEM || GET_MODE (x) == BLKmode) + return x; + temp = gen_reg_rtx (GET_MODE (x)); + emit_move_insn (temp, x); + return temp; +} + +/* Copy X to TARGET (if it's nonzero and a reg) + or to a new temp reg and return that reg. */ + +rtx +copy_to_suggested_reg (x, target) + rtx x, target; +{ + register rtx temp; + if (target && GET_CODE (target) == REG) + temp = target; + else + temp = gen_reg_rtx (GET_MODE (x)); + emit_move_insn (temp, x); + return temp; +} + +/* Adjust the stack pointer by ADJUST (an rtx for a number of bytes). + This pops when ADJUST is positive. ADJUST need not be constant. */ + +void +adjust_stack (adjust) + rtx adjust; +{ + adjust = protect_from_queue (adjust, 0); + +#ifdef STACK_GROWS_DOWNWARD + emit_insn (gen_add2_insn (stack_pointer_rtx, adjust)); +#else + emit_insn (gen_sub2_insn (stack_pointer_rtx, adjust)); +#endif +} + +/* Adjust the stack pointer by minus ADJUST (an rtx for a number of bytes). + This pushes when ADJUST is positive. ADJUST need not be constant. */ + +void +anti_adjust_stack (adjust) + rtx adjust; +{ + adjust = protect_from_queue (adjust, 0); + +#ifdef STACK_GROWS_DOWNWARD + emit_insn (gen_sub2_insn (stack_pointer_rtx, adjust)); +#else + emit_insn (gen_add2_insn (stack_pointer_rtx, adjust)); +#endif +} + +/* Round the size of a block to be pushed up to the boundary required + by this machine. SIZE is the desired size, which need not be constant. */ + +rtx +round_push (size) + rtx size; +{ +#ifdef STACK_BOUNDARY + int align = STACK_BOUNDARY / BITS_PER_UNIT; + if (align == 1) + return size; + if (GET_CODE (size) == CONST_INT) + { + int new = (INTVAL (size) + align - 1) / align * align; + if (INTVAL (size) != new) + size = gen_rtx (CONST_INT, VOIDmode, new); + } + else + { + size = expand_divmod (0, CEIL_DIV_EXPR, Pmode, size, + gen_rtx (CONST_INT, VOIDmode, align), + 0, 1); + size = expand_mult (Pmode, size, + gen_rtx (CONST_INT, VOIDmode, align), + 0, 1); + } +#endif /* STACK_BOUNDARY */ + return size; +} + +/* 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. + FUNC is a FUNCTION_DECL node if the precise function is known, + otherwise 0. */ + +rtx +hard_function_value (valtype, func) + tree valtype; + tree func; +{ + return FUNCTION_VALUE (valtype, func); +} + +/* Return an rtx representing the register or memory location + in which a scalar value of mode MODE was returned by a library call. */ + +rtx +hard_libcall_value (mode) + enum machine_mode mode; +{ + return LIBCALL_VALUE (mode); +} diff --git a/gcc-1.40/expmed.c b/gcc-1.40/expmed.c new file mode 100644 index 0000000..91566fc --- /dev/null +++ b/gcc-1.40/expmed.c @@ -0,0 +1,1888 @@ +/* Medium-level subroutines: convert bit-field store and extract + and shifts, multiplies and divides to rtl instructions. + Copyright (C) 1987, 1988, 1989 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 1, 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 "rtl.h" +#include "tree.h" +#include "flags.h" +#include "insn-flags.h" +#include "insn-codes.h" +#include "insn-config.h" +#include "expr.h" +#include "recog.h" + +static rtx extract_split_bit_field (); +static rtx extract_fixed_bit_field (); +static void store_split_bit_field (); +static void store_fixed_bit_field (); + +/* Return an rtx representing minus the value of X. + MODE is the intended mode of the result, + useful if X is a CONST_INT. */ + +rtx +negate_rtx (mode, x) + enum machine_mode mode; + rtx x; +{ + if (GET_CODE (x) == CONST_INT) + { + int val = - INTVAL (x); + if (GET_MODE_BITSIZE (mode) < HOST_BITS_PER_INT) + { + /* Sign extend the value from the bits that are significant. */ + if (val & (1 << (GET_MODE_BITSIZE (mode) - 1))) + val |= (-1) << GET_MODE_BITSIZE (mode); + else + val &= (1 << GET_MODE_BITSIZE (mode)) - 1; + } + return gen_rtx (CONST_INT, VOIDmode, val); + } + else + return expand_unop (GET_MODE (x), neg_optab, x, 0, 0); +} + +/* Generate code to store value from rtx VALUE + into a bit-field within structure STR_RTX + containing BITSIZE bits starting at bit BITNUM. + FIELDMODE is the machine-mode of the FIELD_DECL node for this field. + ALIGN is the alignment that STR_RTX is known to have, measured in bytes. + TOTAL_SIZE is the size of the structure in bytes, or -1 if unknown. */ + +rtx +store_bit_field (str_rtx, bitsize, bitnum, fieldmode, value, align, total_size) + rtx str_rtx; + register int bitsize; + int bitnum; + enum machine_mode fieldmode; + rtx value; + int align; + int total_size; +{ + int unit = (GET_CODE (str_rtx) == MEM) ? BITS_PER_UNIT : BITS_PER_WORD; + register int offset = bitnum / unit; + register int bitpos = bitnum % unit; + register rtx op0 = str_rtx; + rtx value1; + + /* At this point, BITPOS counts within UNIT for a memref. + For a register or a subreg, it actually counts within the width + of the mode of OP0. However, BITNUM never exceeds that width, + so the % operation above never really does anything. + + We will adjust BITPOS later to count properly within UNIT + in the case of a register. */ + + /* 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) + total_size -= (bitpos / BIGGEST_ALIGNMENT + * (BIGGEST_ALIGNMENT / BITS_PER_UNIT)); + + while (GET_CODE (op0) == SUBREG) + { +#ifdef BYTES_BIG_ENDIAN + /* Keep BITPOS counting within the size of op0. */ + bitpos += (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (op0))) + - GET_MODE_BITSIZE (GET_MODE (op0))); +#endif + offset += SUBREG_WORD (op0); + op0 = SUBREG_REG (op0); + } + + value = protect_from_queue (value, 0); + + if (flag_force_mem) + value = force_not_mem (value); + + if (GET_MODE_SIZE (fieldmode) >= UNITS_PER_WORD + && GET_MODE_BITSIZE (fieldmode) == bitsize + && bitpos % BITS_PER_WORD == 0 + && GET_CODE (op0) == REG) + { + /* Storing in a full-word or multi-word field in a register + can be done with just SUBREG. */ + if (GET_MODE (op0) != fieldmode) + op0 = gen_rtx (SUBREG, fieldmode, op0, offset); + emit_move_insn (op0, value); + return value; + } + +#ifdef BYTES_BIG_ENDIAN + /* If OP0 is a register, BITPOS must count within UNIT, which should be SI. + But as we have it, it counts within whatever size OP0 now has. + These are not the same, so convert if big-endian. */ + if (GET_CODE (op0) != MEM && unit > GET_MODE_BITSIZE (GET_MODE (op0))) + { + bitpos += unit - GET_MODE_BITSIZE (GET_MODE (op0)); + /* Change the mode now so we don't adjust BITPOS again. */ + if (GET_CODE (op0) == SUBREG) + PUT_MODE (op0, SImode); + else + op0 = gen_rtx (SUBREG, SImode, op0, 0); + } +#endif + + /* Storing an lsb-aligned field in a register + can be done with a movestrict instruction. */ + + if (GET_CODE (op0) != MEM +#ifdef BYTES_BIG_ENDIAN + && bitpos + bitsize == unit +#else + && bitpos == 0 +#endif + && (GET_MODE (op0) == fieldmode + || (movstrict_optab->handlers[(int) fieldmode].insn_code + != CODE_FOR_nothing))) + { + /* Get appropriate low part of the value being stored. */ + if (GET_CODE (value) == CONST_INT || GET_CODE (value) == REG) + value = gen_lowpart (fieldmode, value); + else if (!(GET_CODE (value) == SYMBOL_REF + || GET_CODE (value) == LABEL_REF + || GET_CODE (value) == CONST)) + value = convert_to_mode (fieldmode, value, 0); + + if (GET_MODE (op0) == fieldmode) + emit_move_insn (op0, value); + else + { + if (GET_CODE (op0) == SUBREG) + PUT_MODE (op0, fieldmode); + else + op0 = gen_rtx (SUBREG, fieldmode, op0, offset); + emit_insn (GEN_FCN (movstrict_optab->handlers[(int) fieldmode].insn_code) + (op0, value)); + } + + return value; + } + + /* Handle fields bigger than a word. */ + + if (bitsize > BITS_PER_WORD) + { + int low_size = BITS_PER_WORD; + int low_pos = bitpos + offset * unit; + int high_size = bitsize - low_size; + int high_pos; +#ifdef BYTES_BIG_ENDIAN + high_pos = low_pos; + low_pos += high_size; +#else + high_pos = low_pos + low_size; +#endif + + if (GET_MODE (value) != VOIDmode) + value = force_reg (GET_MODE (value), value); + store_bit_field (op0, low_size, low_pos, SImode, + gen_lowpart (SImode, value), align, total_size); + store_bit_field (op0, high_size, high_pos, SImode, + gen_highpart (SImode, value), align, total_size); + return value; + } + + /* From here on we can assume that the field to be stored in is an integer, + since it is shorter than a word. */ + + /* OFFSET is the number of words or bytes (UNIT says which) + from STR_RTX to the first word or byte containing part of the field. */ + + if (GET_CODE (op0) == REG || GET_CODE (op0) == SUBREG) + { + /* If not in memory, merge in the offset now. */ + if (offset != 0 + || GET_MODE_SIZE (GET_MODE (op0)) > GET_MODE_SIZE (SImode)) + { + if (GET_CODE (op0) == SUBREG) + SUBREG_WORD (op0) += offset; + else + op0 = gen_rtx (SUBREG, SImode, op0, offset); + } + offset = 0; + } + else + { + op0 = protect_from_queue (op0, 1); + } + + /* Now OFFSET is nonzero only if OP0 is memory + and is therefore always measured in bytes. */ + +#ifdef HAVE_insv + if (HAVE_insv + && !(bitsize == 1 && GET_CODE (value) == CONST_INT)) + { + int xbitpos = bitpos; + rtx xop0 = op0; + rtx last = get_last_insn (); + rtx pat; + extern int volatile_ok; + int save_volatile_ok = volatile_ok; + volatile_ok = 1; + + /* If this machine's insv can only insert into a register, + copy OP0 into a register and save it back later. */ + if (GET_CODE (op0) == MEM + && ! (*insn_operand_predicate[(int) CODE_FOR_insv][0]) (op0, VOIDmode)) + { + rtx tempreg; + enum machine_mode trymode, bestmode = VOIDmode, insn_mode; + /* Don't use a mode bigger than the one of the value to be stored. + That mode must be okay, since a bit field can be that big. */ + int maxsize + = GET_MODE_SIZE (insn_operand_mode[(int) CODE_FOR_insv][3]); + /* This used to use the mode desired for operand 0, + but that is normally QImode on most machines, + and QImode won't work for fields that cross byte + boundaries. */ + + /* Also don't use a mode bigger than the structure. */ + if (total_size >= 0 && maxsize > total_size) + maxsize = total_size; + + /* Find biggest machine mode we can safely use + to fetch from this structure. + But don't use a bigger mode than the insn wants. */ + for (trymode = QImode; + trymode && GET_MODE_SIZE (trymode) <= maxsize; + trymode = GET_MODE_WIDER_MODE (trymode)) + if (GET_MODE_SIZE (trymode) <= align + || align == BIGGEST_ALIGNMENT / BITS_PER_UNIT) + bestmode = trymode; + if (! bestmode) + abort (); + /* Adjust address to point to the containing unit of that mode. */ + unit = GET_MODE_BITSIZE (bestmode); + /* Compute offset as multiple of this unit, counting in bytes. */ + offset = (bitnum / unit) * GET_MODE_SIZE (bestmode); + bitpos = bitnum % unit; + op0 = change_address (op0, bestmode, + plus_constant (XEXP (op0, 0), offset)); + + /* Fetch that unit, store the bitfield in it, then store the unit. */ + tempreg = copy_to_reg (op0); + /* To actually store in TEMPREG, + look at it in the mode this insn calls for. + (Probably SImode.) */ + insn_mode = SImode; +#ifdef BYTES_BIG_ENDIAN + if (GET_MODE_BITSIZE (insn_mode) > unit) + bitpos += GET_MODE_BITSIZE (insn_mode) - unit; +#endif + store_bit_field (gen_rtx (SUBREG, insn_mode, tempreg, 0), + bitsize, bitpos, fieldmode, value, + align, total_size); + emit_move_insn (op0, tempreg); + return value; + } + volatile_ok = save_volatile_ok; + + /* Add OFFSET into OP0's address. */ + if (GET_CODE (xop0) == MEM) + xop0 = change_address (xop0, QImode, + plus_constant (XEXP (xop0, 0), offset)); + + /* If xop0 is a register, we need it in SImode + to make it acceptable to the format of insv. */ + if (GET_CODE (xop0) == SUBREG) + PUT_MODE (xop0, SImode); + if (GET_CODE (xop0) == REG && GET_MODE (xop0) != SImode) + { +#ifdef BYTES_BIG_ENDIAN + xbitpos += (GET_MODE_BITSIZE (SImode) + - GET_MODE_BITSIZE (GET_MODE (xop0))); +#endif + xop0 = gen_rtx (SUBREG, SImode, xop0, 0); + } + + /* Convert VALUE to SImode (which insv insn wants) in VALUE1. */ + value1 = value; + if (GET_MODE (value) != SImode) + { + if (GET_MODE_BITSIZE (GET_MODE (value)) >= bitsize) + { + /* Optimization: Don't bother really extending VALUE + if it has all the bits we will actually use. */ + + /* Avoid making subreg of a subreg, or of a mem. */ + if (GET_CODE (value1) != REG) + value1 = copy_to_reg (value1); + value1 = gen_rtx (SUBREG, SImode, value1, 0); + } + else if (!CONSTANT_P (value)) + /* Parse phase is supposed to make VALUE's data type + match that of the component reference, which is a type + at least as wide as the field; so VALUE should have + a mode that corresponds to that type. */ + abort (); + } + + /* If this machine's insv insists on a register, + get VALUE1 into a register. */ + if (! (*insn_operand_predicate[(int) CODE_FOR_insv][3]) (value1, SImode)) + value1 = force_reg (SImode, value1); + + /* On big-endian machines, we count bits from the most significant. + If the bit field insn does not, we must invert. */ + +#if defined (BITS_BIG_ENDIAN) != defined (BYTES_BIG_ENDIAN) + xbitpos = unit - 1 - xbitpos; +#endif + + pat = gen_insv (xop0, + gen_rtx (CONST_INT, VOIDmode, bitsize), + gen_rtx (CONST_INT, VOIDmode, xbitpos), + value1); + if (pat) + emit_insn (pat); + else + { + delete_insns_since (last); + store_fixed_bit_field (op0, offset, bitsize, bitpos, value, align); + } + } + else +#endif + /* Insv is not available; store using shifts and boolean ops. */ + store_fixed_bit_field (op0, offset, bitsize, bitpos, value, align); + return value; +} + +/* Use shifts and boolean operations to store VALUE + into a bit field of width BITSIZE + in a memory location specified by OP0 except offset by OFFSET bytes. + (OFFSET must be 0 if OP0 is a register.) + The field starts at position BITPOS within the byte. + (If OP0 is a register, it may be SImode or a narrower mode, + but BITPOS still counts within a full word, + which is significant on bigendian machines.) + STRUCT_ALIGN is the alignment the structure is known to have (in bytes). + + Note that protect_from_queue has already been done on OP0 and VALUE. */ + +static void +store_fixed_bit_field (op0, offset, bitsize, bitpos, value, struct_align) + register rtx op0; + register int offset, bitsize, bitpos; + register rtx value; + int struct_align; +{ + register enum machine_mode mode; + int total_bits = BITS_PER_WORD; + rtx subtarget; + int all_zero = 0; + int all_one = 0; + + /* Add OFFSET to OP0's address (if it is in memory) + and if a single byte contains the whole bit field + change OP0 to a byte. */ + + /* 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. + Or likewise a structure with a known alignment of just a byte + and a field split across two bytes. + Such cases are not supposed to be able to occur. */ + + if (GET_CODE (op0) == REG || GET_CODE (op0) == SUBREG) + { + if (offset != 0) + abort (); + /* Special treatment for a bit field split across two registers. */ + if (bitsize + bitpos > BITS_PER_WORD) + { + store_split_bit_field (op0, bitsize, bitpos, value, BITS_PER_WORD); + return; + } + } + else if (bitsize + bitpos <= BITS_PER_UNIT + && (! SLOW_BYTE_ACCESS + || (struct_align == 1 + && BIGGEST_ALIGNMENT > 1))) + { + /* It fits in one byte, and either bytes are fast + or the alignment won't let us use anything bigger. */ + total_bits = BITS_PER_UNIT; + op0 = change_address (op0, QImode, + plus_constant (XEXP (op0, 0), offset)); + } + else if ((bitsize + bitpos + (offset % GET_MODE_SIZE (HImode)) * BITS_PER_UNIT + <= GET_MODE_BITSIZE (HImode)) + /* If halfwords are fast, use them whenever valid. */ + && (! SLOW_BYTE_ACCESS + /* Use halfwords if larger is invalid due to alignment. */ + || (struct_align == GET_MODE_SIZE (HImode) + && BIGGEST_ALIGNMENT > GET_MODE_SIZE (HImode)))) + { + /* It fits in an aligned halfword within the structure, + and either halfwords are fast + or the alignment won't let us use anything bigger. */ + total_bits = GET_MODE_BITSIZE (HImode); + + /* Get ref to halfword containing the field. */ + bitpos += (offset % (total_bits / BITS_PER_UNIT)) * BITS_PER_UNIT; + offset -= (offset % (total_bits / BITS_PER_UNIT)); + op0 = change_address (op0, HImode, + plus_constant (XEXP (op0, 0), offset)); + } + else + { + /* Get ref to an aligned word containing the field. */ + /* Adjust BITPOS to be position within a word, + and OFFSET to be the offset of that word. + Then alter OP0 to refer to that word. */ + bitpos += (offset % (BITS_PER_WORD / BITS_PER_UNIT)) * BITS_PER_UNIT; + offset -= (offset % (BITS_PER_WORD / BITS_PER_UNIT)); + op0 = change_address (op0, SImode, + plus_constant (XEXP (op0, 0), offset)); + + /* Special treatment for a bit field split across two aligned words. */ + if (bitsize + bitpos > BITS_PER_WORD) + { + store_split_bit_field (op0, bitsize, bitpos, value, struct_align); + return; + } + } + + mode = GET_MODE (op0); + + /* Now MODE is either QImode, HImode or SImode for a MEM as OP0, + or is SImode for a REG as OP0. TOTAL_BITS corresponds. + The bit field is contained entirely within OP0. + BITPOS is the starting bit number within OP0. + (OP0's mode may actually be narrower than MODE.) */ + +#ifdef BYTES_BIG_ENDIAN + /* BITPOS is the distance between our msb + and that of the containing datum. + Convert it to the distance from the lsb. */ + + bitpos = total_bits - bitsize - bitpos; +#endif + /* Now BITPOS is always the distance between our lsb + and that of OP0. */ + + /* Shift VALUE left by BITPOS bits. If VALUE is not constant, + we must first convert its mode to MODE. */ + + if (GET_CODE (value) == CONST_INT) + { + register int v = INTVAL (value); + + if (bitsize < HOST_BITS_PER_INT) + v &= (1 << bitsize) - 1; + + if (v == 0) + all_zero = 1; + else if (bitsize < HOST_BITS_PER_INT && v == (1 << bitsize) - 1) + all_one = 1; + + value = gen_rtx (CONST_INT, VOIDmode, v << bitpos); + } + else + { + int must_and = (GET_MODE_BITSIZE (GET_MODE (value)) != bitsize); + + if (GET_MODE (value) != mode) + { + if ((GET_CODE (value) == REG || GET_CODE (value) == SUBREG) + && GET_MODE_SIZE (mode) < GET_MODE_SIZE (GET_MODE (value))) + value = gen_lowpart (mode, value); + else + value = convert_to_mode (mode, value, 1); + } + + if (must_and && bitsize < HOST_BITS_PER_INT) + value = expand_bit_and (mode, value, + gen_rtx (CONST_INT, VOIDmode, + (1 << bitsize) - 1), + 0); + if (bitpos > 0) + value = expand_shift (LSHIFT_EXPR, mode, value, + build_int_2 (bitpos, 0), 0, 1); + } + + /* Now clear the chosen bits in OP0, + except that if VALUE is -1 we need not bother. */ + + subtarget = op0; + + if (! all_one) + subtarget = expand_bit_and (mode, op0, + gen_rtx (CONST_INT, VOIDmode, + (~ (((unsigned) ~0 + >> (HOST_BITS_PER_INT - bitsize)) + << bitpos)) + & ((GET_MODE_BITSIZE (mode) + == HOST_BITS_PER_INT) + ? -1 + : ((1 << GET_MODE_BITSIZE (mode)) - 1))), + subtarget); + + /* Now logical-or VALUE into OP0, unless it is zero. */ + + if (! all_zero) + subtarget = expand_binop (mode, ior_optab, subtarget, value, + op0, 1, OPTAB_LIB_WIDEN); + if (op0 != subtarget) + emit_move_insn (op0, subtarget); +} + +/* Store a bit field that is split across two words. + + OP0 is the REG, SUBREG or MEM rtx for the first of the two words. + BITSIZE is the field width; BITPOS the position of its first bit + (within the word). + VALUE is the value to store. */ + +static void +store_split_bit_field (op0, bitsize, bitpos, value, align) + rtx op0; + int bitsize, bitpos; + rtx value; + int align; +{ + /* BITSIZE_1 is size of the part in the first word. */ + int bitsize_1 = BITS_PER_WORD - bitpos; + /* BITSIZE_2 is size of the rest (in the following word). */ + int bitsize_2 = bitsize - bitsize_1; + rtx part1, part2; + + /* Alignment of VALUE, after conversion. */ + int valalign = GET_MODE_SIZE (SImode); + + if (GET_MODE (value) != VOIDmode) + value = convert_to_mode (SImode, value, 1); + if (CONSTANT_P (value) && GET_CODE (value) != CONST_INT) + value = copy_to_reg (value); + + /* Split the value into two parts: + PART1 gets that which goes in the first word; PART2 the other. */ +#ifdef BYTES_BIG_ENDIAN + /* PART1 gets the more significant part. */ + if (GET_CODE (value) == CONST_INT) + { + part1 = gen_rtx (CONST_INT, VOIDmode, + (unsigned) (INTVAL (value)) >> bitsize_2); + part2 = gen_rtx (CONST_INT, VOIDmode, + (unsigned) (INTVAL (value)) & ((1 << bitsize_2) - 1)); + } + else + { + part1 = extract_fixed_bit_field (SImode, value, 0, bitsize_1, + BITS_PER_WORD - bitsize, 0, 1, valalign); + part2 = extract_fixed_bit_field (SImode, value, 0, bitsize_2, + BITS_PER_WORD - bitsize_2, 0, 1, valalign); + } +#else + /* PART1 gets the less significant part. */ + if (GET_CODE (value) == CONST_INT) + { + part1 = gen_rtx (CONST_INT, VOIDmode, + (unsigned) (INTVAL (value)) & ((1 << bitsize_1) - 1)); + part2 = gen_rtx (CONST_INT, VOIDmode, + (unsigned) (INTVAL (value)) >> bitsize_1); + } + else + { + part1 = extract_fixed_bit_field (SImode, value, 0, bitsize_1, 0, + 0, 1, valalign); + part2 = extract_fixed_bit_field (SImode, value, 0, bitsize_2, + bitsize_1, 0, 1, valalign); + } +#endif + + /* Store PART1 into the first word. */ + store_fixed_bit_field (op0, 0, bitsize_1, bitpos, part1, align); + + /* Offset op0 to get to the following word. */ + if (GET_CODE (op0) == MEM) + op0 = change_address (op0, SImode, + plus_constant (XEXP (op0, 0), UNITS_PER_WORD)); + else if (GET_CODE (op0) == REG) + op0 = gen_rtx (SUBREG, SImode, op0, 1); + else if (GET_CODE (op0) == SUBREG) + op0 = gen_rtx (SUBREG, SImode, SUBREG_REG (op0), SUBREG_WORD (op0) + 1); + + /* Store PART2 into the second word. */ + store_fixed_bit_field (op0, 0, bitsize_2, 0, part2, align); +} + +/* Generate code to extract a byte-field from STR_RTX + containing BITSIZE bits, starting at BITNUM, + and put it in TARGET if possible (if TARGET is nonzero). + Regardless of TARGET, we return the rtx for where the value is placed. + It may be a QUEUED. + + STR_RTX is the structure containing the byte (a REG or MEM). + UNSIGNEDP is nonzero if this is an unsigned bit field. + MODE is the natural mode of the field value once extracted. + TMODE is the mode the caller would like the value to have; + but the value may be returned with type MODE instead. + + ALIGN is the alignment that STR_RTX is known to have, measured in bytes. + TOTAL_SIZE is the total size in bytes of the structure, if known. + Otherwise it is -1. + + If a TARGET is specified and we can store in it at no extra cost, + we do so, and return TARGET. + Otherwise, we return a REG of mode TMODE or MODE, with TMODE preferred + if they are equally easy. */ + +rtx +extract_bit_field (str_rtx, bitsize, bitnum, unsignedp, + target, mode, tmode, align, total_size) + rtx str_rtx; + register int bitsize; + int bitnum; + int unsignedp; + rtx target; + enum machine_mode mode, tmode; + int align; + int total_size; +{ + int unit = (GET_CODE (str_rtx) == MEM) ? BITS_PER_UNIT : BITS_PER_WORD; + register int offset = bitnum / unit; + register int bitpos = bitnum % unit; + register rtx op0 = str_rtx; + rtx spec_target = target; + rtx bitsize_rtx, bitpos_rtx; + rtx spec_target_subreg = 0; + + /* 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) + total_size -= (bitpos / BIGGEST_ALIGNMENT + * (BIGGEST_ALIGNMENT / BITS_PER_UNIT)); + + if (tmode == VOIDmode) + tmode = mode; + + while (GET_CODE (op0) == SUBREG) + { +#ifdef BYTES_BIG_ENDIAN + /* Keep BITPOS counting within the size of op0. */ + bitpos += (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (op0))) + - GET_MODE_BITSIZE (GET_MODE (op0))); +#endif + offset += SUBREG_WORD (op0); + op0 = SUBREG_REG (op0); + } + +#ifdef BYTES_BIG_ENDIAN + /* 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 (GET_CODE (op0) != MEM && unit > GET_MODE_BITSIZE (GET_MODE (op0))) + { + bitpos += unit - GET_MODE_BITSIZE (GET_MODE (op0)); + /* Change the mode now so we don't adjust BITPOS again. */ + if (GET_CODE (op0) == SUBREG) + PUT_MODE (op0, SImode); + else + op0 = gen_rtx (SUBREG, SImode, op0, 0); + } +#endif + + /* Extracting a full-word or multi-word value + from a structure in a register. + This can be done with just SUBREG. + So too extracting a subword value in + the least significant part of the register. */ + + if (GET_CODE (op0) == REG + && ((bitsize >= BITS_PER_WORD && bitsize == GET_MODE_BITSIZE (mode) + && bitpos % BITS_PER_WORD == 0) + || ((bitsize == GET_MODE_BITSIZE (mode) + || bitsize == GET_MODE_BITSIZE (QImode) + || bitsize == GET_MODE_BITSIZE (HImode)) +#ifdef BYTES_BIG_ENDIAN + && bitpos + bitsize == BITS_PER_WORD +#else + && bitpos == 0 +#endif + ))) + { + enum machine_mode mode1 = mode; + + if (bitsize == GET_MODE_BITSIZE (QImode)) + mode1 = QImode; + if (bitsize == GET_MODE_BITSIZE (HImode)) + mode1 = HImode; + + if (mode1 != GET_MODE (op0)) + { + if (GET_CODE (op0) == SUBREG) + PUT_MODE (op0, mode1); + else + op0 = gen_rtx (SUBREG, mode1, op0, offset); + } + + if (mode1 != mode) + return convert_to_mode (tmode, op0, unsignedp); + return op0; + } + + /* Handle fields bigger than a word. */ + + if (bitsize > BITS_PER_WORD) + { + int low_size = BITS_PER_WORD; + int low_pos = bitpos + offset * unit; + rtx target_low_part, low_part; + int high_size = bitsize - low_size; + int high_pos; + rtx target_high_part, high_part; +#ifdef BYTES_BIG_ENDIAN + high_pos = low_pos; + low_pos += high_size; +#else + high_pos = low_pos + low_size; +#endif + + if (target == 0 || GET_CODE (target) != REG) + target = gen_reg_rtx (mode); + + /* Extract the low part of the bitfield, and make sure + to store it in the low part of TARGET. */ + target_low_part = gen_lowpart (SImode, target); + low_part = extract_bit_field (op0, low_size, low_pos, 1, + target_low_part, SImode, SImode, + align, total_size); + if (low_part != target_low_part) + emit_move_insn (target_low_part, low_part); + + /* Likewise for the high part. */ + target_high_part = gen_highpart (SImode, target); + high_part = extract_bit_field (op0, high_size, high_pos, unsignedp, + target_high_part, SImode, SImode, + align, total_size); + if (high_part != target_high_part) + emit_move_insn (target_high_part, high_part); + + return target; + } + + /* From here on we know the desired field is smaller than a word + so we can assume it is an integer. So we can safely extract it as one + size of integer, if necessary, and then truncate or extend + to the size that is wanted. */ + + /* OFFSET is the number of words or bytes (UNIT says which) + from STR_RTX to the first word or byte containing part of the field. */ + + if (GET_CODE (op0) == REG || GET_CODE (op0) == SUBREG) + { + /* If not in memory, merge in the offset now. */ + if (offset != 0 + || GET_MODE_SIZE (GET_MODE (op0)) > GET_MODE_SIZE (SImode)) + { + if (GET_CODE (op0) == SUBREG) + SUBREG_WORD (op0) += offset; + else + op0 = gen_rtx (SUBREG, SImode, op0, offset); + } + offset = 0; + } + else + { + op0 = protect_from_queue (str_rtx, 1); + } + + /* Now OFFSET is nonzero only for memory operands. */ + + if (unsignedp) + { +#ifdef HAVE_extzv + if (HAVE_extzv) + { + int xbitpos = bitpos, xoffset = offset; + rtx last = get_last_insn(); + rtx xop0 = op0; + rtx xtarget = target; + rtx xspec_target = spec_target; + rtx xspec_target_subreg = spec_target_subreg; + rtx pat; + + if (GET_CODE (xop0) == MEM) + { + extern int volatile_ok; + int save_volatile_ok = volatile_ok; + volatile_ok = 1; + + /* Is the memory operand acceptable? */ + 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 = VOIDmode, trymode; + /* Don't use a mode bigger than the one of the value + to be fetched. That mode must be okay, + since a bit field can be that big. */ + int maxsize + = GET_MODE_SIZE (insn_operand_mode[(int) CODE_FOR_extzv][0]); + /* This used to use the mode desired for operand 1, + but that is normally QImode on most machines, + and QImode won't work for fields that cross byte + boundaries. */ + + /* Also don't use a mode bigger than the structure. */ + if (total_size >= 0 && maxsize > total_size) + maxsize = total_size; + + /* Find biggest machine mode we can safely use + to fetch from this structure. + But don't use a bigger mode than the insn wants. */ + for (trymode = QImode; + trymode && GET_MODE_SIZE (trymode) <= maxsize; + trymode = GET_MODE_WIDER_MODE (trymode)) + if (GET_MODE_SIZE (trymode) <= align + || align == BIGGEST_ALIGNMENT / BITS_PER_UNIT) + bestmode = trymode; + if (! bestmode) + abort (); + unit = GET_MODE_BITSIZE (bestmode); + + /* Compute offset as multiple of this unit, + counting in bytes. */ + xoffset = (bitnum / unit) * GET_MODE_SIZE (bestmode); + xbitpos = bitnum % unit; + xop0 = change_address (xop0, bestmode, + plus_constant (XEXP (xop0, 0), + xoffset)); + /* Fetch it to a register in that size. */ + xop0 = force_reg (bestmode, xop0); + + /* Now ref the register in the mode extzv wants. */ + /* We used to use the mode from operand 1 in the md, + but that is often QImode because that's needed for MEM. + Here we need SImode instead. */ + if (bestmode != SImode) + xop0 = gen_rtx (SUBREG, SImode, xop0, 0); +#ifdef BYTES_BIG_ENDIAN + if (GET_MODE_BITSIZE (GET_MODE (xop0)) > unit) + xbitpos += GET_MODE_BITSIZE (GET_MODE (xop0)) - unit; +#endif + } + else + /* Get ref to first byte containing part of the field. */ + xop0 = change_address (xop0, QImode, + plus_constant (XEXP (xop0, 0), xoffset)); + + volatile_ok = save_volatile_ok; + } + + /* If op0 is a register, we need it in SImode + to make it acceptable to the format of extzv. */ + if (GET_CODE (xop0) == SUBREG && GET_MODE (xop0) != SImode) + abort (); + if (GET_CODE (xop0) == REG && GET_MODE (xop0) != SImode) + { +#ifdef BYTES_BIG_ENDIAN + xbitpos += (GET_MODE_BITSIZE (SImode) + - GET_MODE_BITSIZE (GET_MODE (xop0))); +#endif + xop0 = gen_rtx (SUBREG, SImode, xop0, 0); + } + + if (xtarget == 0 + || (flag_force_mem && GET_CODE (xtarget) == MEM)) + xtarget = xspec_target = gen_reg_rtx (tmode); + + if (GET_MODE (xtarget) != SImode) + { + if (GET_CODE (xtarget) == REG) + xspec_target_subreg = xtarget = gen_lowpart (SImode, xtarget); + else + xtarget = gen_reg_rtx (SImode); + } + + /* If this machine's extzv insists on a register target, + make sure we have one. */ + if (! (*insn_operand_predicate[(int) CODE_FOR_extzv][0]) (xtarget, SImode)) + xtarget = gen_reg_rtx (SImode); + + /* On big-endian machines, we count bits from the most significant. + If the bit field insn does not, we must invert. */ +#if defined (BITS_BIG_ENDIAN) != defined (BYTES_BIG_ENDIAN) + xbitpos = unit - 1 - xbitpos; +#endif + + bitsize_rtx = gen_rtx (CONST_INT, VOIDmode, bitsize); + bitpos_rtx = gen_rtx (CONST_INT, VOIDmode, xbitpos); + + pat = gen_extzv (protect_from_queue (xtarget, 1), + xop0, bitsize_rtx, bitpos_rtx); + if (pat) + { + emit_insn (pat); + target = xtarget; + spec_target = xspec_target; + spec_target_subreg = xspec_target_subreg; + } + else + { + delete_insns_since (last); + target = extract_fixed_bit_field (tmode, op0, offset, bitsize, + bitpos, target, 1, align); + } + } + else +#endif + target = extract_fixed_bit_field (tmode, op0, offset, bitsize, bitpos, + target, 1, align); + } + else + { +#ifdef HAVE_extv + if (HAVE_extv) + { + int xbitpos = bitpos, xoffset = offset; + rtx last = get_last_insn(); + rtx xop0 = op0, xtarget = target; + rtx xspec_target = spec_target; + rtx xspec_target_subreg = spec_target_subreg; + rtx pat; + + if (GET_CODE (xop0) == MEM) + { + /* Is the memory operand acceptable? */ + if (! ((*insn_operand_predicate[(int) CODE_FOR_extv][1]) + (xop0, GET_MODE (xop0)))) + { + /* No, load into a reg and extract from there. */ + enum machine_mode bestmode = VOIDmode, trymode; + /* Don't use a mode bigger than the one of the value + to be fetched. That mode must be okay, + since a bit field can be that big. */ + int maxsize + = GET_MODE_SIZE (insn_operand_mode[(int) CODE_FOR_extv][0]); + /* This used to use the mode desired for operand 1, + but that is normally QImode on most machines, + and QImode won't work for fields that cross byte + boundaries. */ + + /* Also don't use a mode bigger than the structure. */ + if (total_size >= 0 && maxsize > total_size) + maxsize = total_size; + + /* Find biggest machine mode we can safely use + to fetch from this structure. + But don't use a bigger mode than the insn wants. */ + for (trymode = QImode; + trymode && GET_MODE_SIZE (trymode) <= maxsize; + trymode = GET_MODE_WIDER_MODE (trymode)) + if (GET_MODE_SIZE (trymode) <= align + || align == BIGGEST_ALIGNMENT / BITS_PER_UNIT) + bestmode = trymode; + if (! bestmode) + abort (); + unit = GET_MODE_BITSIZE (bestmode); + + /* Compute offset as multiple of this unit, + counting in bytes. */ + xoffset = (bitnum / unit) * GET_MODE_SIZE (bestmode); + xbitpos = bitnum % unit; + xop0 = change_address (xop0, bestmode, + plus_constant (XEXP (xop0, 0), + xoffset)); + /* Fetch it to a register in that size. */ + xop0 = force_reg (bestmode, xop0); + + /* Now ref the register in the mode extv wants. */ + /* We used to use the mode from operand 1 in the md, + but that is often QImode because that's needed for MEM. + Here we need SImode instead. */ + if (bestmode != SImode) + xop0 = gen_rtx (SUBREG, SImode, xop0, 0); +#ifdef BYTES_BIG_ENDIAN + if (GET_MODE_BITSIZE (GET_MODE (xop0)) > unit) + xbitpos += GET_MODE_BITSIZE (GET_MODE (xop0)) - unit; +#endif + } + else + /* Get ref to first byte containing part of the field. */ + xop0 = change_address (xop0, QImode, + plus_constant (XEXP (xop0, 0), xoffset)); + } + + /* If op0 is a register, we need it in SImode + to make it acceptable to the format of extv. */ + if (GET_CODE (xop0) == SUBREG && GET_MODE (xop0) != SImode) + abort (); + if (GET_CODE (xop0) == REG && GET_MODE (xop0) != SImode) + { +#ifdef BYTES_BIG_ENDIAN + xbitpos += (GET_MODE_BITSIZE (SImode) + - GET_MODE_BITSIZE (GET_MODE (xop0))); +#endif + xop0 = gen_rtx (SUBREG, SImode, xop0, 0); + } + + if (xtarget == 0 + || (flag_force_mem && GET_CODE (xtarget) == MEM)) + xtarget = xspec_target = gen_reg_rtx (tmode); + + if (GET_MODE (xtarget) != SImode) + { + if (GET_CODE (xtarget) == REG) + xspec_target_subreg = xtarget = gen_lowpart (SImode, xtarget); + else + xtarget = gen_reg_rtx (SImode); + } + + /* If this machine's extv insists on a register target, + make sure we have one. */ + if (! (*insn_operand_predicate[(int) CODE_FOR_extv][0]) (xtarget, SImode)) + xtarget = gen_reg_rtx (SImode); + + /* On big-endian machines, we count bits from the most significant. + If the bit field insn does not, we must invert. */ +#if defined (BITS_BIG_ENDIAN) != defined (BYTES_BIG_ENDIAN) + xbitpos = unit - 1 - xbitpos; +#endif + + bitsize_rtx = gen_rtx (CONST_INT, VOIDmode, bitsize); + bitpos_rtx = gen_rtx (CONST_INT, VOIDmode, xbitpos); + + pat = gen_extv (protect_from_queue (xtarget, 1), + xop0, bitsize_rtx, bitpos_rtx); + if (pat) + { + emit_insn (pat); + target = xtarget; + spec_target = xspec_target; + spec_target_subreg = xspec_target_subreg; + } + else + { + delete_insns_since (last); + target = extract_fixed_bit_field (tmode, op0, offset, bitsize, + bitpos, target, 0, align); + } + } + else +#endif + target = extract_fixed_bit_field (tmode, op0, offset, bitsize, bitpos, + target, 0, align); + } + if (target == spec_target) + return target; + if (target == spec_target_subreg) + return spec_target; + if (GET_MODE (target) != tmode && GET_MODE (target) != mode) + return convert_to_mode (tmode, target, unsignedp); + return target; +} + +/* Extract a bit field using shifts and boolean operations + Returns an rtx to represent the value. + OP0 addresses a register (word) or memory (byte). + BITPOS says which bit within the word or byte the bit field starts in. + OFFSET says how many bytes farther the bit field starts; + it is 0 if OP0 is a register. + BITSIZE says how many bits long the bit field is. + (If OP0 is a register, it may be narrower than SImode, + but BITPOS still counts within a full word, + which is significant on bigendian machines.) + + UNSIGNEDP is nonzero for an unsigned bit field (don't sign-extend value). + If TARGET is nonzero, attempts to store the value there + and return TARGET, but this is not guaranteed. + If TARGET is not used, create a pseudo-reg of mode TMODE for the value. + + ALIGN is the alignment that STR_RTX is known to have, measured in bytes. */ + +static rtx +extract_fixed_bit_field (tmode, op0, offset, bitsize, bitpos, + target, unsignedp, align) + enum machine_mode tmode; + register rtx op0, target; + register int offset, bitsize, bitpos; + int unsignedp; + int align; +{ + int total_bits = BITS_PER_WORD; + enum machine_mode mode; + + if (GET_CODE (op0) == SUBREG || GET_CODE (op0) == REG) + { + /* Special treatment for a bit field split across two registers. */ + if (bitsize + bitpos > BITS_PER_WORD) + return extract_split_bit_field (op0, bitsize, bitpos, + unsignedp, align); + } + else if (bitsize + bitpos <= BITS_PER_UNIT + && (! SLOW_BYTE_ACCESS + || (align == 1 + && BIGGEST_ALIGNMENT > 1))) + { + /* It fits in one byte, and either bytes are fast + or the alignment won't let us use anything bigger. */ + total_bits = BITS_PER_UNIT; + op0 = change_address (op0, QImode, + plus_constant (XEXP (op0, 0), offset)); + } + else if ((bitsize + bitpos + (offset % GET_MODE_SIZE (HImode)) * BITS_PER_UNIT + <= GET_MODE_BITSIZE (HImode)) + /* If halfwords are fast, use them whenever valid. */ + && (! SLOW_BYTE_ACCESS + /* Use halfwords if larger is invalid due to alignment. */ + || (align == GET_MODE_SIZE (HImode) + && BIGGEST_ALIGNMENT > GET_MODE_SIZE (HImode)))) + { + /* It fits in an aligned halfword, and either halfwords are fast + or the alignment won't let us use anything bigger. */ + total_bits = GET_MODE_BITSIZE (HImode); + + /* Get ref to halfword containing the field. */ + bitpos += (offset % (total_bits / BITS_PER_UNIT)) * BITS_PER_UNIT; + offset -= (offset % (total_bits / BITS_PER_UNIT)); + op0 = change_address (op0, HImode, + plus_constant (XEXP (op0, 0), offset)); + } + else + { + /* Get ref to word containing the field. */ + /* Adjust BITPOS to be position within a word, + and OFFSET to be the offset of that word. */ + bitpos += (offset % (BITS_PER_WORD / BITS_PER_UNIT)) * BITS_PER_UNIT; + offset -= (offset % (BITS_PER_WORD / BITS_PER_UNIT)); + op0 = change_address (op0, SImode, + plus_constant (XEXP (op0, 0), offset)); + + /* Special treatment for a bit field split across two words. */ + if (bitsize + bitpos > BITS_PER_WORD) + return extract_split_bit_field (op0, bitsize, bitpos, + unsignedp, align); + } + + mode = GET_MODE (op0); + +#ifdef BYTES_BIG_ENDIAN + /* BITPOS is the distance between our msb and that of OP0. + Convert it to the distance from the lsb. */ + + bitpos = total_bits - bitsize - bitpos; +#endif + /* Now BITPOS is always the distance between the field's lsb and that of OP0. + We have reduced the big-endian case to the little-endian case. */ + + if (unsignedp) + { + if (bitpos) + { + /* If the field does not already start at the lsb, + shift it so it does. */ + tree amount = build_int_2 (bitpos, 0); + /* Maybe propagate the target for the shift. */ + /* But not if we will return it--could confuse integrate.c. */ + rtx subtarget = (target != 0 && GET_CODE (target) == REG + && !REG_FUNCTION_VALUE_P (target) + ? target : 0); + if (tmode != mode) subtarget = 0; + op0 = expand_shift (RSHIFT_EXPR, mode, op0, amount, subtarget, 1); + } + /* Convert the value to the desired mode. */ + if (mode != tmode) + op0 = convert_to_mode (tmode, op0, 1); + + /* Unless the msb of the field used to be the msb when we shifted, + mask out the upper bits. */ + + if ((GET_MODE_BITSIZE (mode) != bitpos + bitsize +#if 0 +#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. */ + || tmode != mode +#endif +#endif + ) + && bitsize < HOST_BITS_PER_INT) + return expand_bit_and (GET_MODE (op0), op0, + gen_rtx (CONST_INT, VOIDmode, (1 << bitsize) - 1), + target); + return op0; + } + + /* To extract a signed bit-field, first shift its msb to the msb of the word, + then arithmetic-shift its lsb to the lsb of the word. */ + op0 = force_reg (mode, op0); + if (mode != tmode) + target = 0; + if (GET_MODE_BITSIZE (QImode) < GET_MODE_BITSIZE (mode) + && GET_MODE_BITSIZE (QImode) >= bitsize + bitpos) + mode = QImode, op0 = convert_to_mode (QImode, op0, 0); + if (GET_MODE_BITSIZE (HImode) < GET_MODE_BITSIZE (mode) + && GET_MODE_BITSIZE (HImode) >= bitsize + bitpos) + mode = HImode, op0 = convert_to_mode (HImode, op0, 0); + if (GET_MODE_BITSIZE (mode) != (bitsize + bitpos)) + { + tree amount = build_int_2 (GET_MODE_BITSIZE (mode) - (bitsize + bitpos), 0); + /* Maybe propagate the target for the shift. */ + /* But not if we will return the result--could confuse integrate.c. */ + rtx subtarget = (target != 0 && GET_CODE (target) == REG + && ! REG_FUNCTION_VALUE_P (target) + ? target : 0); + op0 = expand_shift (LSHIFT_EXPR, mode, op0, amount, subtarget, 1); + } + + return expand_shift (RSHIFT_EXPR, mode, op0, + build_int_2 (GET_MODE_BITSIZE (mode) - bitsize, 0), + target, 0); +} + +/* Extract a bit field that is split across two words + and return an RTX for the result. + + OP0 is the REG, SUBREG or MEM rtx for the first of the two words. + BITSIZE is the field width; BITPOS, position of its first bit, in the word. + UNSIGNEDP is 1 if should zero-extend the contents; else sign-extend. */ + +static rtx +extract_split_bit_field (op0, bitsize, bitpos, unsignedp, align) + rtx op0; + int bitsize, bitpos, unsignedp, align; +{ + /* BITSIZE_1 is size of the part in the first word. */ + int bitsize_1 = BITS_PER_WORD - bitpos; + /* BITSIZE_2 is size of the rest (in the following word). */ + int bitsize_2 = bitsize - bitsize_1; + rtx part1, part2, result; + + /* Get the part of the bit field from the first word. */ + part1 = extract_fixed_bit_field (SImode, op0, 0, bitsize_1, bitpos, + 0, 1, align); + + /* Offset op0 by 1 word to get to the following one. */ + if (GET_CODE (op0) == MEM) + op0 = change_address (op0, SImode, + plus_constant (XEXP (op0, 0), UNITS_PER_WORD)); + else if (GET_CODE (op0) == REG) + op0 = gen_rtx (SUBREG, SImode, op0, 1); + else + op0 = gen_rtx (SUBREG, SImode, SUBREG_REG (op0), SUBREG_WORD (op0) + 1); + + /* Get the part of the bit field from the second word. */ + part2 = extract_fixed_bit_field (SImode, op0, 0, bitsize_2, 0, 0, 1, align); + + /* Shift the more significant part up to fit above the other part. */ +#ifdef BYTES_BIG_ENDIAN + part1 = expand_shift (LSHIFT_EXPR, SImode, part1, + build_int_2 (bitsize_2, 0), 0, 1); +#else + part2 = expand_shift (LSHIFT_EXPR, SImode, part2, + build_int_2 (bitsize_1, 0), 0, 1); +#endif + + /* Combine the two parts with bitwise or. This works + because we extracted both parts as unsigned bit fields. */ + result = expand_binop (SImode, ior_optab, part1, part2, 0, 1, + OPTAB_LIB_WIDEN); + + /* Unsigned bit field: we are done. */ + if (unsignedp) + return result; + /* Signed bit field: sign-extend with two arithmetic shifts. */ + result = expand_shift (LSHIFT_EXPR, SImode, result, + build_int_2 (BITS_PER_WORD - bitsize, 0), 0, 0); + return expand_shift (RSHIFT_EXPR, SImode, result, + build_int_2 (BITS_PER_WORD - bitsize, 0), 0, 0); +} + +/* Add INC into TARGET. */ + +void +expand_inc (target, inc) + rtx target, inc; +{ + rtx value = expand_binop (GET_MODE (target), add_optab, + target, inc, + target, 0, OPTAB_LIB_WIDEN); + if (value != target) + emit_move_insn (target, value); +} + +/* Subtract INC from TARGET. */ + +void +expand_dec (target, dec) + rtx target, dec; +{ + rtx value = expand_binop (GET_MODE (target), sub_optab, + target, dec, + target, 0, OPTAB_LIB_WIDEN); + if (value != target) + emit_move_insn (target, value); +} + +/* Output a shift instruction for expression code CODE, + with SHIFTED being the rtx for the value to shift, + and AMOUNT the tree for the amount to shift by. + Store the result in the rtx TARGET, if that is convenient. + If UNSIGNEDP is nonzero, do a logical shift; otherwise, arithmetic. + Return the rtx for where the value is. */ + +/* Pastel, for shifts, converts shift count to SImode here + independent of the mode being shifted. + Should that be done in an earlier pass? + It turns out not to matter for C. */ + +rtx +expand_shift (code, mode, shifted, amount, target, unsignedp) + enum tree_code code; + register enum machine_mode mode; + rtx shifted; + tree amount; + register rtx target; + int unsignedp; +{ + register rtx op1, temp = 0; + register int left = (code == LSHIFT_EXPR || code == LROTATE_EXPR); + int try; + int rotate = code == LROTATE_EXPR || code == RROTATE_EXPR; + rtx last; + + /* Previously detected shift-counts computed by NEGATE_EXPR + and shifted in the other direction; but that does not work + on all machines. */ + + op1 = expand_expr (amount, 0, VOIDmode, 0); + + last = get_last_insn (); + + for (try = 0; temp == 0 && try < 3; try++) + { + enum optab_methods methods; + delete_insns_since (last); + + if (try == 0) + methods = OPTAB_DIRECT; + else if (try == 1) + methods = OPTAB_WIDEN; + else + methods = OPTAB_LIB_WIDEN; + + if (rotate) + { + /* Widening does not work for rotation. */ + if (methods != OPTAB_DIRECT) + methods = OPTAB_LIB; + + temp = expand_binop (mode, + left ? rotl_optab : rotr_optab, + shifted, op1, target, -1, methods); + } + else if (unsignedp) + { + temp = expand_binop (mode, + left ? lshl_optab : lshr_optab, + shifted, op1, target, unsignedp, methods); + if (temp == 0 && left) + temp = expand_binop (mode, ashl_optab, + shifted, op1, target, unsignedp, methods); + if (temp != 0) + return temp; + } + /* Do arithmetic shifts. + Also, if we are going to widen the operand, we can just as well + use an arithmetic right-shift instead of a logical one. */ + if (! rotate && (! unsignedp || (! left && methods == OPTAB_WIDEN))) + { + enum optab_methods methods1 = methods; + + /* If trying to widen a log shift to an arithmetic shift, + don't accept an arithmetic shift of the same size. */ + if (unsignedp) + methods1 = OPTAB_MUST_WIDEN; + + /* Arithmetic shift */ + + temp = expand_binop (mode, + left ? ashl_optab : ashr_optab, + shifted, op1, target, unsignedp, methods1); + if (temp != 0) + return temp; + } + + if (unsignedp) + { + /* No logical shift insn in either direction => + try a bit-field extract instruction if we have one. */ +#ifdef HAVE_extzv +#ifndef BITS_BIG_ENDIAN + if (HAVE_extzv && !left + && ((methods == OPTAB_DIRECT && mode == SImode) + || (methods == OPTAB_WIDEN + && GET_MODE_SIZE (mode) < GET_MODE_SIZE (SImode)))) + { + rtx shifted1 = convert_to_mode (SImode, shifted, 1); + rtx target1 = target; + + /* If -fforce-mem, don't let the operand be in memory. */ + if (flag_force_mem && GET_CODE (shifted1) == MEM) + shifted1 = force_not_mem (shifted1); + + /* If this machine's extzv insists on a register for + operand 1, arrange for that. */ + if (! ((*insn_operand_predicate[(int) CODE_FOR_extzv][1]) + (shifted1, SImode))) + shifted1 = force_reg (SImode, shifted1); + + /* If we don't have or cannot use a suggested target, + make a place for the result, in the proper mode. */ + if (methods == OPTAB_WIDEN || target1 == 0 + || ! ((*insn_operand_predicate[(int) CODE_FOR_extzv][0]) + (target1, SImode))) + target1 = gen_reg_rtx (SImode); + + op1 = convert_to_mode (SImode, op1, 0); + + /* If this machine's extzv insists on a register for + operand 3, arrange for that. */ + if (! ((*insn_operand_predicate[(int) CODE_FOR_extzv][3]) + (op1, SImode))) + op1 = force_reg (SImode, op1); + + op1 = protect_from_queue (op1, 1); + + /* TEMP gets the width of the bit field to extract: + wordsize minus # bits to shift by. */ + if (GET_CODE (op1) == CONST_INT) + temp = gen_rtx (CONST_INT, VOIDmode, + (GET_MODE_BITSIZE (mode) - INTVAL (op1))); + else + temp = expand_binop (SImode, sub_optab, + gen_rtx (CONST_INT, VOIDmode, + GET_MODE_BITSIZE (mode)), + op1, gen_reg_rtx (SImode), + 0, OPTAB_LIB_WIDEN); + /* Now extract with width TEMP, omitting OP1 least sig bits. */ + emit_insn (gen_extzv (protect_from_queue (target1, 1), + protect_from_queue (shifted1, 0), + temp, op1)); + return convert_to_mode (mode, target1, 1); + } + /* Can also do logical shift with signed bit-field extract + followed by inserting the bit-field at a different position. + That strategy is not yet implemented. */ +#endif /* not BITS_BIG_ENDIAN */ +#endif /* HAVE_extzv */ + /* We have failed to generate the logical shift and will abort. */ + } + } + if (temp == 0) + abort (); + return temp; +} + +/* Output an instruction or two to bitwise-and OP0 with OP1 + in mode MODE, with output to TARGET if convenient and TARGET is not zero. + Returns where the result is. */ +/* This function used to do more; now it could be eliminated. */ + +rtx +expand_bit_and (mode, op0, op1, target) + enum machine_mode mode; + rtx op0, op1, target; +{ + register rtx temp; + + /* First try to open-code it directly. */ + temp = expand_binop (mode, and_optab, op0, op1, target, 1, OPTAB_LIB_WIDEN); + if (temp == 0) + abort (); + return temp; +} + +/* Perform a multiplication and return an rtx for the result. + MODE is mode of value; OP0 and OP1 are what to multiply (rtx's); + TARGET is a suggestion for where to store the result (an rtx). + + We check specially for a constant integer as OP1. + If you want this check for OP0 as well, then before calling + you should swap the two operands if OP0 would be constant. */ + +rtx +expand_mult (mode, op0, op1, target, unsignedp) + enum machine_mode mode; + register rtx op0, op1, target; + int unsignedp; +{ + /* Don't use the function value register as a target + since we have to read it as well as write it, + and function-inlining gets confused by this. */ + if (target && REG_P (target) && REG_FUNCTION_VALUE_P (target)) + target = 0; + + if (GET_CODE (op1) == CONST_INT) + { + register int foo; + int bar; + int negate = INTVAL (op1) < 0; + int absval = INTVAL (op1) * (negate ? -1 : 1); + + /* Is multiplier a power of 2, or minus that? */ + foo = exact_log2 (absval); + if (foo >= 0) + { + rtx tem; + if (foo == 0) + tem = op0; + else + tem = expand_shift (LSHIFT_EXPR, mode, op0, + build_int_2 (foo, 0), + target, 0); + return (negate + ? expand_unop (mode, neg_optab, tem, target, 0) + : tem); + } + /* Is multiplier a sum of two powers of 2, or minus that? */ + bar = floor_log2 (absval); + foo = exact_log2 (absval - (1 << bar)); + if (bar >= 0 && foo >= 0) + { + rtx tem = + force_operand (gen_rtx (PLUS, mode, + expand_shift (LSHIFT_EXPR, mode, op0, + build_int_2 (bar - foo, 0), + 0, 0), + op0), + ((foo == 0 && ! negate) ? target : 0)); + + if (foo != 0) + tem = expand_shift (LSHIFT_EXPR, mode, tem, + build_int_2 (foo, 0), + negate ? 0 : target, 0); + + return negate ? expand_unop (mode, neg_optab, tem, target, 0) : tem; + } + } + /* This used to use umul_optab if unsigned, + but I think that for non-widening multiply there is no difference + between signed and unsigned. */ + op0 = expand_binop (mode, smul_optab, + op0, op1, target, unsignedp, OPTAB_LIB_WIDEN); + if (op0 == 0) + abort (); + return op0; +} + +/* Emit the code to divide OP0 by OP1, putting the result in TARGET + if that is convenient, and returning where the result is. + You may request either the quotient or the remainder as the result; + specify REM_FLAG nonzero to get the remainder. + + CODE is the expression code for which kind of division this is; + it controls how rounding is done. MODE is the machine mode to use. + UNSIGNEDP nonzero means do unsigned division. */ + +/* ??? For CEIL_MOD_EXPR, can compute incorrect remainder with ANDI + and then correct it by or'ing in missing high bits + if result of ANDI is nonzero. + For ROUND_MOD_EXPR, can use ANDI and then sign-extend the result. + This could optimize to a bfexts instruction. + But C doesn't use these operations, so their optimizations are + left for later. */ + +rtx +expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp) + int rem_flag; + enum tree_code code; + enum machine_mode mode; + register rtx op0, op1, target; + int unsignedp; +{ + register rtx temp; + int log = -1; + int can_clobber_op0; + int mod_insn_no_good = 0; + rtx adjusted_op0 = op0; + + /* Don't use the function value register as a target + since we have to read it as well as write it, + and function-inlining gets confused by this. */ + if (target && REG_P (target) && REG_FUNCTION_VALUE_P (target)) + target = 0; + + /* Don't clobber an operand while doing a multi-step calculation. */ + if (target) + if ((rem_flag && (reg_mentioned_p (target, op0) + || (GET_CODE (op0) == MEM && GET_CODE (target) == MEM))) + || reg_mentioned_p (target, op1) + || (GET_CODE (op1) == MEM && GET_CODE (target) == MEM)) + target = 0; + + if (target == 0) + target = gen_reg_rtx (mode); + + can_clobber_op0 = (GET_CODE (op0) == REG && op0 == target); + + if (GET_CODE (op1) == CONST_INT) + log = exact_log2 (INTVAL (op1)); + + /* If log is >= 0, we are dividing by 2**log, and will do it by shifting, + which is really floor-division. Otherwise we will really do a divide, + and we assume that is trunc-division. + + We must correct the dividend by adding or subtracting something + based on the divisor, in order to do the kind of rounding specified + by CODE. The correction depends on what kind of rounding is actually + available, and that depends on whether we will shift or divide. */ + + switch (code) + { + case TRUNC_MOD_EXPR: + case TRUNC_DIV_EXPR: + if (log >= 0 && ! unsignedp) + { + rtx label = gen_label_rtx (); + if (! can_clobber_op0) + { + adjusted_op0 = copy_to_suggested_reg (adjusted_op0, target); + /* Copy op0 to a reg, since emit_cmp_insn will call emit_queue + which will screw up mem refs for autoincrements. */ + op0 = force_reg (mode, op0); + } + emit_cmp_insn (adjusted_op0, const0_rtx, 0, 0, 0); + emit_jump_insn (gen_bge (label)); + expand_inc (adjusted_op0, plus_constant (op1, -1)); + emit_label (label); + mod_insn_no_good = 1; + } + break; + + case FLOOR_DIV_EXPR: + case FLOOR_MOD_EXPR: + if (log < 0 && ! unsignedp) + { + rtx label = gen_label_rtx (); + if (! can_clobber_op0) + { + adjusted_op0 = copy_to_suggested_reg (adjusted_op0, target); + op0 = force_reg (mode, op0); + } + emit_cmp_insn (adjusted_op0, const0_rtx, 0, 0, 0); + emit_jump_insn (gen_bge (label)); + expand_dec (adjusted_op0, op1); + expand_inc (adjusted_op0, const1_rtx); + emit_label (label); + mod_insn_no_good = 1; + } + break; + + case CEIL_DIV_EXPR: + case CEIL_MOD_EXPR: + if (! can_clobber_op0) + { + adjusted_op0 = copy_to_suggested_reg (adjusted_op0, target); + op0 = force_reg (mode, op0); + } + if (log < 0) + { + rtx label = 0; + if (! unsignedp) + { + label = gen_label_rtx (); + emit_cmp_insn (adjusted_op0, const0_rtx, 0, 0, 0); + emit_jump_insn (gen_ble (label)); + } + expand_inc (adjusted_op0, op1); + expand_dec (adjusted_op0, const1_rtx); + if (! unsignedp) + emit_label (label); + } + else + { + adjusted_op0 = expand_binop (GET_MODE (target), add_optab, + adjusted_op0, plus_constant (op1, -1), + 0, 0, OPTAB_LIB_WIDEN); + } + mod_insn_no_good = 1; + break; + + case ROUND_DIV_EXPR: + case ROUND_MOD_EXPR: + if (! can_clobber_op0) + { + adjusted_op0 = copy_to_suggested_reg (adjusted_op0, target); + op0 = force_reg (mode, op0); + } + if (log < 0) + { + op1 = expand_shift (RSHIFT_EXPR, mode, op1, integer_one_node, 0, 0); + if (! unsignedp) + { + rtx label = gen_label_rtx (); + emit_cmp_insn (adjusted_op0, const0_rtx, 0, 0, 0); + emit_jump_insn (gen_bge (label)); + expand_unop (mode, neg_optab, op1, op1, 0); + emit_label (label); + } + expand_inc (adjusted_op0, op1); + } + else + { + op1 = gen_rtx (CONST_INT, VOIDmode, INTVAL (op1) / 2); + expand_inc (adjusted_op0, op1); + } + mod_insn_no_good = 1; + break; + } + + if (rem_flag && !mod_insn_no_good) + { + /* Try to produce the remainder directly */ + if (log >= 0) + { + return expand_bit_and (mode, adjusted_op0, + gen_rtx (CONST_INT, VOIDmode, + INTVAL (op1) - 1), + target); + } + else + { + /* See if we can do remainder without a library call. */ + temp = sign_expand_binop (mode, umod_optab, smod_optab, + adjusted_op0, op1, target, + unsignedp, OPTAB_WIDEN); + if (temp != 0) + return temp; + /* No luck there. + Can we do remainder and divide at once without a library call? */ + temp = gen_reg_rtx (mode); + if (expand_twoval_binop (unsignedp ? udivmod_optab : sdivmod_optab, + adjusted_op0, op1, + 0, temp, unsignedp)) + return temp; + temp = 0; + } + } + + /* Produce the quotient. */ + if (log >= 0) + temp = expand_shift (RSHIFT_EXPR, mode, adjusted_op0, + build_int_2 (exact_log2 (INTVAL (op1)), 0), + target, unsignedp); + else if (rem_flag && !mod_insn_no_good) + /* If producing quotient in order to subtract for remainder, + and a remainder subroutine would be ok, + don't use a divide subroutine. */ + temp = sign_expand_binop (mode, udiv_optab, sdiv_optab, + adjusted_op0, op1, target, + unsignedp, OPTAB_WIDEN); + else + { + /* Try a quotient insn, but not a library call. */ + temp = sign_expand_binop (mode, udiv_optab, sdiv_optab, + adjusted_op0, op1, target, + unsignedp, OPTAB_WIDEN); + if (temp == 0) + { + /* No luck there. Try a quotient-and-remainder insn, + keeping the quotient alone. */ + temp = gen_reg_rtx (mode); + if (! expand_twoval_binop (unsignedp ? udivmod_optab : sdivmod_optab, + adjusted_op0, op1, + temp, 0, unsignedp)) + temp = 0; + } + + /* If still no luck, use a library call. */ + if (temp == 0) + temp = sign_expand_binop (mode, udiv_optab, sdiv_optab, + adjusted_op0, op1, target, + unsignedp, OPTAB_LIB_WIDEN); + } + + /* If we really want the remainder, get it by subtraction. */ + if (rem_flag) + { + if (temp == 0) + { + /* No divide instruction either. Use library for remainder. */ + temp = sign_expand_binop (mode, umod_optab, smod_optab, + op0, op1, target, + unsignedp, OPTAB_LIB_WIDEN); + } + else + { + /* We divided. Now finish doing X - Y * (X / Y). */ + temp = expand_mult (mode, temp, op1, temp, unsignedp); + if (! temp) abort (); + temp = expand_binop (mode, sub_optab, op0, + temp, target, unsignedp, OPTAB_LIB_WIDEN); + } + } + + if (temp == 0) + abort (); + return temp; +} + +/* Return a tree node with data type TYPE, describing the value of X. + Usually this is an RTL_EXPR, if there is no obvious better choice. */ + +static tree +make_tree (type, x) + tree type; + rtx x; +{ + tree t; + switch (GET_CODE (x)) + { + case CONST_INT: + t = build_int_2 (INTVAL (x), 0); + TREE_TYPE (t) = type; + return fold (t); + + default: + t = make_node (RTL_EXPR); + TREE_TYPE (t) = type; + RTL_EXPR_RTL (t) = x; + /* There are no insns to be output + when this rtl_expr is used. */ + RTL_EXPR_SEQUENCE (t) = 0; + return t; + } +} + +/* Return an rtx representing the value of X * MULT + ADD. + MODE is the machine mode for the computation. + UNSIGNEDP is non-zero to do unsigned multiplication. + This may emit insns. */ + +rtx +expand_mult_add (x, mult, add, mode, unsignedp) + rtx x, mult, add; + enum machine_mode mode; + int unsignedp; +{ + tree type = type_for_size (GET_MODE_BITSIZE (mode), unsignedp); + tree prod = fold (build (MULT_EXPR, type, make_tree (type, x), + make_tree (type, mult))); + tree sum = fold (build (PLUS_EXPR, type, prod, make_tree (type, add))); + return expand_expr (sum, 0, VOIDmode, 0); +} diff --git a/gcc-1.40/expr.c b/gcc-1.40/expr.c new file mode 100644 index 0000000..f0dc2b9 --- /dev/null +++ b/gcc-1.40/expr.c @@ -0,0 +1,5617 @@ +/* Convert tree expression to rtl instructions, for GNU compiler. + Copyright (C) 1988 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 1, 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 "rtl.h" +#include "tree.h" +#include "flags.h" +#include "insn-flags.h" +#include "insn-codes.h" +#include "expr.h" +#include "insn-config.h" +#include "recog.h" +#include "gvarargs.h" +#include "typeclass.h" +#include "recog.h" + +/* Decide whether a function's arguments should be processed + from first to last or from last to first. */ + +#ifdef STACK_GROWS_DOWNWARD +#ifdef PUSH_ROUNDING +#define PUSH_ARGS_REVERSED /* If it's last to first */ +#endif +#endif + +/* Like STACK_BOUNDARY but in units of bytes, not bits. */ +#define STACK_BYTES (STACK_BOUNDARY / BITS_PER_UNIT) + +/* 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 + indirect addresses so a useful potential cse is generated; + if it is used only once, instruction combination will produce + the same indirect address eventually. */ +int cse_not_expected; + +/* Nonzero to generate code for all the subroutines within an + expression before generating the upper levels of the expression. + Nowadays this is never zero. */ +int do_preexpand_calls = 1; + +/* Number of units that we should eventually pop off the stack. + These are the arguments to function calls that have already returned. */ +int pending_stack_adjust; + +/* Nonzero means stack pops must not be deferred, and deferred stack + pops must not be output. It is nonzero inside a function call, + inside a conditional expression, inside a statement expression, + 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. */ +static tree cleanups_of_this_call; + +/* Nonzero means __builtin_saveregs has already been done in this function. + The value is the pseudoreg containing the value __builtin_saveregs + returned. */ +static rtx saveregs_value; + +/* Nonzero means current function may call alloca + as a subroutine. (__builtin_alloca does not count.) */ +int may_call_alloca; + +rtx store_expr (); +static void store_constructor (); +static rtx store_field (); +static rtx expand_call (); +static void emit_call_1 (); +static rtx prepare_call_address (); +static rtx expand_builtin (); +static rtx compare (); +static rtx compare_constants (); +static rtx compare1 (); +static rtx do_store_flag (); +static void preexpand_calls (); +static rtx expand_increment (); +static void init_queue (); + +void do_pending_stack_adjust (); + +/* MOVE_RATIO is the number of move instructions that is better than + a block move. */ + +#ifndef MOVE_RATIO +#if defined (HAVE_movstrqi) || defined (HAVE_movstrhi) || defined (HAVE_movstrsi) +#define MOVE_RATIO 2 +#else +/* A value of around 6 would minimize code size; infinity would minimize + execution time. */ +#define MOVE_RATIO 15 +#endif +#endif + +/* Table indexed by tree code giving 1 if the code is for a + comparison operation, or anything that is most easily + computed with a conditional branch. + + We include tree.def to give it the proper length. + The contents thus created are irrelevant. + The real contents are initialized in init_comparisons. */ + +#define DEFTREECODE(SYM, NAME, TYPE, LENGTH) 0, + +static char comparison_code[] = { +#include "tree.def" +}; +#undef DEFTREECODE + +/* This is run once per compilation. */ + +void +init_comparisons () +{ + comparison_code[(int) EQ_EXPR] = 1; + comparison_code[(int) NE_EXPR] = 1; + comparison_code[(int) LT_EXPR] = 1; + comparison_code[(int) GT_EXPR] = 1; + comparison_code[(int) LE_EXPR] = 1; + comparison_code[(int) GE_EXPR] = 1; +} + +/* This is run at the start of compiling a function. */ + +void +init_expr () +{ + init_queue (); + may_call_alloca = 0; + saveregs_value = 0; +} + +/* 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. + + The value is a QUEUED expression to be used in place of VAR + where you want to guarantee the pre-incrementation value of VAR. */ + +static rtx +enqueue_insn (var, body) + rtx var, body; +{ + pending_chain = gen_rtx (QUEUED, GET_MODE (var), + var, 0, 0, body, pending_chain); + return pending_chain; +} + +/* Use protect_from_queue to convert a QUEUED expression + into something that you can put immediately into an instruction. + If the queued incrementation has not happened yet, + protect_from_queue returns the variable itself. + If the incrementation has happened, protect_from_queue returns a temp + that contains a copy of the old value of the variable. + + Any time an rtx which might possibly be a QUEUED is to be put + into an instruction, it must be passed through protect_from_queue first. + QUEUED expressions are not meaningful in instructions. + + Do not pass a value through protect_from_queue and then hold + on to it for a while before putting it in an instruction! + If the queue is flushed in between, incorrect code will result. */ + +rtx +protect_from_queue (x, modify) + register rtx x; + int modify; +{ + register RTX_CODE code = GET_CODE (x); + if (code != QUEUED) + { + /* A special hack for read access to (MEM (QUEUED ...)) + to facilitate use of autoincrement. + Make a copy of the contents of the memory location + rather than a copy of the address. */ + if (code == MEM && GET_CODE (XEXP (x, 0)) == QUEUED && !modify) + { + register rtx y = XEXP (x, 0); + XEXP (x, 0) = QUEUED_VAR (y); + if (QUEUED_INSN (y)) + { + register rtx temp = gen_reg_rtx (GET_MODE (x)); + emit_insn_before (gen_move_insn (temp, x), + QUEUED_INSN (y)); + return temp; + } + return x; + } + /* Otherwise, recursively protect the subexpressions of all + the kinds of rtx's that can contain a QUEUED. */ + if (code == MEM) + XEXP (x, 0) = protect_from_queue (XEXP (x, 0), 0); + else if (code == PLUS || code == MULT) + { + XEXP (x, 0) = protect_from_queue (XEXP (x, 0), 0); + XEXP (x, 1) = protect_from_queue (XEXP (x, 1), 0); + } + return x; + } + /* If the increment has not happened, use the variable itself. */ + if (QUEUED_INSN (x) == 0) + return QUEUED_VAR (x); + /* If the increment has happened and a pre-increment copy exists, + use that copy. */ + if (QUEUED_COPY (x) != 0) + return QUEUED_COPY (x); + /* The increment has happened but we haven't set up a pre-increment copy. + Set one up now, and use it. */ + QUEUED_COPY (x) = gen_reg_rtx (GET_MODE (QUEUED_VAR (x))); + emit_insn_before (gen_move_insn (QUEUED_COPY (x), QUEUED_VAR (x)), + QUEUED_INSN (x)); + return QUEUED_COPY (x); +} + +/* Return nonzero if X contains a QUEUED expression: + if it contains anything that will be altered by a queued increment. + We handle only combinations of MEM, PLUS, MINUS and MULT operators + since memory addresses generally contain only those. */ + +static int +queued_subexp_p (x) + rtx x; +{ + register enum rtx_code code = GET_CODE (x); + switch (code) + { + case QUEUED: + return 1; + case MEM: + return queued_subexp_p (XEXP (x, 0)); + case MULT: + case PLUS: + case MINUS: + return queued_subexp_p (XEXP (x, 0)) + || queued_subexp_p (XEXP (x, 1)); + } + return 0; +} + +/* Perform all the pending incrementations. */ + +void +emit_queue () +{ + register rtx p; + while (p = pending_chain) + { + QUEUED_INSN (p) = emit_insn (QUEUED_BODY (p)); + pending_chain = QUEUED_NEXT (p); + } +} + +static void +init_queue () +{ + if (pending_chain) + abort (); +} + +/* Copy data from FROM to TO, where the machine modes are not the same. + Both modes may be integer, or both may be floating. + UNSIGNEDP should be nonzero if FROM is an unsigned type. + This causes zero-extension instead of sign-extension. */ + +void +convert_move (to, from, unsignedp) + register rtx to, from; + int unsignedp; +{ + enum machine_mode to_mode = GET_MODE (to); + enum machine_mode from_mode = GET_MODE (from); + int to_real = GET_MODE_CLASS (to_mode) == MODE_FLOAT; + int from_real = GET_MODE_CLASS (from_mode) == MODE_FLOAT; + int extending = (int) to_mode > (int) from_mode; + + to = protect_from_queue (to, 1); + from = protect_from_queue (from, 0); + + if (to_real != from_real) + abort (); + + if (to_mode == from_mode + || (from_mode == VOIDmode && CONSTANT_P (from))) + { + emit_move_insn (to, from); + return; + } + + if (to_real) + { +#ifdef HAVE_extendsfdf2 + if (HAVE_extendsfdf2 && extending) + { + emit_unop_insn (CODE_FOR_extendsfdf2, to, from, UNKNOWN); + return; + } +#endif +#ifdef HAVE_truncdfsf2 + if (HAVE_truncdfsf2 && ! extending) + { + emit_unop_insn (CODE_FOR_truncdfsf2, to, from, UNKNOWN); + return; + } +#endif + emit_library_call (gen_rtx (SYMBOL_REF, Pmode, (extending + ? "__extendsfdf2" + : "__truncdfsf2")), 0, + GET_MODE (to), 1, + from, (extending ? SFmode : DFmode)); + emit_move_insn (to, hard_libcall_value (GET_MODE (to))); + return; + } + + /* Now both modes are integers. */ + + if (to_mode == DImode) + { + if (unsignedp) + { +#ifdef HAVE_zero_extendsidi2 + if (HAVE_zero_extendsidi2 && from_mode == SImode) + emit_unop_insn (CODE_FOR_zero_extendsidi2, to, from, ZERO_EXTEND); + else +#endif +#ifdef HAVE_zero_extendhidi2 + if (HAVE_zero_extendhidi2 && from_mode == HImode) + emit_unop_insn (CODE_FOR_zero_extendhidi2, to, from, ZERO_EXTEND); + else +#endif +#ifdef HAVE_zero_extendqidi2 + if (HAVE_zero_extendqidi2 && from_mode == QImode) + emit_unop_insn (CODE_FOR_zero_extendqidi2, to, from, ZERO_EXTEND); + else +#endif +#ifdef HAVE_zero_extendsidi2 + if (HAVE_zero_extendsidi2) + { + convert_move (gen_lowpart (SImode, to), from, unsignedp); + emit_unop_insn (CODE_FOR_zero_extendsidi2, to, + gen_lowpart (SImode, to), ZERO_EXTEND); + } + else +#endif + { + emit_insn (gen_rtx (CLOBBER, VOIDmode, to)); + convert_move (gen_lowpart (SImode, to), from, unsignedp); + emit_clr_insn (gen_highpart (SImode, to)); + } + } +#ifdef HAVE_extendsidi2 + else if (HAVE_extendsidi2 && from_mode == SImode) + emit_unop_insn (CODE_FOR_extendsidi2, to, from, SIGN_EXTEND); +#endif +#ifdef HAVE_extendhidi2 + else if (HAVE_extendhidi2 && from_mode == HImode) + emit_unop_insn (CODE_FOR_extendhidi2, to, from, SIGN_EXTEND); +#endif +#ifdef HAVE_extendqidi2 + else if (HAVE_extendqidi2 && from_mode == QImode) + emit_unop_insn (CODE_FOR_extendqidi2, to, from, SIGN_EXTEND); +#endif +#ifdef HAVE_extendsidi2 + else if (HAVE_extendsidi2) + { + convert_move (gen_lowpart (SImode, to), from, unsignedp); + emit_unop_insn (CODE_FOR_extendsidi2, to, + gen_lowpart (SImode, to), SIGN_EXTEND); + } +#endif +#ifdef HAVE_slt + else if (HAVE_slt && insn_operand_mode[(int) CODE_FOR_slt][0] == SImode) + { + rtx temp, target; + emit_insn (gen_rtx (CLOBBER, VOIDmode, to)); + convert_move (gen_lowpart (SImode, to), from, unsignedp); + emit_cmp_insn (gen_lowpart (SImode, to), const0_rtx, 0, 0, 0); + target = gen_highpart (SImode, to); + if (!(*insn_operand_predicate[(int) CODE_FOR_slt][0]) (target, SImode)) + temp = gen_reg_rtx (SImode); + else + temp = target; + emit_insn (gen_slt (temp)); + if (temp != target) + emit_move_insn (target, temp); + } +#endif + else + { + register rtx label = gen_label_rtx (); + rtx temp, target; + + emit_insn (gen_rtx (CLOBBER, VOIDmode, to)); + emit_clr_insn (gen_highpart (SImode, to)); + convert_move (gen_lowpart (SImode, to), from, unsignedp); + emit_cmp_insn (gen_lowpart (SImode, to), + gen_rtx (CONST_INT, VOIDmode, 0), + 0, 0, 0); + NO_DEFER_POP; + emit_jump_insn (gen_bge (label)); + target = gen_highpart (SImode, to); + temp = expand_unop (SImode, one_cmpl_optab, + target, gen_highpart (SImode, to), + 1); + if (temp != target) + emit_move_insn (target, temp); + emit_label (label); + OK_DEFER_POP; + } + return; + } + + if (from_mode == DImode) + { + convert_move (to, gen_lowpart (SImode, from), 0); + return; + } + + /* Now follow all the conversions between integers + no more than a word long. */ + + /* For truncation, usually we can just refer to FROM in a narrower mode. */ + if (GET_MODE_BITSIZE (to_mode) < GET_MODE_BITSIZE (from_mode) + && TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (to_mode), + GET_MODE_BITSIZE (from_mode)) + && ((GET_CODE (from) == MEM + && ! MEM_VOLATILE_P (from) + && ! mode_dependent_address_p (XEXP (from, 0))) + || GET_CODE (from) == REG + || GET_CODE (from) == SUBREG)) + { + emit_move_insn (to, gen_lowpart (to_mode, from)); + return; + } + + if (to_mode == SImode && from_mode == HImode) + { + if (unsignedp) + { +#ifdef HAVE_zero_extendhisi2 + if (HAVE_zero_extendhisi2) + emit_unop_insn (CODE_FOR_zero_extendhisi2, to, from, ZERO_EXTEND); + else +#endif + abort (); + } + else + { +#ifdef HAVE_extendhisi2 + if (HAVE_extendhisi2) + emit_unop_insn (CODE_FOR_extendhisi2, to, from, SIGN_EXTEND); + else +#endif + abort (); + } + return; + } + + if (to_mode == SImode && from_mode == QImode) + { + if (unsignedp) + { +#ifdef HAVE_zero_extendqisi2 + if (HAVE_zero_extendqisi2) + { + emit_unop_insn (CODE_FOR_zero_extendqisi2, to, from, ZERO_EXTEND); + return; + } +#endif +#if defined (HAVE_zero_extendqihi2) && defined (HAVE_extendhisi2) + if (HAVE_zero_extendqihi2 && HAVE_extendhisi2) + { + register rtx temp = gen_reg_rtx (HImode); + emit_unop_insn (CODE_FOR_zero_extendqihi2, temp, from, ZERO_EXTEND); + emit_unop_insn (CODE_FOR_extendhisi2, to, temp, SIGN_EXTEND); + return; + } +#endif + } + else + { +#ifdef HAVE_extendqisi2 + if (HAVE_extendqisi2) + { + emit_unop_insn (CODE_FOR_extendqisi2, to, from, SIGN_EXTEND); + return; + } +#endif +#if defined (HAVE_extendqihi2) && defined (HAVE_extendhisi2) + if (HAVE_extendqihi2 && HAVE_extendhisi2) + { + register rtx temp = gen_reg_rtx (HImode); + emit_unop_insn (CODE_FOR_extendqihi2, temp, from, SIGN_EXTEND); + emit_unop_insn (CODE_FOR_extendhisi2, to, temp, SIGN_EXTEND); + return; + } +#endif + } + abort (); + } + + if (to_mode == HImode && from_mode == QImode) + { + if (unsignedp) + { +#ifdef HAVE_zero_extendqihi2 + if (HAVE_zero_extendqihi2) + { + emit_unop_insn (CODE_FOR_zero_extendqihi2, to, from, ZERO_EXTEND); + return; + } +#endif + } + else + { +#ifdef HAVE_extendqihi2 + if (HAVE_extendqihi2) + { + emit_unop_insn (CODE_FOR_extendqihi2, to, from, SIGN_EXTEND); + return; + } +#endif + } + abort (); + } + +#if 0 /* This seems to be redundant with code 100 lines up. */ + + /* Now we are truncating an integer to a smaller one. + If the result is a temporary, we might as well just copy it, + since only the low-order part of the result needs to be valid + and it is valid with no change. */ + + if (GET_CODE (to) == REG) + { + if (GET_CODE (from) == REG) + { + emit_move_insn (to, gen_lowpart (GET_MODE (to), from)); + return; + } + else if (GET_CODE (from) == SUBREG) + { + from = copy_rtx (from); + /* This is safe since FROM is not more than one word. */ + PUT_MODE (from, GET_MODE (to)); + emit_move_insn (to, from); + return; + } +#ifndef BYTES_BIG_ENDIAN + else if (GET_CODE (from) == MEM) + { + register rtx addr = XEXP (from, 0); + if (memory_address_p (GET_MODE (to), addr)) + { + emit_move_insn (to, gen_rtx (MEM, GET_MODE (to), addr)); + return; + } + } +#endif /* not BYTES_BIG_ENDIAN */ + } +#endif /* 0 */ + + if (from_mode == SImode && to_mode == HImode) + { +#ifdef HAVE_truncsihi2 + if (HAVE_truncsihi2) + { + emit_unop_insn (CODE_FOR_truncsihi2, to, from, UNKNOWN); + return; + } +#endif + abort (); + } + + if (from_mode == SImode && to_mode == QImode) + { +#ifdef HAVE_truncsiqi2 + if (HAVE_truncsiqi2) + { + emit_unop_insn (CODE_FOR_truncsiqi2, to, from, UNKNOWN); + return; + } +#endif + abort (); + } + + if (from_mode == HImode && to_mode == QImode) + { +#ifdef HAVE_trunchiqi2 + if (HAVE_trunchiqi2) + { + emit_unop_insn (CODE_FOR_trunchiqi2, to, from, UNKNOWN); + return; + } +#endif + abort (); + } + + /* Mode combination is not recognized. */ + abort (); +} + +/* Return an rtx for a value that would result + from converting X to mode MODE. + Both X and MODE may be floating, or both integer. + UNSIGNEDP is nonzero if X is an unsigned value. + This can be done by referring to a part of X in place + or by copying to a new temporary with conversion. */ + +rtx +convert_to_mode (mode, x, unsignedp) + enum machine_mode mode; + rtx x; + int unsignedp; +{ + register rtx temp; + if (mode == GET_MODE (x)) + return x; + if (integer_mode_p (mode) + && GET_MODE_SIZE (mode) <= GET_MODE_SIZE (GET_MODE (x)) + && (GET_CODE (x) == REG || GET_CODE (x) == CONST_DOUBLE + || (GET_CODE (x) == MEM && ! MEM_VOLATILE_P (x)))) + return gen_lowpart (mode, x); + temp = gen_reg_rtx (mode); + convert_move (temp, x, unsignedp); + return temp; +} + +int +integer_mode_p (mode) + enum machine_mode mode; +{ + return (int) mode > (int) VOIDmode && (int) mode <= (int) TImode; +} + +/* Generate several move instructions to copy LEN bytes + from block FROM to block TO. (These are MEM rtx's with BLKmode). + The caller must pass FROM and TO + through protect_from_queue before calling. + ALIGN (in bytes) is maximum alignment we can assume. */ + +struct move_by_pieces +{ + rtx to; + rtx to_addr; + int autinc_to; + int explicit_inc_to; + rtx from; + rtx from_addr; + int autinc_from; + int explicit_inc_from; + int len; + int offset; + int reverse; +}; + +static void move_by_pieces_1 (); +static int move_by_pieces_ninsns (); + +static void +move_by_pieces (to, from, len, align) + rtx to, from; + int len, align; +{ + struct move_by_pieces data; + rtx to_addr = XEXP (to, 0), from_addr = XEXP (from, 0); + + data.offset = 0; + data.to_addr = to_addr; + data.from_addr = from_addr; + data.to = to; + data.from = from; + 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.autinc_from + = (GET_CODE (from_addr) == PRE_INC || GET_CODE (from_addr) == PRE_DEC + || GET_CODE (from_addr) == POST_INC + || GET_CODE (from_addr) == POST_DEC); + + data.explicit_inc_from = 0; + 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; + + /* 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_from && data.autinc_to) + && move_by_pieces_ninsns (len, align) > 2) + { +#ifdef HAVE_PRE_DECREMENT + if (data.reverse && ! data.autinc_from) + { + data.from_addr = copy_addr_to_reg (plus_constant (from_addr, len)); + data.autinc_from = 1; + data.explicit_inc_from = -1; + } +#endif +#ifdef HAVE_POST_INCREMENT + if (! data.autinc_from) + { + data.from_addr = copy_addr_to_reg (from_addr); + data.autinc_from = 1; + data.explicit_inc_from = 1; + } +#endif + if (!data.autinc_from && CONSTANT_P (from_addr)) + data.from_addr = copy_addr_to_reg (from_addr); +#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); + } + +#ifdef STRICT_ALIGNMENT + if (align > MOVE_MAX || align >= BIGGEST_ALIGNMENT / BITS_PER_UNIT) + align = MOVE_MAX; +#else + align = MOVE_MAX; +#endif + +#ifdef HAVE_movti + if (HAVE_movti && align >= GET_MODE_SIZE (TImode)) + move_by_pieces_1 (gen_movti, TImode, &data); +#endif +#ifdef HAVE_movdi + if (HAVE_movdi && align >= GET_MODE_SIZE (DImode)) + move_by_pieces_1 (gen_movdi, DImode, &data); +#endif +#ifdef HAVE_movsi + if (align >= GET_MODE_SIZE (SImode)) + move_by_pieces_1 (gen_movsi, SImode, &data); +#endif +#ifdef HAVE_movhi + if (HAVE_movhi && align >= GET_MODE_SIZE (HImode)) + move_by_pieces_1 (gen_movhi, HImode, &data); +#endif +#ifdef HAVE_movqi + move_by_pieces_1 (gen_movqi, QImode, &data); +#else + movqi instruction required in machine description +#endif +} + +/* Return number of insns required to move L bytes by pieces. + ALIGN (in bytes) is maximum alignment we can assume. */ + +static int +move_by_pieces_ninsns (l, align) + unsigned int l; + int align; +{ + register int n_insns = 0; + +#ifdef STRICT_ALIGNMENT + if (align > MOVE_MAX || align >= BIGGEST_ALIGNMENT / BITS_PER_UNIT) + align = MOVE_MAX; +#else + align = MOVE_MAX; +#endif + +#ifdef HAVE_movti + if (HAVE_movti && align >= GET_MODE_SIZE (TImode)) + n_insns += l / GET_MODE_SIZE (TImode), l %= GET_MODE_SIZE (TImode); +#endif +#ifdef HAVE_movdi + if (HAVE_movdi && align >= GET_MODE_SIZE (DImode)) + n_insns += l / GET_MODE_SIZE (DImode), l %= GET_MODE_SIZE (DImode); +#endif +#ifdef HAVE_movsi + if (HAVE_movsi && align >= GET_MODE_SIZE (SImode)) + n_insns += l / GET_MODE_SIZE (SImode), l %= GET_MODE_SIZE (SImode); +#endif +#ifdef HAVE_movhi + if (HAVE_movhi && align >= GET_MODE_SIZE (HImode)) + n_insns += l / GET_MODE_SIZE (HImode), l %= GET_MODE_SIZE (HImode); +#endif + n_insns += l; + + return n_insns; +} + +/* Subroutine of move_by_pieces. Move 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 +move_by_pieces_1 (genfun, mode, data) + rtx (*genfun) (); + enum machine_mode mode; + struct move_by_pieces *data; +{ + register int size = GET_MODE_SIZE (mode); + register rtx to1, from1; + + while (data->len >= size) + { + 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))); + from1 = + (data->autinc_from + ? gen_rtx (MEM, mode, data->from_addr) + : change_address (data->from, mode, + plus_constant (data->from_addr, data->offset))); + +#ifdef HAVE_PRE_DECREMENT + if (data->explicit_inc_to < 0) + emit_insn (gen_sub2_insn (data->to_addr, + gen_rtx (CONST_INT, VOIDmode, size))); + if (data->explicit_inc_from < 0) + emit_insn (gen_sub2_insn (data->from_addr, + gen_rtx (CONST_INT, VOIDmode, size))); +#endif + + emit_insn ((*genfun) (to1, from1)); +#ifdef HAVE_POST_INCREMENT + if (data->explicit_inc_to > 0) + emit_insn (gen_add2_insn (data->to_addr, + gen_rtx (CONST_INT, VOIDmode, size))); + if (data->explicit_inc_from > 0) + emit_insn (gen_add2_insn (data->from_addr, + gen_rtx (CONST_INT, VOIDmode, size))); +#endif + + if (! data->reverse) data->offset += size; + + data->len -= size; + } +} + +/* Emit code to move a block Y to a block X. + This may be done with string-move instructions, + with multiple scalar move instructions, or with a library call. + + Both X and Y must be MEM rtx's (perhaps inside VOLATILE) + 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. */ + +static void +emit_block_move (x, y, size, align) + rtx x, y; + rtx size; + int align; +{ + if (GET_MODE (x) != BLKmode) + abort (); + + if (GET_MODE (y) != BLKmode) + abort (); + + x = protect_from_queue (x, 1); + y = protect_from_queue (y, 0); + + if (GET_CODE (x) != MEM) + abort (); + if (GET_CODE (y) != MEM) + abort (); + if (size == 0) + abort (); + + if (GET_CODE (size) == CONST_INT + && (move_by_pieces_ninsns ((unsigned) INTVAL (size), align) + < MOVE_RATIO)) + move_by_pieces (x, y, 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. */ +#ifdef HAVE_movstrqi + if (HAVE_movstrqi + && GET_CODE (size) == CONST_INT + && ((unsigned) INTVAL (size) + < (1 << (GET_MODE_BITSIZE (QImode) - 1)))) + { + emit_insn (gen_movstrqi (x, y, size, + gen_rtx (CONST_INT, VOIDmode, align))); + return; + } +#endif +#ifdef HAVE_movstrhi + if (HAVE_movstrhi + && GET_CODE (size) == CONST_INT + && ((unsigned) INTVAL (size) + < (1 << (GET_MODE_BITSIZE (HImode) - 1)))) + { + emit_insn (gen_movstrhi (x, y, size, + gen_rtx (CONST_INT, VOIDmode, align))); + return; + } +#endif +#ifdef HAVE_movstrsi + if (HAVE_movstrsi) + { + emit_insn (gen_movstrsi (x, y, size, + gen_rtx (CONST_INT, VOIDmode, align))); + return; + } +#endif + +#ifdef TARGET_MEM_FUNCTIONS + emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "memcpy"), 0, + VOIDmode, 3, XEXP (x, 0), Pmode, + XEXP (y, 0), Pmode, + size, Pmode); +#else + emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "bcopy"), 0, + VOIDmode, 3, XEXP (y, 0), Pmode, + XEXP (x, 0), Pmode, + size, Pmode); +#endif + } +} + +/* Copy all or part of a BLKmode value X into registers starting at REGNO. + The number of registers to be filled is NREGS. */ + +static void +move_block_to_reg (regno, x, nregs) + int regno; + rtx x; + int nregs; +{ + int i; + if (GET_CODE (x) == CONST_DOUBLE && x != dconst0_rtx) + x = force_const_double_mem (x); + for (i = 0; i < nregs; i++) + { + if (GET_CODE (x) == REG) + emit_move_insn (gen_rtx (REG, SImode, regno + i), + gen_rtx (SUBREG, SImode, x, i)); + else if (x == dconst0_rtx || x == const0_rtx) + emit_move_insn (gen_rtx (REG, SImode, regno + i), + const0_rtx); + else + emit_move_insn (gen_rtx (REG, SImode, regno + i), + gen_rtx (MEM, SImode, + memory_address (SImode, + plus_constant (XEXP (x, 0), + i * GET_MODE_SIZE (SImode))))); + } +} + +/* Copy all or part of a BLKmode value X out of registers starting at REGNO. + The number of registers to be filled is NREGS. */ + +void +move_block_from_reg (regno, x, nregs) + int regno; + rtx x; + int nregs; +{ + int i; + for (i = 0; i < nregs; i++) + { + if (GET_CODE (x) == REG) + emit_move_insn (gen_rtx (SUBREG, SImode, x, i), + gen_rtx (REG, SImode, regno + i)); + else + emit_move_insn (gen_rtx (MEM, SImode, + memory_address (SImode, + plus_constant (XEXP (x, 0), + i * GET_MODE_SIZE (SImode)))), + gen_rtx (REG, SImode, regno + i)); + } +} + +/* Mark NREGS consecutive regs, starting at REGNO, as being live now. */ + +static void +use_regs (regno, nregs) + int regno; + int nregs; +{ + int i; + for (i = 0; i < nregs; i++) + emit_insn (gen_rtx (USE, VOIDmode, gen_rtx (REG, SImode, regno + i))); +} + +/* Write zeros through the storage of OBJECT. + If OBJECT has BLKmode, SIZE is its length in bytes. */ + +void +clear_storage (object, size) + rtx object; + int size; +{ + if (GET_MODE (object) == BLKmode) + { +#ifdef TARGET_MEM_FUNCTIONS + emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "memset"), 0, + VOIDmode, 3, + XEXP (object, 0), Pmode, const0_rtx, Pmode, + gen_rtx (CONST_INT, VOIDmode, size), Pmode); +#else + emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "bzero"), 0, + VOIDmode, 2, + XEXP (object, 0), Pmode, + gen_rtx (CONST_INT, VOIDmode, size), Pmode); +#endif + } + else + emit_move_insn (object, const0_rtx); +} + +/* Generate code to copy Y into X. + Both Y and X must have the same mode, except that + Y can be a constant with VOIDmode. + This mode cannot be BLKmode; use emit_block_move for that. + + Return the last instruction emitted. */ + +rtx +emit_move_insn (x, y) + rtx x, y; +{ + enum machine_mode mode = GET_MODE (x); + x = protect_from_queue (x, 1); + y = protect_from_queue (y, 0); + + if (mode == BLKmode) + abort (); + if (mov_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing) + { + int icode = (int) mov_optab->handlers[(int) mode].insn_code; + if (! (*insn_operand_predicate[icode][1]) (y, mode) + && (CONSTANT_P (y) || GET_CODE (y) == CONST_DOUBLE)) + { + y = force_const_mem (mode, y); + if (! memory_address_p (mode, XEXP (y, 0))) + y = gen_rtx (MEM, mode, memory_address (mode, XEXP (y, 0))); + } + return emit_insn (GEN_FCN (icode) (x, y)); + } +#if 0 + /* It turns out you get much better optimization (in cse and flow) + if you define movdi and movdf instruction patterns + even if they must turn into multiple assembler instructions. */ + else if (GET_MODE_SIZE (mode) >= GET_MODE_SIZE (SImode)) + { + register int count = GET_MODE_SIZE (mode) / GET_MODE_SIZE (SImode); + register int i; + if (GET_CODE (y) == CONST_DOUBLE && y != dconst0_rtx) + y = force_const_double_mem (y); + for (i = 0; i < count; i++) + { + rtx x1, y1; + if (GET_CODE (x) == REG) + x1 = gen_rtx (SUBREG, SImode, x, i); + else + x1 = gen_rtx (MEM, SImode, + memory_address (SImode, + plus_constant (XEXP (x, 0), + i * GET_MODE_SIZE (SImode)))); + if (GET_CODE (y) == REG) + y1 = gen_rtx (SUBREG, SImode, y, i); + else if (y == dconst0_rtx) + y1 = const0_rtx; + else + y1 = gen_rtx (MEM, SImode, + memory_address (SImode, + plus_constant (XEXP (y, 0), + i * GET_MODE_SIZE (SImode)))); + emit_insn (gen_movsi (protect_from_queue (x1, 1), protect_from_queue (y1, 0))); + } + } +#endif + else + abort (); +} + +/* Pushing data onto the stack. */ + +/* Push a block of length SIZE (perhaps variable) + and return an rtx to address the beginning of the block. + Note that it is not possible for the value returned to be a QUEUED. + The value may be stack_pointer_rtx. + + EXTRA is the number of bytes of padding to push in addition to the block. + The padding is pushed "after" the specified size. + + The value we return does take account of STACK_POINTER_OFFSET. */ + +rtx +push_block (size, extra) + rtx size; + int extra; +{ + register rtx temp; + if (CONSTANT_P (size)) + anti_adjust_stack (plus_constant (size, extra)); + else if (GET_CODE (size) == REG && extra == 0) + anti_adjust_stack (size); + else + { + rtx temp = copy_to_mode_reg (Pmode, size); + if (extra != 0) + temp = expand_binop (Pmode, add_optab, + temp, gen_rtx (CONST_INT, VOIDmode, extra), + temp, 0, OPTAB_LIB_WIDEN); + anti_adjust_stack (temp); + } + +#ifdef STACK_GROWS_DOWNWARD + temp = stack_pointer_rtx; + if (extra != 0) + temp = plus_constant (temp, extra); +#else + temp = gen_rtx (PLUS, Pmode, + stack_pointer_rtx, + negate_rtx (Pmode, size)); + if (GET_CODE (size) != CONST_INT) + temp = force_operand (temp, 0); + if (extra != 0) + temp = plus_constant (temp, -extra); +#endif + +#ifdef STACK_POINTER_OFFSET + temp = plus_constant (temp, STACK_POINTER_OFFSET); +#endif /* STACK_POINTER_OFFSET */ + + return memory_address (QImode, temp); +} + +static rtx +gen_push_operand () +{ + return gen_rtx ( +#ifdef STACK_GROWS_DOWNWARD + PRE_DEC, +#else + PRE_INC, +#endif + Pmode, + stack_pointer_rtx); +} + +/* Generate code to push X onto the stack, assuming it has mode MODE. + MODE is redundant except when X is a CONST_INT (since they don't + carry mode info). + SIZE is an rtx for the size of data to be copied (in bytes), + needed only if X is BLKmode. + + ALIGN (in bytes) is maximum alignment we can assume. + + If PARTIAL is nonzero, then copy that many of the first words + of X into registers starting with REG, and push the rest of X. + The amount of space pushed is decreased by PARTIAL words, + rounded *down* to a multiple of PARM_BOUNDARY. + REG must be a hard register in this case. + + EXTRA is the amount in bytes of extra space to leave next to this arg. + Within the function, we set EXTRA to zero once the padding is done, + to avoid padding twice. + + On a machine that lacks real push insns, ARGS_ADDR is the address of + the bottom of the argument block for this call. We use indexing off there + to store the arg. On machines with push insns, ARGS_ADDR is 0. + + ARGS_SO_FAR is the size of args previously pushed for this call. */ + +static void +emit_push_insn (x, mode, size, align, partial, reg, extra, args_addr, args_so_far) + register rtx x; + enum machine_mode mode; + rtx size; + int align; + int partial; + rtx reg; + int extra; + rtx args_addr; + rtx args_so_far; +{ + rtx xinner; + enum direction stack_direction +#ifdef STACK_GROWS_DOWNWARD + = downward; +#else + = upward; +#endif + + /* Decide where to pad the argument: `downward' for below, + `upward' for above, or `none' for don't pad it. + Default is below for small data on big-endian machines; else above. */ + enum direction where_pad = FUNCTION_ARG_PADDING (mode, size); + + xinner = x = protect_from_queue (x, 0); + + if (extra) + { + if (args_addr == 0) + { + /* Push padding now if padding above and stack grows down, + or if padding below and stack grows up. */ + if (where_pad != none && where_pad != stack_direction) + { + anti_adjust_stack (gen_rtx (CONST_INT, VOIDmode, extra)); + extra = 0; + } + } + else + { + /* If space already allocated, just adjust the address we use. */ + if (where_pad == downward) + { + args_so_far = plus_constant (args_so_far, extra); + } + /* If padding comes after a space already allocated, + there is nothing to do. */ + extra = 0; + } + } + + if (mode == BLKmode) + { + /* Copy a block into the stack, entirely or partially. */ + + register rtx temp; + int used = partial * UNITS_PER_WORD; + int offset = used % (PARM_BOUNDARY / BITS_PER_UNIT); + int skip; + + if (size == 0) + abort (); + + used -= offset; + + /* USED is now the # of bytes we need not copy to the stack + because registers will take care of them. */ + + if (partial != 0) + xinner = change_address (xinner, BLKmode, + plus_constant (XEXP (xinner, 0), used)); + +/* If the partial register-part of the arg counts in its stack size, + 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 FIRST_PARM_CALLER_OFFSET + skip = 0; +#else + skip = used; +#endif + +#ifdef PUSH_ROUNDING + /* Do it with several push insns if that doesn't take lots of insns + and if there is no difficulty with push insns that skip bytes + on the stack for alignment purposes. */ + if (args_addr == 0 + && GET_CODE (size) == CONST_INT + && args_addr == 0 + && skip == 0 + && (move_by_pieces_ninsns ((unsigned) INTVAL (size) - used, align) + < MOVE_RATIO) + && PUSH_ROUNDING (INTVAL (size)) == INTVAL (size)) + move_by_pieces (gen_rtx (MEM, BLKmode, gen_push_operand ()), xinner, + INTVAL (size) - used, align); + else +#endif /* PUSH_ROUNDING */ + { + /* Otherwise make space on the stack and copy the data + to the address of that space. */ + + /* Deduct words put into registers from the size we must copy. */ + if (partial != 0) + { + if (GET_CODE (size) == CONST_INT) + size = gen_rtx (CONST_INT, VOIDmode, INTVAL (size) - used); + else + size = expand_binop (GET_MODE (size), sub_optab, size, + gen_rtx (CONST_INT, VOIDmode, used), + 0, 0, OPTAB_LIB_WIDEN); + } + + /* Get the address of the stack space. */ + if (! args_addr) + { + temp = push_block (size, extra); + extra = 0; + } + else if (GET_CODE (args_so_far) == CONST_INT) + temp = memory_address (BLKmode, + plus_constant (args_addr, + skip + INTVAL (args_so_far))); + else + temp = memory_address (BLKmode, + plus_constant (gen_rtx (PLUS, Pmode, + args_addr, args_so_far), + skip)); + + /* 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, + 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)))) + { + emit_insn (gen_movstrqi (gen_rtx (MEM, BLKmode, temp), + xinner, size, + gen_rtx (CONST_INT, VOIDmode, align))); + goto ret; + } +#endif +#ifdef HAVE_movstrhi + if (HAVE_movstrhi + && GET_CODE (size) == CONST_INT + && ((unsigned) INTVAL (size) + < (1 << (GET_MODE_BITSIZE (HImode) - 1)))) + { + emit_insn (gen_movstrhi (gen_rtx (MEM, BLKmode, temp), + xinner, size, + gen_rtx (CONST_INT, VOIDmode, align))); + goto ret; + } +#endif +#ifdef HAVE_movstrsi + if (HAVE_movstrsi) + { + emit_insn (gen_movstrsi (gen_rtx (MEM, BLKmode, temp), + xinner, size, + gen_rtx (CONST_INT, VOIDmode, align))); + goto ret; + } +#endif + + if (reg_mentioned_p (stack_pointer_rtx, temp)) + { + /* Now that emit_library_call does force_operand + before pushing anything, preadjustment does not work. */ + temp = copy_to_reg (temp); +#if 0 + /* Correct TEMP so it holds what will be a description of + the address to copy to, valid after one arg is pushed. */ + int xsize = GET_MODE_SIZE (Pmode); +#ifdef PUSH_ROUNDING + xsize = PUSH_ROUNDING (xsize); +#endif + xsize = ((xsize + PARM_BOUNDARY / BITS_PER_UNIT - 1) + / (PARM_BOUNDARY / BITS_PER_UNIT) + * (PARM_BOUNDARY / BITS_PER_UNIT)); +#ifdef TARGET_MEM_FUNCTIONS + /* If we are calling bcopy, we push one arg before TEMP. + If calling memcpy, we push two. */ + xsize *= 2; +#endif +#ifdef STACK_GROWS_DOWNWARD + temp = plus_constant (temp, xsize); +#else + temp = plus_constant (temp, -xsize); +#endif /* not STACK_GROWS_DOWNWARD */ +#endif /* 0 */ + } + + /* Make inhibit_defer_pop nonzero around the library call + to force it to pop the bcopy-arguments right away. */ + NO_DEFER_POP; +#ifdef TARGET_MEM_FUNCTIONS + emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "memcpy"), 0, + VOIDmode, 3, temp, Pmode, XEXP (xinner, 0), Pmode, + size, Pmode); +#else + emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "bcopy"), 0, + VOIDmode, 3, XEXP (xinner, 0), Pmode, temp, Pmode, + size, Pmode); +#endif + OK_DEFER_POP; + } + } + else if (partial > 0) + { + /* Scalar partly in registers. */ + + int size = GET_MODE_SIZE (mode) / UNITS_PER_WORD; + int i; + int not_stack; + /* # words of start of argument + that we must make space for but need not store. */ + int offset = partial % (PARM_BOUNDARY / BITS_PER_WORD); + int args_offset = INTVAL (args_so_far); + int skip; + + /* If we make space by pushing it, we might as well push + the real data. Otherwise, we can leave OFFSET nonzero + and leave the space uninitialized. */ + if (args_addr == 0) + offset = 0; + + /* Now NOT_STACK gets the number of words that we don't need to + allocate on the stack. */ + not_stack = partial - offset; + +/* If the partial register-part of the arg counts in its stack size, + 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 FIRST_PARM_CALLER_OFFSET + skip = 0; +#else + skip = not_stack; +#endif + + if (GET_CODE (x) == CONST_DOUBLE && x != dconst0_rtx) + x = force_const_double_mem (x); + + /* Loop over all the words allocated on the stack for this arg. */ + /* We can do it by words, because any scalar bigger than a word + has a size a multiple of a word. */ +#ifndef PUSH_ARGS_REVERSED + for (i = not_stack; i < size; i++) +#else + for (i = size - 1; i >= not_stack; i--) +#endif + if (i >= not_stack + offset) + { + rtx wd; + rtx addr; + /* Get the next word of the value in WD. */ + if (GET_CODE (x) == MEM) + { + rtx addr = memory_address (SImode, + plus_constant (XEXP (x, 0), + i * UNITS_PER_WORD)); + /* Copy to a reg, since machine may lack + memory-to-memory move insns. */ + wd = copy_to_reg (gen_rtx (MEM, SImode, addr)); + } + else if (GET_CODE (x) == REG) + wd = gen_rtx (SUBREG, SImode, x, i); + else if (x == dconst0_rtx || x == const0_rtx) + wd = const0_rtx; + else + abort (); + + emit_push_insn (wd, + SImode, 0, align, 0, 0, 0, args_addr, + gen_rtx (CONST_INT, VOIDmode, + args_offset + (i - not_stack + skip) * UNITS_PER_WORD)); + } + } + else + { + rtx addr; +#ifdef PUSH_ROUNDING + if (args_addr == 0) + 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)); + + emit_move_insn (gen_rtx (MEM, mode, addr), x); + } + + ret: + /* If part should go in registers, copy that part + into the appropriate registers. Do this now, at the end, + since mem-to-mem copies above may do function calls. */ + if (partial > 0) + move_block_to_reg (REGNO (reg), x, partial); + + if (extra) + anti_adjust_stack (gen_rtx (CONST_INT, VOIDmode, extra)); +} + +/* Output a library call to function FUN (a SYMBOL_REF rtx) + (emitting the queue unless NO_QUEUE is nonzero), + for a value of mode OUTMODE, + with NARGS different arguments, passed as alternating rtx values + and machine_modes to convert them to. + The rtx values should have been passed through protect_from_queue already. */ + +void +emit_library_call (va_alist) + va_dcl +{ + register va_list p; + register int args_size = 0; + register int argnum; + enum machine_mode outmode; + int nargs; + rtx fun; + rtx orgfun; + int inc; + int count; + rtx *regvec; + rtx argblock = 0; + CUMULATIVE_ARGS args_so_far; + struct arg { rtx value; enum machine_mode mode; rtx reg; int partial; }; + struct arg *argvec; + int old_inhibit_defer_pop = inhibit_defer_pop; + int stack_padding = 0; + int no_queue = 0; + rtx use_insns; + + va_start (p); + orgfun = fun = va_arg (p, rtx); + no_queue = va_arg (p, int); + outmode = va_arg (p, enum machine_mode); + nargs = va_arg (p, int); + + regvec = (rtx *) alloca (nargs * sizeof (rtx)); + + /* Copy all the libcall-arguments out of the varargs data + and into a vector ARGVEC. */ + argvec = (struct arg *) alloca (nargs * sizeof (struct arg)); + + INIT_CUMULATIVE_ARGS (args_so_far, (tree)0); + for (count = 0; count < nargs; count++) + { + rtx val = va_arg (p, rtx); + enum machine_mode mode = va_arg (p, enum machine_mode); + int arg_size; + + argvec[count].value = val; + + /* Convert the arg value to the mode the library wants. + Also make sure it is a reasonable operand + for a move or push insn. */ + /* ??? It is wrong to do it here; must do it earlier + where we know the signedness of the arg. */ +#ifdef GNULIB_NEEDS_DOUBLE + if (GNULIB_NEEDS_DOUBLE && mode == SFmode) + mode = DFmode; +#endif + if (GET_MODE (val) != mode && GET_MODE (val) != VOIDmode) + { + val = gen_reg_rtx (mode); + convert_move (val, argvec[count].value, 0); + } + else if (GET_CODE (val) != REG && GET_CODE (val) != MEM + + && ! ((CONSTANT_P (val) || GET_CODE (val) == CONST_DOUBLE) + && LEGITIMATE_CONSTANT_P (val))) + val = force_operand (val, 0); + + argvec[count].value = val; + argvec[count].mode = mode; + + regvec[count] = FUNCTION_ARG (args_so_far, mode, (tree)0, 1); + +#ifdef FUNCTION_ARG_PARTIAL_NREGS + argvec[count].partial + = FUNCTION_ARG_PARTIAL_NREGS (args_so_far, mode, (tree)0, 1); +#else + argvec[count].partial = 0; +#endif + + FUNCTION_ARG_ADVANCE (args_so_far, mode, (tree)0, 1); + } + va_end (p); + + /* If we have no actual push instructions, make space for all the args + right now. */ +#ifndef PUSH_ROUNDING + for (count = 0; count < nargs; count++) + { + register enum machine_mode mode = argvec[count].mode; + register rtx reg = regvec[count]; + register int partial = argvec[count].partial; + + if (reg == 0 || partial != 0) + args_size += GET_MODE_SIZE (mode); + if (partial != 0) + args_size -= partial * GET_MODE_SIZE (SImode); + } + + if (args_size != 0) + { +#ifdef STACK_ARGS_ADJUST + struct args_size size; + size.constant = args_size; + size.var = 0; + STACK_ARGS_ADJUST (size); + args_size = size.constant; +#endif + argblock + = push_block (round_push (gen_rtx (CONST_INT, VOIDmode, args_size)), 0); + } +#endif /* no PUSH_ROUNDING */ + +#ifdef PUSH_ARGS_REVERSED + inc = -1; + argnum = nargs - 1; +#else + inc = 1; + argnum = 0; +#endif + args_size = stack_padding; + + for (count = 0; count < nargs; count++, argnum += inc) + { + register enum machine_mode mode = argvec[argnum].mode; + register rtx val = argvec[argnum].value; + rtx reg = regvec[argnum]; + int partial = argvec[argnum].partial; + int arg_size; + + if (reg != 0 && partial == 0) + emit_move_insn (reg, val); + else + emit_push_insn (val, mode, 0, 0, partial, reg, 0, argblock, + gen_rtx (CONST_INT, VOIDmode, args_size)); + + /* Compute size of stack space used by this argument. */ + if (reg == 0 || partial != 0) + arg_size = GET_MODE_SIZE (mode); + else + arg_size = 0; + if (partial != 0) + arg_size + -= ((partial * UNITS_PER_WORD) + / (PARM_BOUNDARY / BITS_PER_UNIT) + * (PARM_BOUNDARY / BITS_PER_UNIT)); + + args_size += arg_size; + + NO_DEFER_POP; + } + + /* For version 1.37, try deleting this entirely. */ + if (! no_queue) + emit_queue (); + + fun = prepare_call_address (fun, 0); + + /* Any regs containing parms remain in use through the call. */ + start_sequence (); + for (count = 0; count < nargs; count++) + if (regvec[count] != 0) + emit_insn (gen_rtx (USE, VOIDmode, regvec[count])); + + use_insns = gen_sequence (); + end_sequence (); + +#ifdef STACK_BOUNDARY + args_size = (args_size + STACK_BYTES - 1) / STACK_BYTES * STACK_BYTES; +#endif + + /* Don't allow popping to be deferred, since then + cse'ing of library calls could delete a call and leave the pop. */ + NO_DEFER_POP; + emit_call_1 (fun, get_identifier (XSTR (orgfun, 0)), args_size, + FUNCTION_ARG (args_so_far, VOIDmode, void_type_node, 1), + outmode != VOIDmode ? hard_libcall_value (outmode) : 0, + old_inhibit_defer_pop + 1, use_insns); + OK_DEFER_POP; +} + +/* Expand an assignment that stores the value of FROM into TO. + If WANT_VALUE is nonzero, return an rtx for the value of TO. + (This may contain a QUEUED rtx.) + Otherwise, the returned value is not meaningful. + + SUGGEST_REG is no longer actually used. + It used to mean, copy the value through a register + and return that register, if that is possible. + But now we do this if WANT_VALUE. + + If the value stored is a constant, we return the constant. */ + +rtx +expand_assignment (to, from, want_value, suggest_reg) + tree to, from; + int want_value; + int suggest_reg; +{ + register rtx to_rtx = 0; + + /* Don't crash if the lhs of the assignment was erroneous. */ + + if (TREE_CODE (to) == ERROR_MARK) + return expand_expr (from, 0, VOIDmode, 0); + + /* 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 + has the same problem. */ + + if (TREE_CODE (to) == COMPONENT_REF + || (TREE_CODE (to) == ARRAY_REF + && TREE_CODE (TREE_OPERAND (to, 1)) == INTEGER_CST + && TREE_CODE (TYPE_SIZE (TREE_TYPE (to))) == INTEGER_CST)) + { + register enum machine_mode mode1; + int bitsize; + int volstruct = 0; + tree tem = to; + int bitpos = 0; + int unsignedp; + + if (TREE_CODE (to) == COMPONENT_REF) + { + tree field = TREE_OPERAND (to, 1); + bitsize = TREE_INT_CST_LOW (DECL_SIZE (field)) * DECL_SIZE_UNIT (field); + mode1 = DECL_MODE (TREE_OPERAND (to, 1)); + unsignedp = TREE_UNSIGNED (field); + } + else + { + mode1 = TYPE_MODE (TREE_TYPE (to)); + bitsize = GET_MODE_BITSIZE (mode1); + unsignedp = TREE_UNSIGNED (TREE_TYPE (to)); + } + + /* Compute cumulative bit-offset for nested component-refs + and array-refs, and find the ultimate containing object. */ + + while (1) + { + if (TREE_CODE (tem) == COMPONENT_REF) + { + bitpos += DECL_OFFSET (TREE_OPERAND (tem, 1)); + if (TREE_THIS_VOLATILE (tem)) + volstruct = 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))); + if (TREE_THIS_VOLATILE (tem)) + volstruct = 1; + } + else + break; + tem = TREE_OPERAND (tem, 0); + } + /* TEM is now the containing data object. */ + + /* If we are going to use store_bit_field and extract_bit_field, + make sure to_rtx will be safe for multiple use. */ + if (mode1 == BImode && want_value) + tem = stabilize_reference (tem); + + to_rtx = expand_expr (tem, 0, VOIDmode, 0); + if (volstruct) + { + if (GET_CODE (to_rtx) == MEM) + MEM_VOLATILE_P (to_rtx) = 1; + else + abort (); + } + + return store_field (to_rtx, bitsize, bitpos, mode1, from, + (want_value + /* Spurious cast makes HPUX compiler happy. */ + ? (enum machine_mode) TYPE_MODE (TREE_TYPE (to)) + : VOIDmode), + unsignedp, + /* Required alignment of containing datum. */ + TYPE_ALIGN (TREE_TYPE (tem)) / BITS_PER_UNIT, + int_size_in_bytes (TREE_TYPE (tem))); + } + + /* Ordinary treatment. Expand TO to get a REG or MEM rtx. + Don't re-expand if it was expanded already (in COMPONENT_REF case). */ + + if (to_rtx == 0) + to_rtx = expand_expr (to, 0, VOIDmode, 0); + + /* Compute FROM and store the value in the rtx we got. */ + + return store_expr (from, to_rtx, want_value); +} + +/* Generate code for computing expression EXP, + and storing the value into TARGET. + Returns TARGET or an equivalent value. + TARGET may contain a QUEUED rtx. + + If SUGGEST_REG is nonzero, copy the value through a register + and return that register, if that is possible. + + If the value stored is a constant, we return the constant. */ + +rtx +store_expr (exp, target, suggest_reg) + register tree exp; + register rtx target; + int suggest_reg; +{ + register rtx temp; + int dont_return_target = 0; + + /* Copying a non-constant CONSTRUCTOR needs special treatment. */ + + if (TREE_CODE (exp) == CONSTRUCTOR && ! TREE_LITERAL (exp)) + { + store_constructor (exp, target); + return target; + } + + if (suggest_reg && GET_CODE (target) == MEM && 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, SUGGEST_REG will be nonzero for it. + We know expand_expr will not use the target in that case. */ + { + temp = expand_expr (exp, cse_not_expected ? 0 : 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, it is not safe + to use as the returned value. It would access the wrong + place by the time the queued increment gets output. + So copy the value through a temporary and use that temp + as the result. */ + { + temp = expand_expr (exp, 0, GET_MODE (target), 0); + if (GET_MODE (temp) != BLKmode && GET_MODE (temp) != VOIDmode) + temp = copy_to_reg (temp); + dont_return_target = 1; + } + else + { + temp = expand_expr (exp, target, GET_MODE (target), 0); + /* DO return TARGET if it's a specified hardware register. + expand_return relies on this. */ + if (!(target && GET_CODE (target) == REG + && REGNO (target) < FIRST_PSEUDO_REGISTER) + && (CONSTANT_P (temp) || GET_CODE (temp) == CONST_DOUBLE)) + dont_return_target = 1; + } + + /* 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) + { + target = protect_from_queue (target, 1); + if (GET_MODE (temp) != GET_MODE (target) + && GET_MODE (temp) != VOIDmode) + { + int unsignedp = TREE_UNSIGNED (TREE_TYPE (exp)); + if (dont_return_target) + { + /* In this case, we will return TEMP, + so make sure it has the proper mode. + But don't forget to store the value into TARGET. */ + temp = convert_to_mode (GET_MODE (target), temp, unsignedp); + emit_move_insn (target, temp); + } + else + convert_move (target, temp, unsignedp); + } + + else if (GET_MODE (temp) == BLKmode) + emit_block_move (target, temp, expr_size (exp), + TYPE_ALIGN (TREE_TYPE (exp)) / BITS_PER_UNIT); + else + emit_move_insn (target, temp); + } + if (dont_return_target) + return temp; + return target; +} + +/* Store the value of constructor EXP into the rtx TARGET. + TARGET is either a REG or a MEM. */ + +static void +store_constructor (exp, target) + tree exp; + rtx target; +{ + /* Don't try copying piece by piece into a hard register + since that is vulnerable to being clobbered by EXP. + Instead, construct in a pseudo register and then copy it all. */ + if (GET_CODE (target) == REG && REGNO (target) < FIRST_PSEUDO_REGISTER) + { + rtx temp = gen_reg_rtx (GET_MODE (target)); + store_constructor (exp, temp); + emit_move_insn (target, temp); + return; + } + + if (TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE) + { + register tree elt; + + /* If the constructor has fewer fields than the structure, + clear the whole structure first. */ + + if (list_length (CONSTRUCTOR_ELTS (exp)) + != list_length (TYPE_FIELDS (TREE_TYPE (exp)))) + clear_storage (target, int_size_in_bytes (TREE_TYPE (exp))); + else + /* Inform later passes that the old value is dead. */ + emit_insn (gen_rtx (CLOBBER, VOIDmode, target)); + + /* Store each element of the constructor into + the corresponding field of TARGET. */ + + for (elt = CONSTRUCTOR_ELTS (exp); 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 = DECL_OFFSET (field); + + store_field (target, bitsize, bitpos, mode, TREE_VALUE (elt), + /* The alignment of TARGET is + at least what its type requires. */ + VOIDmode, 0, + TYPE_ALIGN (TREE_TYPE (exp)) / BITS_PER_UNIT, + int_size_in_bytes (TREE_TYPE (exp))); + } + } + else if (TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE) + { + register tree elt; + register int i; + tree domain = TYPE_DOMAIN (TREE_TYPE (exp)); + 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 (exp)); + + /* If the constructor has fewer fields than the structure, + clear the whole structure first. */ + + if (list_length (CONSTRUCTOR_ELTS (exp)) < maxelt - minelt + 1) + clear_storage (target, maxelt - minelt + 1); + else + /* Inform later passes that the old value is dead. */ + emit_insn (gen_rtx (CLOBBER, VOIDmode, target)); + + /* Store each element of the constructor into + the corresponding element of TARGET, determined + by counting the elements. */ + for (elt = CONSTRUCTOR_ELTS (exp), 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)); + + store_field (target, bitsize, bitpos, mode, TREE_VALUE (elt), + /* The alignment of TARGET is + at least what its type requires. */ + VOIDmode, 0, + TYPE_ALIGN (TREE_TYPE (exp)) / BITS_PER_UNIT, + int_size_in_bytes (TREE_TYPE (exp))); + } + } +} + +/* Store the value of EXP (an expression tree) + into a subfield of TARGET which has mode MODE and occupies + BITSIZE bits, starting BITPOS bits from the start of TARGET. + + If VALUE_MODE is VOIDmode, return nothing in particular. + UNSIGNEDP is not used in this case. + + Otherwise, return an rtx for the value stored. This rtx + has mode VALUE_MODE if that is convenient to do. + In this case, UNSIGNEDP must be nonzero if the value is an unsigned type. + + ALIGN is the alignment that TARGET is known to have, measured in bytes. + TOTAL_SIZE is its size in bytes, or -1 if variable. */ + +static rtx +store_field (target, bitsize, bitpos, mode, exp, value_mode, unsignedp, align, + total_size) + rtx target; + int bitsize, bitpos; + enum machine_mode mode; + tree exp; + enum machine_mode value_mode; + int unsignedp; + int align; + int total_size; +{ + /* If the structure is in a register or if the component + is a bit field, we cannot use addressing to access it. + Use bit-field techniques or SUBREG to store in it. */ + + if (mode == BImode || GET_CODE (target) == REG + || GET_CODE (target) == SUBREG) + { + store_bit_field (target, bitsize, bitpos, + mode, + expand_expr (exp, 0, VOIDmode, 0), + align, total_size); + if (value_mode != VOIDmode) + return extract_bit_field (target, bitsize, bitpos, unsignedp, + 0, value_mode, 0, align, total_size); + return const0_rtx; + } + else + { + rtx addr = XEXP (target, 0); + rtx to_rtx; + + /* If a value is wanted, it must be the lhs; + so make the address stable for multiple use. */ + + if (value_mode != VOIDmode && GET_CODE (addr) != REG + && ! CONSTANT_ADDRESS_P (addr)) + addr = copy_to_reg (addr); + + /* Now build a reference to just the desired component. */ + + to_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); + } +} + +/* Given an rtx VALUE that may contain additions and multiplications, + return an equivalent value that just refers to a register or memory. + This is done by generating instructions to perform the arithmetic + and returning a pseudo-register containing the value. */ + +rtx +force_operand (value, target) + rtx value, target; +{ + register optab binoptab = 0; + register rtx op2; + /* Use subtarget as the target for operand 0 of a binary operation. */ + register rtx subtarget = (target != 0 && GET_CODE (target) == REG ? target : 0); + + if (GET_CODE (value) == PLUS) + binoptab = add_optab; + else if (GET_CODE (value) == MINUS) + binoptab = sub_optab; + else if (GET_CODE (value) == MULT) + { + op2 = XEXP (value, 1); + if (!CONSTANT_P (op2) + && !(GET_CODE (op2) == REG && op2 != subtarget)) + subtarget = 0; + return expand_mult (GET_MODE (value), + force_operand (XEXP (value, 0), subtarget), + force_operand (op2, 0), + target, 0); + } + + if (binoptab) + { + op2 = XEXP (value, 1); + if (!CONSTANT_P (op2) + && !(GET_CODE (op2) == REG && op2 != subtarget)) + subtarget = 0; + if (binoptab == sub_optab + && GET_CODE (op2) == CONST_INT && INTVAL (op2) < 0) + { + binoptab = add_optab; + op2 = gen_rtx (CONST_INT, VOIDmode, - INTVAL (op2)); + } + return expand_binop (GET_MODE (value), binoptab, + force_operand (XEXP (value, 0), subtarget), + force_operand (op2, 0), + target, 0, OPTAB_LIB_WIDEN); + /* We give UNSIGNEP = 0 to expand_binop + because the only operations we are expanding here are signed ones. */ + } + return value; +} + +/* expand_expr: generate code for computing expression EXP. + An rtx for the computed value is returned. The value is never null. + In the case of a void EXP, const0_rtx is returned. + + The value may be stored in TARGET if TARGET is nonzero. + TARGET is just a suggestion; callers must assume that + the rtx returned may not be the same as TARGET. + + If TARGET is CONST0_RTX, it means that the value will be ignored. + + If TMODE is not VOIDmode, it suggests generating the + result in mode TMODE. But this is done only when convenient. + Otherwise, TMODE is ignored and the value generated in its natural mode. + TMODE is just a suggestion; callers must assume that + the rtx returned may not have mode TMODE. + + If MODIFIER is EXPAND_SUM then when EXP is an addition + we can return an rtx of the form (MULT (REG ...) (CONST_INT ...)) + or a nest of (PLUS ...) and (MINUS ...) where the terms are + products as above, or REG or MEM, or constant. + Ordinarily in such cases we would output mul or add instructions + and then return a pseudo reg containing the sum. + + If MODIFIER is EXPAND_CONST_ADDRESS then it is ok to return + a MEM rtx whose address is a constant that isn't a legitimate address. */ + +/* Subroutine of expand_expr: + save the non-copied parts (LIST) of an expr (LHS), and return a list + which can restore these values to their previous values, + should something modify their storage. */ +static tree +save_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, save_noncopied_parts (TREE_VALUE (tail))); + else + { + tree part = TREE_VALUE (tail); + tree part_type = TREE_TYPE (part); + parts = tree_cons (save_expr (build_component_ref (lhs, part, parts, 0)), + build_nt (RTL_EXPR, 0, (tree) assign_stack_local (TYPE_MODE (part_type), int_size_in_bytes (part_type))), + parts); + store_expr (TREE_PURPOSE (parts), RTL_EXPR_RTL (TREE_VALUE (parts)), 0); + } + return parts; +} + +/* Subroutine of expand_expr: + return the target to use when recursively expanding + the first operand of an arithmetic operation. */ + +static rtx +validate_subtarget (subtarget, otherop) + rtx subtarget; + tree otherop; +{ + if (TREE_LITERAL (otherop)) + return subtarget; + if (TREE_CODE (otherop) == VAR_DECL + && DECL_RTL (otherop) != subtarget) + return subtarget; + return 0; +} + +rtx +expand_expr (exp, target, tmode, modifier) + register tree exp; + rtx target; + enum machine_mode tmode; + enum expand_modifier modifier; +{ + register rtx op0, op1, temp; + tree type = TREE_TYPE (exp); + register enum machine_mode mode = TYPE_MODE (type); + register enum tree_code code = TREE_CODE (exp); + optab this_optab; + int negate_1; + /* 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; + int ignore = target == const0_rtx; + + /* Don't use hard regs as subtargets, because the combiner + can only handle pseudo regs. */ + if (subtarget && REGNO (subtarget) < FIRST_PSEUDO_REGISTER) + subtarget = 0; + /* Avoid subtargets inside loops, + since they hide some invariant expressions. */ + if (optimize && inside_loop ()) + subtarget = 0; + + if (ignore) target = 0, original_target = 0; + + /* If will do cse, generate all results into registers + since 1) that allows cse to find more things + and 2) otherwise cse could produce an insn the machine + cannot support. */ + + if (! cse_not_expected && mode != BLKmode) + target = subtarget; + + /* No sense saving up arithmetic to be done + if it's all in the wrong mode to form part of an address. + And force_operand won't know whether to sign-extend or zero-extend. */ + + if (mode != Pmode && modifier == EXPAND_SUM) + modifier = EXPAND_NORMAL; + + /* Ensure we reference a volatile object even if value is ignored. */ + if (ignore && TREE_THIS_VOLATILE (exp) + && mode != VOIDmode && mode != BLKmode) + { + target = gen_reg_rtx (mode); + temp = expand_expr (exp, target, VOIDmode, modifier); + if (temp != target) + emit_move_insn (target, temp); + return target; + } + + switch (code) + { + case PARM_DECL: + if (DECL_RTL (exp) == 0) + { + error_with_decl (exp, "prior parameter's size depends on `%s'"); + return const0_rtx; + } + + case FUNCTION_DECL: + case VAR_DECL: + case RESULT_DECL: + if (DECL_RTL (exp) == 0) + abort (); + /* 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)), + XEXP (DECL_RTL (exp), 0)); + if (GET_CODE (DECL_RTL (exp)) == MEM + && modifier != EXPAND_CONST_ADDRESS) + { + /* DECL_RTL probably contains a constant address. + On RISC machines where a constant address isn't valid, + make some insns to get that address into a register. */ + if (!memory_address_p (DECL_MODE (exp), XEXP (DECL_RTL (exp), 0)) + || (flag_force_addr + && CONSTANT_ADDRESS_P (XEXP (DECL_RTL (exp), 0)))) + return change_address (DECL_RTL (exp), VOIDmode, + copy_rtx (XEXP (DECL_RTL (exp), 0))); + } + return DECL_RTL (exp); + + case INTEGER_CST: + if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_INT) + return gen_rtx (CONST_INT, VOIDmode, TREE_INT_CST_LOW (exp)); + /* Generate immediate CONST_DOUBLE + which will be turned into memory by reload if necessary. */ + return immed_double_const (TREE_INT_CST_LOW (exp), + TREE_INT_CST_HIGH (exp), + mode); + + case CONST_DECL: + return expand_expr (DECL_INITIAL (exp), target, VOIDmode, 0); + + case REAL_CST: + /* If optimized, generate immediate CONST_DOUBLE + which will be turned into memory by reload if necessary. */ + if (!cse_not_expected) + return immed_real_const (exp); + case COMPLEX_CST: + case STRING_CST: + if (! TREE_CST_RTL (exp)) + output_constant_def (exp); + + /* TREE_CST_RTL probably contains a constant address. + On RISC machines where a constant address isn't valid, + make some insns to get that address into a register. */ + if (GET_CODE (TREE_CST_RTL (exp)) == MEM + && modifier != EXPAND_CONST_ADDRESS + && !memory_address_p (mode, XEXP (TREE_CST_RTL (exp), 0))) + return change_address (TREE_CST_RTL (exp), VOIDmode, + copy_rtx (XEXP (TREE_CST_RTL (exp), 0))); + return TREE_CST_RTL (exp); + + case SAVE_EXPR: + if (SAVE_EXPR_RTL (exp) == 0) + { + rtx reg = gen_reg_rtx (mode); + SAVE_EXPR_RTL (exp) = reg; + store_expr (TREE_OPERAND (exp, 0), reg, 0); + if (!optimize) + save_expr_regs = gen_rtx (EXPR_LIST, VOIDmode, reg, + save_expr_regs); + } + /* Don't let the same rtl node appear in two places. */ + return SAVE_EXPR_RTL (exp); + + case LET_STMT: + TREE_USED (exp) = 1; + temp = expand_expr (STMT_BODY (exp), target, tmode, modifier); + return temp; + + case RTL_EXPR: + if (RTL_EXPR_SEQUENCE (exp) == const0_rtx) + abort (); + emit_insns (RTL_EXPR_SEQUENCE (exp)); + RTL_EXPR_SEQUENCE (exp) = const0_rtx; + return RTL_EXPR_RTL (exp); + + case CONSTRUCTOR: + /* All elts simple constants => refer to a constant in memory. */ + if (TREE_STATIC (exp)) + /* For aggregate types with non-BLKmode modes, + this should ideally construct a CONST_INT. */ + { + rtx constructor = output_constant_def (exp); + if (! memory_address_p (GET_MODE (constructor), + XEXP (constructor, 0))) + constructor = change_address (constructor, VOIDmode, + XEXP (constructor, 0)); + return constructor; + } + + if (ignore) + { + tree elt; + for (elt = CONSTRUCTOR_ELTS (exp); elt; elt = TREE_CHAIN (elt)) + expand_expr (TREE_VALUE (elt), const0_rtx, VOIDmode, 0); + return const0_rtx; + } + else + { + if (target == 0) + target + = assign_stack_local (TYPE_MODE (TREE_TYPE (exp)), + int_size_in_bytes (TREE_TYPE (exp))); + store_expr (exp, target, 0); + return target; + } + + case INDIRECT_REF: + { + 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 + && TREE_CODE (exp2 = TREE_OPERAND (exp1, 0)) != ERROR_MARK + && TYPE_MODE (TREE_TYPE (exp1)) == Pmode + && TYPE_MODE (TREE_TYPE (exp2)) == Pmode) + { + temp = expand_expr (TREE_OPERAND (exp1, 0), 0, VOIDmode, EXPAND_SUM); + op0 = memory_address (mode, temp); + op0 = copy_all_regs (op0); + SAVE_EXPR_RTL (exp1) = op0; + } + else + { + op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, EXPAND_SUM); + op0 = memory_address (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)) + MEM_IN_STRUCT_P (temp) = 1; + MEM_VOLATILE_P (temp) = TREE_THIS_VOLATILE (exp) || flag_volatile; + RTX_UNCHANGING_P (temp) = TREE_READONLY (exp); + return temp; + + case ARRAY_REF: + if (TREE_CODE (TREE_OPERAND (exp, 1)) != INTEGER_CST + || TREE_CODE (TYPE_SIZE (TREE_TYPE (exp))) != INTEGER_CST) + { + /* Nonconstant array index or nonconstant element size. + 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 = build (ADDR_EXPR, build_pointer_type (variant_type), + TREE_OPERAND (exp, 0)); + tree index = TREE_OPERAND (exp, 1); + tree elt; + + /* 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. */ + TREE_VOLATILE (array_adr) = 0; + + elt = build (INDIRECT_REF, type, + fold (build (PLUS_EXPR, TYPE_POINTER_TO (variant_type), + array_adr, + fold (build (MULT_EXPR, + TYPE_POINTER_TO (variant_type), + index, size_in_bytes (type)))))); + + 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 &. */ + { + int i; + tree arg0 = TREE_OPERAND (exp, 0); + tree arg1 = TREE_OPERAND (exp, 1); + + if (TREE_CODE (arg0) == STRING_CST + && TREE_CODE (arg1) == INTEGER_CST + && !TREE_INT_CST_HIGH (arg1) + && (i = TREE_INT_CST_LOW (arg1)) < TREE_STRING_LENGTH (arg0)) + { + if (TREE_TYPE (TREE_TYPE (arg0)) == integer_type_node) + { + exp = build_int_2 (((int *)TREE_STRING_POINTER (arg0))[i], 0); + TREE_TYPE (exp) = integer_type_node; + return expand_expr (exp, target, tmode, modifier); + } + if (TREE_TYPE (TREE_TYPE (arg0)) == char_type_node) + { + exp = build_int_2 (TREE_STRING_POINTER (arg0)[i], 0); + TREE_TYPE (exp) = integer_type_node; + return expand_expr (convert (TREE_TYPE (TREE_TYPE (arg0)), exp), target, tmode, modifier); + } + } + } + + /* If this is a constant index into a constant array, + just get the value from the array. */ + if (TREE_READONLY (TREE_OPERAND (exp, 0)) + && ! TREE_VOLATILE (TREE_OPERAND (exp, 0)) + && TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 0))) == ARRAY_TYPE + && TREE_LITERAL (TREE_OPERAND (exp, 1)) + && TREE_CODE (TREE_OPERAND (exp, 0)) == VAR_DECL + && DECL_INITIAL (TREE_OPERAND (exp, 0)) + && TREE_CODE (DECL_INITIAL (TREE_OPERAND (exp, 0))) != ERROR_MARK) + { + tree index = fold (TREE_OPERAND (exp, 1)); + if (TREE_CODE (index) == INTEGER_CST) + { + int i = TREE_INT_CST_LOW (index); + tree init = CONSTRUCTOR_ELTS (DECL_INITIAL (TREE_OPERAND (exp, 0))); + + while (init && i--) + init = TREE_CHAIN (init); + if (init) + return expand_expr (fold (TREE_VALUE (init)), target, tmode, modifier); + } + } + /* Treat array-ref with constant index as a component-ref. */ + + case COMPONENT_REF: + { + register enum machine_mode mode1; + int volstruct = 0; + int bitsize; + tree tem = exp; + int bitpos = 0; + int unsignedp; + + if (TREE_CODE (exp) == COMPONENT_REF) + { + tree field = TREE_OPERAND (exp, 1); + bitsize = TREE_INT_CST_LOW (DECL_SIZE (field)) * DECL_SIZE_UNIT (field); + mode1 = DECL_MODE (TREE_OPERAND (exp, 1)); + unsignedp = TREE_UNSIGNED (field); + } + else + { + mode1 = TYPE_MODE (TREE_TYPE (exp)); + bitsize = GET_MODE_BITSIZE (mode1); + unsignedp = TREE_UNSIGNED (TREE_TYPE (exp)); + } + + /* Compute cumulative bit-offset for nested component-refs + and array-refs, and find the ultimate containing object. */ + + while (1) + { + if (TREE_CODE (tem) == COMPONENT_REF) + { + bitpos += DECL_OFFSET (TREE_OPERAND (tem, 1)); + if (TREE_THIS_VOLATILE (tem)) + volstruct = 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))); + if (TREE_THIS_VOLATILE (tem)) + volstruct = 1; + } + else + break; + tem = TREE_OPERAND (tem, 0); + } + + op0 = expand_expr (tem, 0, VOIDmode, + (modifier == EXPAND_CONST_ADDRESS + ? modifier : EXPAND_NORMAL)); + + /* Don't forget about volatility even if this is a bitfield. */ + if (GET_CODE (op0) == MEM && volstruct && ! MEM_VOLATILE_P (op0)) + { + op0 = copy_rtx (op0); + MEM_VOLATILE_P (op0) = 1; + } + + if (mode1 == BImode || GET_CODE (op0) == REG + || GET_CODE (op0) == SUBREG) + return extract_bit_field (op0, bitsize, bitpos, unsignedp, + target, mode, tmode, + TYPE_ALIGN (TREE_TYPE (tem)) / BITS_PER_UNIT, + int_size_in_bytes (TREE_TYPE (tem))); + /* Get a reference to just this component. */ + if (modifier == EXPAND_CONST_ADDRESS) + 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))); + MEM_IN_STRUCT_P (op0) = 1; + MEM_VOLATILE_P (op0) |= volstruct; + /* If OP0 is in the shared structure-value stack slot, + and it is not BLKmode, copy it into a register. + The shared slot may be clobbered at any time by another call. + BLKmode is safe because our caller will either copy the value away + or take another component and come back here. */ + if (mode != BLKmode + && TREE_CODE (TREE_OPERAND (exp, 0)) == CALL_EXPR + && TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))) == BLKmode) + op0 = copy_to_reg (op0); + if (mode == mode1 || mode1 == BLKmode || mode1 == tmode) + return op0; + if (target == 0) + target = gen_reg_rtx (tmode != VOIDmode ? tmode : mode); + convert_move (target, op0, unsignedp); + return target; + } + + /* 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. */ + case BUFFER_REF: + abort (); + + case WITH_CLEANUP_EXPR: + RTL_EXPR_RTL (TREE_OPERAND (exp, 1)) + = expand_expr (TREE_OPERAND (exp, 0), target, tmode, modifier); + cleanups_of_this_call = tree_cons (0, TREE_OPERAND (exp, 2), cleanups_of_this_call); + return RTL_EXPR_RTL (TREE_OPERAND (exp, 1)); + + case CALL_EXPR: + /* Check for a built-in function. */ + if (TREE_CODE (TREE_OPERAND (exp, 0)) == ADDR_EXPR + && TREE_CODE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)) == FUNCTION_DECL + && (DECL_FUNCTION_CODE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)) + != NOT_BUILT_IN)) + return expand_builtin (exp, target, subtarget, tmode, ignore); + /* If this call was expanded already by preexpand_calls, + just return the result we got. */ + if (CALL_EXPR_RTL (exp) != 0) + return CALL_EXPR_RTL (exp); + return expand_call (exp, target, ignore); + + case NOP_EXPR: + case CONVERT_EXPR: + case REFERENCE_EXPR: + if (TREE_CODE (type) == VOID_TYPE || ignore) + { + expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode, modifier); + return const0_rtx; + } + if (mode == TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)))) + return expand_expr (TREE_OPERAND (exp, 0), target, VOIDmode, modifier); + op0 = expand_expr (TREE_OPERAND (exp, 0), 0, mode, 0); + if (GET_MODE (op0) == mode || GET_MODE (op0) == VOIDmode) + return op0; + if (flag_force_mem && GET_CODE (op0) == MEM) + op0 = copy_to_reg (op0); + if (GET_MODE (op0) == VOIDmode) + /* Avoid problem in convert_move due to unknown mode of OP0. */ + op0 = copy_to_mode_reg (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))), + op0); + if (target == 0) + target = gen_reg_rtx (mode); + convert_move (target, op0, TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0)))); + return target; + + case PLUS_EXPR: + preexpand_calls (exp); + if (TREE_CODE (TREE_OPERAND (exp, 0)) == INTEGER_CST + && modifier == EXPAND_SUM) + { + op1 = expand_expr (TREE_OPERAND (exp, 1), subtarget, VOIDmode, EXPAND_SUM); + op1 = plus_constant (op1, TREE_INT_CST_LOW (TREE_OPERAND (exp, 0))); + return op1; + } + negate_1 = 1; + plus_minus: + if (TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST + && modifier == EXPAND_SUM) + { + op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, EXPAND_SUM); + op0 = plus_constant (op0, + negate_1 * TREE_INT_CST_LOW (TREE_OPERAND (exp, 1))); + return op0; + } + this_optab = add_optab; + if (modifier != EXPAND_SUM) goto binop; + subtarget = validate_subtarget (subtarget, TREE_OPERAND (exp, 1)); + op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, EXPAND_SUM); + op1 = expand_expr (TREE_OPERAND (exp, 1), 0, VOIDmode, EXPAND_SUM); + /* Put a sum last, to simplify what follows. */ +#ifdef OLD_INDEXING + if (GET_CODE (op1) == MULT) + { + temp = op0; + op0 = op1; + op1 = temp; + } +#endif +#ifndef OLD_INDEXING + /* Make sure any term that's a sum with a constant comes last. */ + if (GET_CODE (op0) == PLUS + && CONSTANT_P (XEXP (op0, 1))) + { + temp = op0; + op0 = op1; + op1 = temp; + } + /* If adding to a sum including a constant, + associate it to put the constant outside. */ + if (GET_CODE (op1) == PLUS + && CONSTANT_P (XEXP (op1, 1))) + { + rtx tem; + int constant_term = 0; + + op0 = gen_rtx (PLUS, mode, XEXP (op1, 0), op0); + /* Let's also eliminate constants from op0 if possible. */ + tem = eliminate_constant_term (op0, &constant_term); + if (GET_CODE (XEXP (op1, 1)) == CONST_INT) + { + if (constant_term != 0) + return plus_constant (tem, INTVAL (XEXP (op1, 1)) + constant_term); + else + return plus_constant (op0, INTVAL (XEXP (op1, 1))); + } + else + return gen_rtx (PLUS, mode, op0, XEXP (op1, 1)); + } +#endif + return gen_rtx (PLUS, mode, op0, op1); + + case MINUS_EXPR: + preexpand_calls (exp); + if (TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST + && GET_MODE_BITSIZE (TYPE_MODE (type)) <= HOST_BITS_PER_INT) + { + int negated; + if (modifier == EXPAND_SUM) + { + negate_1 = -1; + goto plus_minus; + } + subtarget = validate_subtarget (subtarget, TREE_OPERAND (exp, 1)); + op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0); + negated = - TREE_INT_CST_LOW (TREE_OPERAND (exp, 1)); + if (GET_MODE_BITSIZE (mode) < HOST_BITS_PER_INT) + negated &= (1 << GET_MODE_BITSIZE (mode)) - 1; + op1 = gen_rtx (CONST_INT, VOIDmode, negated); + this_optab = add_optab; + goto binop2; + } + this_optab = sub_optab; + goto binop; + + case MULT_EXPR: + preexpand_calls (exp); + /* If first operand is constant, swap them. + Thus the following special case checks need only + check the second operand. */ + if (TREE_CODE (TREE_OPERAND (exp, 0)) == INTEGER_CST) + { + register tree t1 = TREE_OPERAND (exp, 0); + TREE_OPERAND (exp, 0) = TREE_OPERAND (exp, 1); + TREE_OPERAND (exp, 1) = t1; + } + + /* Attempt to return something suitable for generating an + indexed address, for machines that support that. */ + + if (modifier == EXPAND_SUM + && TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST) + { + 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_rtx (CONST_INT, VOIDmode, + TREE_INT_CST_LOW (TREE_OPERAND (exp, 1)))), + gen_rtx (CONST_INT, VOIDmode, + (TREE_INT_CST_LOW (TREE_OPERAND (exp, 1)) + * INTVAL (XEXP (op0, 1))))); + + if (GET_CODE (op0) != REG) + op0 = force_operand (op0, 0); + if (GET_CODE (op0) != REG) + op0 = copy_to_mode_reg (mode, op0); + + return gen_rtx (MULT, mode, op0, + gen_rtx (CONST_INT, VOIDmode, + TREE_INT_CST_LOW (TREE_OPERAND (exp, 1)))); + } + subtarget = validate_subtarget (subtarget, TREE_OPERAND (exp, 1)); + /* Check for multiplying things that have been extended + from a narrower type. If this machine supports multiplying + in that narrower type with a result in the desired type, + do it that way, and avoid the explicit type-conversion. */ + if (TREE_CODE (TREE_OPERAND (exp, 0)) == NOP_EXPR + && TREE_CODE (TREE_TYPE (exp)) == INTEGER_TYPE + && (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0))) + < TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (exp, 0)))) + && ((TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST + && int_fits_type_p (TREE_OPERAND (exp, 1), + TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0))) + /* Don't use a widening multiply if a shift will do. */ + && exact_log2 (TREE_INT_CST_LOW (TREE_OPERAND (exp, 1))) < 0) + || + (TREE_CODE (TREE_OPERAND (exp, 1)) == NOP_EXPR + && (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 1), 0))) + == + TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)))) + /* If both operands are extended, they must either both + be zero-extended or both be sign-extended. */ + && (TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 1), 0))) + == + TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0))))))) + { + enum machine_mode innermode + = TYPE_MODE (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0))); + 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) + { + op0 = expand_expr (TREE_OPERAND (TREE_OPERAND (exp, 0), 0), + 0, VOIDmode, 0); + if (TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST) + op1 = expand_expr (TREE_OPERAND (exp, 1), 0, VOIDmode, 0); + else + op1 = expand_expr (TREE_OPERAND (TREE_OPERAND (exp, 1), 0), + 0, VOIDmode, 0); + goto binop2; + } + } + op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0); + op1 = expand_expr (TREE_OPERAND (exp, 1), 0, VOIDmode, 0); + return expand_mult (mode, op0, op1, target, TREE_UNSIGNED (type)); + + case TRUNC_DIV_EXPR: + case FLOOR_DIV_EXPR: + case CEIL_DIV_EXPR: + case ROUND_DIV_EXPR: + case EXACT_DIV_EXPR: + preexpand_calls (exp); + subtarget = validate_subtarget (subtarget, TREE_OPERAND (exp, 1)); + /* Possible optimization: compute the dividend with EXPAND_SUM + then if the divisor is constant can optimize the case + where some terms of the dividend have coeffs divisible by it. */ + op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0); + op1 = expand_expr (TREE_OPERAND (exp, 1), 0, VOIDmode, 0); + return expand_divmod (0, code, mode, op0, op1, target, + TREE_UNSIGNED (type)); + + case RDIV_EXPR: + preexpand_calls (exp); + this_optab = flodiv_optab; + goto binop; + + case TRUNC_MOD_EXPR: + case FLOOR_MOD_EXPR: + case CEIL_MOD_EXPR: + case ROUND_MOD_EXPR: + preexpand_calls (exp); + subtarget = validate_subtarget (subtarget, TREE_OPERAND (exp, 1)); + op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0); + op1 = expand_expr (TREE_OPERAND (exp, 1), 0, VOIDmode, 0); + return expand_divmod (1, code, mode, op0, op1, target, + TREE_UNSIGNED (type)); +#if 0 +#ifdef HAVE_divmoddisi4 + if (GET_MODE (op0) != DImode) + { + temp = gen_reg_rtx (DImode); + convert_move (temp, op0, 0); + op0 = temp; + if (GET_MODE (op1) != SImode && GET_CODE (op1) != CONST_INT) + { + temp = gen_reg_rtx (SImode); + convert_move (temp, op1, 0); + op1 = temp; + } + temp = gen_reg_rtx (SImode); + if (target == 0) + target = gen_reg_rtx (SImode); + emit_insn (gen_divmoddisi4 (temp, protect_from_queue (op0, 0), + protect_from_queue (op1, 0), + protect_from_queue (target, 1))); + return target; + } +#endif +#endif + + case FIX_ROUND_EXPR: + case FIX_FLOOR_EXPR: + case FIX_CEIL_EXPR: + abort (); /* Not used for C. */ + + case FIX_TRUNC_EXPR: + op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0); + if (target == 0) + target = gen_reg_rtx (mode); + { + int unsignedp = TREE_UNSIGNED (TREE_TYPE (exp)); + if (mode == HImode || mode == QImode) + { + register rtx temp = gen_reg_rtx (SImode); + expand_fix (temp, op0, 0); + convert_move (target, temp, 0); + } + else + expand_fix (target, op0, unsignedp); + } + return target; + + case FLOAT_EXPR: + op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0); + if (target == 0) + target = gen_reg_rtx (mode); + if (GET_MODE (op0) == VOIDmode) + /* Avoid problem in convert_move due to unknown mode of OP0. */ + op0 = copy_to_mode_reg (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))), + op0); + { + int unsignedp = TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0))); + if (GET_MODE (op0) == HImode + || GET_MODE (op0) == QImode) + { + register rtx temp = gen_reg_rtx (SImode); + convert_move (temp, op0, unsignedp); + expand_float (target, temp, 0); + } + else + expand_float (target, op0, unsignedp); + } + return target; + + case NEGATE_EXPR: + op0 = expand_expr (TREE_OPERAND (exp, 0), target, VOIDmode, 0); + temp = expand_unop (mode, neg_optab, op0, target, 0); + if (temp == 0) + abort (); + return temp; + + case ABS_EXPR: + /* First try to do it with a special abs instruction. + If that does not win, use conditional jump and negate. */ + op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0); + temp = expand_unop (mode, abs_optab, op0, target, 0); + if (temp != 0) + return temp; + temp = gen_label_rtx (); + if (target == 0 || GET_CODE (target) != REG) + target = gen_reg_rtx (mode); + emit_move_insn (target, op0); + emit_cmp_insn (target, + expand_expr (convert (TREE_TYPE (exp), integer_zero_node), + 0, VOIDmode, 0), + 0, 0, 0); + NO_DEFER_POP; + emit_jump_insn (gen_bge (temp)); + op0 = expand_unop (mode, neg_optab, target, target, 0); + if (op0 != target) + emit_move_insn (target, op0); + emit_label (temp); + OK_DEFER_POP; + return target; + + case MAX_EXPR: + case MIN_EXPR: + mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 1))); + op1 = expand_expr (TREE_OPERAND (exp, 1), 0, VOIDmode, 0); + if (target == 0 || GET_CODE (target) != REG || target == op1) + target = gen_reg_rtx (mode); + op0 = expand_expr (TREE_OPERAND (exp, 0), target, VOIDmode, 0); + if (target != op0) + emit_move_insn (target, op0); + op0 = gen_label_rtx (); + if (code == MAX_EXPR) + temp = (TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 1))) + ? compare1 (target, op1, GEU, LEU, 1, mode) + : compare1 (target, op1, GE, LE, 0, mode)); + else + temp = (TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 1))) + ? compare1 (target, op1, LEU, GEU, 1, mode) + : compare1 (target, op1, LE, GE, 0, mode)); + if (temp == const0_rtx) + emit_move_insn (target, op1); + else if (temp != const1_rtx) + { + if (bcc_gen_fctn[(int) GET_CODE (temp)] != 0) + emit_jump_insn ((*bcc_gen_fctn[(int) GET_CODE (temp)]) (op0)); + else + abort (); + emit_move_insn (target, op1); + } + emit_label (op0); + return target; + +/* ??? Can optimize when the operand of this is a bitwise operation, + by using a different bitwise operation. */ + case BIT_NOT_EXPR: + op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0); + temp = expand_unop (mode, one_cmpl_optab, op0, target, 1); + if (temp == 0) + abort (); + return temp; + + case FFS_EXPR: + op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0); + temp = expand_unop (mode, ffs_optab, op0, target, 1); + if (temp == 0) + abort (); + return temp; + +/* ??? Can optimize bitwise operations with one arg constant. + Pastel optimizes (a bitwise1 n) bitwise2 (a bitwise3 b) + and (a bitwise1 b) bitwise2 b (etc) + but that is probably not worth while. */ + +/* BIT_AND_EXPR is for bitwise anding. + TRUTH_AND_EXPR is for anding two boolean values + when we want in all cases to compute both of them. + In general it is fastest to do TRUTH_AND_EXPR by + computing both operands as actual zero-or-1 values + and then bitwise anding. In cases where there cannot + be any side effects, better code would be made by + treating TRUTH_AND_EXPR like TRUTH_ANDIF_EXPR; + but the question is how to recognize those cases. */ + + case TRUTH_AND_EXPR: + case BIT_AND_EXPR: + preexpand_calls (exp); + subtarget = validate_subtarget (subtarget, TREE_OPERAND (exp, 1)); + op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0); + op1 = expand_expr (TREE_OPERAND (exp, 1), 0, VOIDmode, 0); + return expand_bit_and (mode, op0, op1, target); + +/* See comment above about TRUTH_AND_EXPR; it applies here too. */ + case TRUTH_OR_EXPR: + case BIT_IOR_EXPR: + preexpand_calls (exp); + this_optab = ior_optab; + goto binop; + + case BIT_XOR_EXPR: + preexpand_calls (exp); + this_optab = xor_optab; + goto binop; + + case LSHIFT_EXPR: + case RSHIFT_EXPR: + case LROTATE_EXPR: + case RROTATE_EXPR: + preexpand_calls (exp); + subtarget = validate_subtarget (subtarget, TREE_OPERAND (exp, 1)); + op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0); + return expand_shift (code, mode, op0, TREE_OPERAND (exp, 1), target, + TREE_UNSIGNED (type)); + +/* ??? cv's were used to effect here to combine additive constants + and to determine the answer when only additive constants differ. + Also, the addition of one can be handled by changing the condition. */ + case LT_EXPR: + case LE_EXPR: + case GT_EXPR: + case GE_EXPR: + case EQ_EXPR: + case NE_EXPR: + preexpand_calls (exp); + temp = do_store_flag (exp, target, mode); + if (temp != 0) + return temp; + /* For foo != 0, load foo, and if it is nonzero load 1 instead. */ + if (code == NE_EXPR && integer_zerop (TREE_OPERAND (exp, 1)) + && subtarget + && (GET_MODE (subtarget) + == TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))))) + { + temp = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0); + if (temp != subtarget) + temp = copy_to_reg (temp); + op1 = gen_label_rtx (); + emit_cmp_insn (temp, const0_rtx, 0, TREE_UNSIGNED (type), 0); + emit_jump_insn (gen_beq (op1)); + emit_move_insn (temp, const1_rtx); + emit_label (op1); + return temp; + } + /* If no set-flag instruction, must generate a conditional + store into a temporary variable. Drop through + and handle this like && and ||. */ + + case TRUTH_ANDIF_EXPR: + case TRUTH_ORIF_EXPR: + temp = gen_reg_rtx (mode); + emit_clr_insn (temp); + op1 = gen_label_rtx (); + jumpifnot (exp, op1); + emit_0_to_1_insn (temp); + emit_label (op1); + return temp; + + case TRUTH_NOT_EXPR: + op0 = expand_expr (TREE_OPERAND (exp, 0), target, VOIDmode, 0); + /* The parser is careful to generate TRUTH_NOT_EXPR + only with operands that are always zero or one. */ + temp = expand_binop (mode, xor_optab, op0, + gen_rtx (CONST_INT, mode, 1), + target, 1, OPTAB_LIB_WIDEN); + if (temp == 0) + abort (); + return temp; + + case COMPOUND_EXPR: + expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode, 0); + emit_queue (); + return expand_expr (TREE_OPERAND (exp, 1), target, VOIDmode, 0); + + case COND_EXPR: + /* 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 + for side effect only. If type is void, we must do likewise. */ + op0 = gen_label_rtx (); + op1 = gen_label_rtx (); + + if (mode == VOIDmode || ignore) + temp = 0; + else if (target) + temp = target; + else if (mode == BLKmode) + { + if (TYPE_SIZE (type) == 0 || ! TREE_LITERAL (TYPE_SIZE (type))) + abort (); + temp = assign_stack_local (BLKmode, + (TREE_INT_CST_LOW (TYPE_SIZE (type)) + * TYPE_SIZE_UNIT (type) + + BITS_PER_UNIT - 1) + / BITS_PER_UNIT); + } + else + temp = gen_reg_rtx (mode); + + jumpifnot (TREE_OPERAND (exp, 0), op0); + NO_DEFER_POP; + if (temp != 0) + store_expr (TREE_OPERAND (exp, 1), temp, 0); + else + expand_expr (TREE_OPERAND (exp, 1), ignore ? const0_rtx : 0, + VOIDmode, 0); + emit_queue (); + emit_jump_insn (gen_jump (op1)); + emit_barrier (); + emit_label (op0); + if (temp != 0) + store_expr (TREE_OPERAND (exp, 2), temp, 0); + else + expand_expr (TREE_OPERAND (exp, 2), ignore ? const0_rtx : 0, + VOIDmode, 0); + emit_queue (); + emit_label (op1); + OK_DEFER_POP; + return temp; + + case MODIFY_EXPR: + { + /* If lhs is complex, expand calls in rhs before computing it. + That's so we don't compute a pointer and save it over a call. + If lhs is simple, compute it first so we can give it as a + target if the rhs is just a call. This avoids an extra temp and copy + and that prevents a partial-subsumption which makes bad code. + Actually we could treat component_ref's of vars like vars. */ + + tree lhs = TREE_OPERAND (exp, 0); + tree rhs = TREE_OPERAND (exp, 1); + tree noncopied_parts; + + if (TREE_CODE (lhs) != VAR_DECL + && TREE_CODE (lhs) != RESULT_DECL + && TREE_CODE (lhs) != PARM_DECL) + preexpand_calls (exp); + + noncopied_parts = save_noncopied_parts (lhs, TYPE_NONCOPIED_PARTS (TREE_TYPE (lhs))); + temp = expand_assignment (lhs, rhs, ! ignore, original_target != 0); + while (noncopied_parts != 0) + { + store_expr (TREE_VALUE (noncopied_parts), + SAVE_EXPR_RTL (TREE_PURPOSE (noncopied_parts)), 0); + noncopied_parts = TREE_CHAIN (noncopied_parts); + } + return temp; + } + + case PREINCREMENT_EXPR: + case PREDECREMENT_EXPR: + return expand_increment (exp, 0); + + case POSTINCREMENT_EXPR: + case POSTDECREMENT_EXPR: + return expand_increment (exp, 1); + + case ADDR_EXPR: + op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, + EXPAND_CONST_ADDRESS); + if (GET_CODE (op0) != MEM) + abort (); + if (modifier == EXPAND_SUM) + return XEXP (op0, 0); + op0 = force_operand (XEXP (op0, 0), target); + if (flag_force_addr && GET_CODE (op0) != REG) + return force_reg (Pmode, op0); + return op0; + + case ENTRY_VALUE_EXPR: + abort (); + + case ERROR_MARK: + return const0_rtx; + + default: + abort (); + } + + /* Here to do an ordinary binary operator, generating an instruction + from the optab already placed in `this_optab'. */ + binop: + /* Detect things like x = y | (a == b) + and do them as (x = y), (a == b ? x |= 1 : 0), x. */ + /* First, get the comparison or conditional into the second arg. */ + if (comparison_code[(int) TREE_CODE (TREE_OPERAND (exp, 0))] + || (TREE_CODE (TREE_OPERAND (exp, 0)) == COND_EXPR + && (integer_zerop (TREE_OPERAND (TREE_OPERAND (exp, 0), 1)) + || integer_zerop (TREE_OPERAND (TREE_OPERAND (exp, 0), 2))))) + { + if (this_optab == ior_optab || this_optab == add_optab + || this_optab == xor_optab) + { + tree exch = TREE_OPERAND (exp, 1); + TREE_OPERAND (exp, 1) = TREE_OPERAND (exp, 0); + TREE_OPERAND (exp, 0) = exch; + } + } + /* Optimize X + (Y ? Z : 0) by computing X and maybe adding Z. */ + if (comparison_code[(int) TREE_CODE (TREE_OPERAND (exp, 1))] + || (TREE_CODE (TREE_OPERAND (exp, 1)) == COND_EXPR + && (integer_zerop (TREE_OPERAND (TREE_OPERAND (exp, 1), 1)) + || integer_zerop (TREE_OPERAND (TREE_OPERAND (exp, 1), 2))))) + { + if (this_optab == ior_optab || this_optab == add_optab + || this_optab == xor_optab || this_optab == sub_optab + || this_optab == lshl_optab || this_optab == ashl_optab + || this_optab == lshr_optab || this_optab == ashr_optab + || this_optab == rotl_optab || this_optab == rotr_optab) + { + tree thenexp; + rtx thenv = 0; + + /* TARGET gets a reg in which we can perform the computation. + Use the specified target if it's a pseudo reg and safe. */ + target = validate_subtarget (subtarget, TREE_OPERAND (exp, 1)); + if (target == 0) target = gen_reg_rtx (mode); + + /* Compute X into the target. */ + store_expr (TREE_OPERAND (exp, 0), target, 0); + op0 = gen_label_rtx (); + + /* If other operand is a comparison COMP, treat it as COMP ? 1 : 0 */ + if (TREE_CODE (TREE_OPERAND (exp, 1)) != COND_EXPR) + { + do_jump (TREE_OPERAND (exp, 1), op0, 0); + thenv = const1_rtx; + } + else if (integer_zerop (TREE_OPERAND (TREE_OPERAND (exp, 1), 2))) + { + do_jump (TREE_OPERAND (TREE_OPERAND (exp, 1), 0), op0, 0); + thenexp = TREE_OPERAND (TREE_OPERAND (exp, 1), 1); + } + else + { + do_jump (TREE_OPERAND (TREE_OPERAND (exp, 1), 0), 0, op0); + thenexp = TREE_OPERAND (TREE_OPERAND (exp, 1), 2); + } + + if (thenv == 0) + thenv = expand_expr (thenexp, 0, VOIDmode, 0); + + /* THENV is now Z, the value to operate on, as an rtx. + We have already tested that Y isn't zero, so do the operation. */ + + if (this_optab == rotl_optab || this_optab == rotr_optab) + temp = expand_binop (mode, this_optab, target, thenv, target, + -1, OPTAB_LIB); + else if (this_optab == lshl_optab || this_optab == lshr_optab) + temp = expand_binop (mode, this_optab, target, thenv, target, + 1, OPTAB_LIB_WIDEN); + else + temp = expand_binop (mode, this_optab, target, thenv, target, + 0, OPTAB_LIB_WIDEN); + if (target != temp) + emit_move_insn (target, temp); + + emit_queue (); + do_pending_stack_adjust (); + emit_label (op0); + return target; + } + } + subtarget = validate_subtarget (subtarget, TREE_OPERAND (exp, 1)); + op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0); + op1 = expand_expr (TREE_OPERAND (exp, 1), 0, VOIDmode, 0); + binop2: + temp = expand_binop (mode, this_optab, op0, op1, target, + TREE_UNSIGNED (TREE_TYPE (exp)), OPTAB_LIB_WIDEN); + if (temp == 0) + abort (); + return temp; +} + +/* Expand an expression EXP that calls a built-in function, + with result going to TARGET if that's convenient + (and in mode MODE if that's convenient). + SUBTARGET may be used as the target for computing one of EXP's operands. + IGNORE is nonzero if the value is to be ignored. */ + +static rtx +expand_builtin (exp, target, subtarget, mode, ignore) + tree exp; + rtx target; + rtx subtarget; + enum machine_mode mode; + int ignore; +{ + tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0); + tree arglist = TREE_OPERAND (exp, 1); + rtx op0; + + switch (DECL_FUNCTION_CODE (fndecl)) + { + case BUILT_IN_ABS: + case BUILT_IN_LABS: + case BUILT_IN_FABS: + /* build_function_call changes these into ABS_EXPR. */ + abort (); + + case BUILT_IN_SAVEREGS: + if (saveregs_value != 0) + return saveregs_value; + { + /* When this function is called, it means that registers must be + saved on entry to this function. So we migrate the + call to the first insn of this function. */ + rtx last = get_last_insn (); + /* Now really call the function. `expand_call' does not call + expand_builtin, so there is no danger of infinite recursion here. */ + rtx temp = expand_call (exp, target, ignore); + reorder_insns (NEXT_INSN (last), get_last_insn (), get_insns ()); + saveregs_value = temp; + return temp; + } + + case BUILT_IN_NEXT_ARG: + { + tree fntype = TREE_TYPE (current_function_decl); + if (!(TYPE_ARG_TYPES (fntype) != 0 + && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype))) + != void_type_node))) + { + error ("`stdarg.h' facilities used, but function has fixed args"); + return const0_rtx; + } + } + + return expand_binop (Pmode, add_optab, + arg_pointer_rtx, current_function_arg_offset_rtx, + 0, 0, OPTAB_LIB_WIDEN); + + case BUILT_IN_CLASSIFY_TYPE: + if (arglist != 0) + { + tree type = TREE_TYPE (TREE_VALUE (arglist)); + enum tree_code code = TREE_CODE (type); + if (code == VOID_TYPE) + return gen_rtx (CONST_INT, VOIDmode, void_type_class); + if (code == INTEGER_TYPE) + return gen_rtx (CONST_INT, VOIDmode, integer_type_class); + if (code == CHAR_TYPE) + return gen_rtx (CONST_INT, VOIDmode, char_type_class); + if (code == ENUMERAL_TYPE) + return gen_rtx (CONST_INT, VOIDmode, enumeral_type_class); + if (code == BOOLEAN_TYPE) + return gen_rtx (CONST_INT, VOIDmode, boolean_type_class); + if (code == POINTER_TYPE) + return gen_rtx (CONST_INT, VOIDmode, pointer_type_class); + if (code == REFERENCE_TYPE) + return gen_rtx (CONST_INT, VOIDmode, reference_type_class); + if (code == OFFSET_TYPE) + return gen_rtx (CONST_INT, VOIDmode, offset_type_class); + if (code == REAL_TYPE) + return gen_rtx (CONST_INT, VOIDmode, real_type_class); + if (code == COMPLEX_TYPE) + return gen_rtx (CONST_INT, VOIDmode, complex_type_class); + if (code == FUNCTION_TYPE) + return gen_rtx (CONST_INT, VOIDmode, function_type_class); + if (code == METHOD_TYPE) + return gen_rtx (CONST_INT, VOIDmode, method_type_class); + if (code == RECORD_TYPE) + return gen_rtx (CONST_INT, VOIDmode, record_type_class); + if (code == UNION_TYPE) + return gen_rtx (CONST_INT, VOIDmode, union_type_class); + if (code == ARRAY_TYPE) + return gen_rtx (CONST_INT, VOIDmode, array_type_class); + if (code == STRING_TYPE) + return gen_rtx (CONST_INT, VOIDmode, string_type_class); + if (code == SET_TYPE) + return gen_rtx (CONST_INT, VOIDmode, set_type_class); + if (code == FILE_TYPE) + return gen_rtx (CONST_INT, VOIDmode, file_type_class); + if (code == LANG_TYPE) + return gen_rtx (CONST_INT, VOIDmode, lang_type_class); + } + return gen_rtx (CONST_INT, VOIDmode, no_type_class); + + case BUILT_IN_ALLOCA: + if (arglist == 0 + /* Arg could be non-integer if user redeclared this fcn wrong. */ + || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != INTEGER_TYPE) + return const0_rtx; + frame_pointer_needed = 1; + current_function_calls_alloca = 1; + /* Compute the argument. */ + op0 = expand_expr (TREE_VALUE (arglist), 0, VOIDmode, 0); + if (! CONSTANT_P (op0)) + { + op0 = force_reg (GET_MODE (op0), op0); + if (GET_MODE (op0) != Pmode) + op0 = convert_to_mode (Pmode, op0, 1); + } + /* Push that much space (rounding it up). */ + do_pending_stack_adjust (); + +#ifdef STACK_POINTER_OFFSET + /* If we will have to round the result down (which is up + if stack grows down), make sure we have extra space so the + user still gets at least as much space as he asked for. */ + if ((STACK_POINTER_OFFSET + STACK_BYTES - 1) / STACK_BYTES + != STACK_POINTER_OFFSET / STACK_BYTES) + op0 = plus_constant (op0, STACK_BYTES); +#endif + +#ifdef STACK_GROWS_DOWNWARD + anti_adjust_stack (round_push (op0)); +#endif + /* Return a copy of current stack ptr, in TARGET if possible. */ + if (target) + emit_move_insn (target, stack_pointer_rtx); + else + target = copy_to_reg (stack_pointer_rtx); +#ifdef STACK_POINTER_OFFSET + /* If the contents of the stack pointer reg are offset from the + actual top-of-stack address, add the offset here. */ + if (GET_CODE (target) == REG) + emit_insn (gen_add2_insn (target, + gen_rtx (CONST_INT, VOIDmode, + (STACK_POINTER_OFFSET + STACK_BYTES - 1) / STACK_BYTES * STACK_BYTES))); + else + { + rtx temp = + expand_binop (GET_MODE (target), add_optab, target, + gen_rtx (CONST_INT, VOIDmode, + (STACK_POINTER_OFFSET + STACK_BYTES - 1) / STACK_BYTES * STACK_BYTES), + target, + 1, OPTAB_DIRECT); + if (temp == 0) abort (); + if (temp != target) + emit_move_insn (target, temp); + } +#endif +#ifndef STACK_GROWS_DOWNWARD + anti_adjust_stack (round_push (op0)); +#endif + /* Some systems require a particular insn to refer to the stack + to make the pages exist. */ +#ifdef HAVE_probe + if (HAVE_probe) + emit_insn (gen_probe ()); +#endif + return target; + + case BUILT_IN_FFS: + if (arglist == 0 + /* Arg could be non-integer if user redeclared this fcn wrong. */ + || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != INTEGER_TYPE) + return const0_rtx; + + /* Compute the argument. */ + op0 = expand_expr (TREE_VALUE (arglist), subtarget, VOIDmode, 0); + /* Compute ffs, into TARGET if possible. + Set TARGET to wherever the result comes back. */ + target = expand_unop (TYPE_MODE (TREE_TYPE (TREE_VALUE (arglist))), + ffs_optab, op0, target, 1); + if (target == 0) + abort (); + return target; + + default: + abort (); + } +} + +/* Expand code for a post- or pre- increment or decrement + and return the RTX for the result. + POST is 1 for postinc/decrements and 0 for preinc/decrements. */ + +static rtx +expand_increment (exp, post) + register tree exp; + int post; +{ + register rtx op0, op1; + register rtx temp; + register tree incremented = TREE_OPERAND (exp, 0); + optab this_optab = add_optab; + int icode; + enum machine_mode mode = TYPE_MODE (TREE_TYPE (exp)); + int op0_is_copy = 0; + + /* Stabilize any component ref that might need to be + evaluated more than once below. */ + if (TREE_CODE (incremented) == COMPONENT_REF + && (TREE_CODE (TREE_OPERAND (incremented, 0)) != INDIRECT_REF + || DECL_MODE (TREE_OPERAND (incremented, 1)) == BImode)) + incremented = stabilize_reference (incremented); + + /* Compute the operands as RTX. + Note whether OP0 is the actual lvalue or a copy of it: + I believe it is a copy iff it is a register and insns were + generated in computing it. */ + temp = get_last_insn (); + op0 = expand_expr (incremented, 0, VOIDmode, 0); + if (temp != get_last_insn ()) + op0_is_copy = (GET_CODE (op0) == REG || GET_CODE (op0) == SUBREG); + op1 = expand_expr (TREE_OPERAND (exp, 1), 0, VOIDmode, 0); + + /* Decide whether incrementing or decrementing. */ + if (TREE_CODE (exp) == POSTDECREMENT_EXPR + || TREE_CODE (exp) == PREDECREMENT_EXPR) + this_optab = sub_optab; + + /* If OP0 is not the actual lvalue, but rather a copy in a register, + then we cannot just increment OP0. We must + therefore contrive to increment the original value. + Then we can return OP0 since it is a copy of the old value. */ + if (op0_is_copy) + { + /* This is the easiest way to increment the value wherever it is. + Problems with multiple evaluation of INCREMENTED + are prevented because either (1) it is a component_ref, + in which case it was stabilized above, or (2) it is an array_ref + with constant index in an array in a register, which is + safe to reevaluate. */ + tree newexp = build ((this_optab == add_optab + ? PLUS_EXPR : MINUS_EXPR), + TREE_TYPE (exp), + incremented, + TREE_OPERAND (exp, 1)); + temp = expand_assignment (incremented, newexp, ! post, 0); + return post ? op0 : temp; + } + + /* Convert decrement by a constant into a negative increment. */ + if (this_optab == sub_optab + && GET_CODE (op1) == CONST_INT) + { + op1 = gen_rtx (CONST_INT, VOIDmode, - INTVAL (op1)); + this_optab = add_optab; + } + + if (post) + { + /* We have a true reference to the value in OP0. + If there is an insn to add or subtract in this mode, queue it. */ + + /* I'm not sure this is still necessary. */ + op0 = stabilize (op0); + + icode = (int) this_optab->handlers[(int) mode].insn_code; + if (icode != (int) CODE_FOR_nothing + /* Make sure that OP0 is valid for operands 0 and 1 + of the insn we want to queue. */ + && (*insn_operand_predicate[icode][0]) (op0, mode) + && (*insn_operand_predicate[icode][1]) (op0, mode)) + { + if (! (*insn_operand_predicate[icode][2]) (op1, mode)) + op1 = force_reg (mode, op1); + + return enqueue_insn (op0, GEN_FCN (icode) (op0, op0, op1)); + } + } + + /* Preincrement, or we can't increment with one simple insn. */ + if (post) + /* Save a copy of the value before inc or dec, to return it later. */ + temp = copy_to_reg (op0); + else + /* Arrange to return the incremented value. */ + /* Copy the rtx because expand_binop will protect from the queue, + and the results of that would be invalid for us to return + if our caller does emit_queue before using our result. */ + temp = copy_rtx (op0); + + /* Increment however we can. */ + op1 = expand_binop (mode, this_optab, op0, op1, op0, + TREE_UNSIGNED (TREE_TYPE (exp)), OPTAB_LIB_WIDEN); + /* Make sure the value is stored into OP0. */ + if (op1 != op0) + emit_move_insn (op0, op1); + + return temp; +} + +/* Expand all function calls contained within EXP, innermost ones first. + But don't look within expressions that have sequence points. + For each CALL_EXPR, record the rtx for its value + in the CALL_EXPR_RTL field. + + Calls that return large structures for which a structure return + stack slot is needed are not preexpanded. Preexpanding them loses + because if more than one were preexpanded they would try to use the + same stack slot. */ + +static void +preexpand_calls (exp) + tree exp; +{ + register int nops, i; + + if (! do_preexpand_calls) + return; + + /* Only expressions and references can contain calls. */ + + if (tree_code_type[(int) TREE_CODE (exp)][0] != 'e' + && tree_code_type[(int) TREE_CODE (exp)][0] != 'r') + return; + + switch (TREE_CODE (exp)) + { + case CALL_EXPR: + /* 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_FUNCTION_CODE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)) + != NOT_BUILT_IN)) + return; + /* Precompute calls that don't return values in memory. */ + if (CALL_EXPR_RTL (exp) == 0 + && TYPE_MODE (TREE_TYPE (exp)) != BLKmode + && ! RETURN_IN_MEMORY (TREE_TYPE (exp))) + CALL_EXPR_RTL (exp) = expand_call (exp, 0, 0); + return; + + case COMPOUND_EXPR: + case COND_EXPR: + case TRUTH_ANDIF_EXPR: + case TRUTH_ORIF_EXPR: + /* If we find one of these, then we can be sure + the adjust will be done for it (since it makes jumps). + Do it now, so that if this is inside an argument + of a function, we don't get the stack adjustment + after some other args have already been pushed. */ + do_pending_stack_adjust (); + return; + + case RTL_EXPR: + return; + + case SAVE_EXPR: + if (SAVE_EXPR_RTL (exp) != 0) + return; + } + + nops = tree_code_length[(int) TREE_CODE (exp)]; + for (i = 0; i < nops; i++) + if (TREE_OPERAND (exp, i) != 0) + { + register int type = *tree_code_type[(int) TREE_CODE (TREE_OPERAND (exp, i))]; + if (type == 'e' || type == 'r') + preexpand_calls (TREE_OPERAND (exp, i)); + } +} + +/* Force FUNEXP into a form suitable for the address of a CALL, + and return that as an rtx. Also load the static chain register + from either FUNEXP or CONTEXT. */ + +static rtx +prepare_call_address (funexp, context) + rtx funexp; + rtx context; +{ + funexp = protect_from_queue (funexp, 0); + if (context != 0) + context = protect_from_queue (context, 0); + + /* Function variable in language with nested functions. */ + if (GET_MODE (funexp) == EPmode) + { + emit_move_insn (static_chain_rtx, gen_highpart (Pmode, funexp)); + funexp = memory_address (FUNCTION_MODE, gen_lowpart (Pmode, funexp)); + emit_insn (gen_rtx (USE, VOIDmode, static_chain_rtx)); + } + else + { + if (context != 0) + /* Unless function variable in C, or top level function constant */ + emit_move_insn (static_chain_rtx, lookup_static_chain (context)); + + /* 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 = memory_address (FUNCTION_MODE, funexp); + else + { +#ifndef NO_FUNCTION_CSE + if (optimize && ! flag_no_function_cse) + funexp = force_reg (Pmode, funexp); +#endif + } + + if (context != 0) + emit_insn (gen_rtx (USE, VOIDmode, static_chain_rtx)); + } + return funexp; +} + +/* Generate instructions to call function FUNEXP, + and optionally pop the results. + The CALL_INSN is the first insn generated. + + 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. + + STACK_SIZE is the number of bytes of arguments on the stack, + rounded up to STACK_BOUNDARY; zero if the size is variable. + This is both to put into the call insn and + to generate explicit popping code if necessary. + + NEXT_ARG_REG is the rtx that results from executing + FUNCTION_ARG (args_so_far, VOIDmode, void_type_node, 1) + just after all the args have had their registers assigned. + This could be whatever you like, but normally it is the first + arg-register beyond those used for args in this call, + or 0 if all the arg-registers are used in this call. + It is passed on to `gen_call' so you can put this info in the call insn. + + VALREG is a hard register in which a value is returned, + or 0 if the call does not return a value. + + OLD_INHIBIT_DEFER_POP is the value that `inhibit_defer_pop' had before + the args to this call were processed. + We restore `inhibit_defer_pop' to that value. + + USE_INSNS is a SEQUENCE of USE insns to be emitted immediately before + the actual CALL insn. */ + +static void +emit_call_1 (funexp, funtype, stack_size, next_arg_reg, valreg, old_inhibit_defer_pop, use_insns) + rtx funexp; + tree funtype; + int stack_size; + rtx next_arg_reg; + rtx valreg; + int old_inhibit_defer_pop; + rtx use_insns; +{ + rtx stack_size_rtx = gen_rtx (CONST_INT, VOIDmode, stack_size); + rtx call_insn; + + if (valreg) + emit_call_insn (gen_call_value (valreg, + gen_rtx (MEM, FUNCTION_MODE, funexp), + stack_size_rtx, next_arg_reg)); + else + emit_call_insn (gen_call (gen_rtx (MEM, FUNCTION_MODE, funexp), + stack_size_rtx, next_arg_reg)); + + /* Find the CALL insn we just emitted and write the USE insns before it. */ + for (call_insn = get_last_insn(); + call_insn && GET_CODE (call_insn) != CALL_INSN; + call_insn = PREV_INSN (call_insn)) + ; + + if (! call_insn) + abort (); + + /* Put the USE insns before the CALL. */ + emit_insn_before (use_insns, call_insn); + + inhibit_defer_pop = old_inhibit_defer_pop; + + /* If returning from the subroutine does not automatically pop the args, + we need an instruction to pop them sooner or later. + Perhaps do it now; perhaps just record how much space to pop later. */ + + if (! RETURN_POPS_ARGS (funtype) + && stack_size != 0) + { + if (flag_defer_pop && inhibit_defer_pop == 0) + pending_stack_adjust += stack_size; + else + adjust_stack (stack_size_rtx); + } +} + +/* At the start of a function, record that we have no previously-pushed + arguments waiting to be popped. */ + +void +init_pending_stack_adjust () +{ + pending_stack_adjust = 0; +} + +/* When exiting from function, if safe, clear out any pending stack adjust + so the adjustment won't get done. */ + +void +clear_pending_stack_adjust () +{ +#ifdef EXIT_IGNORE_STACK + if (!flag_omit_frame_pointer && EXIT_IGNORE_STACK + && ! TREE_INLINE (current_function_decl) + && ! flag_inline_functions) + pending_stack_adjust = 0; +#endif +} + +/* Pop any previously-pushed arguments that have not been popped yet. */ + +void +do_pending_stack_adjust () +{ + if (inhibit_defer_pop == 0) + { + if (pending_stack_adjust != 0) + adjust_stack (gen_rtx (CONST_INT, VOIDmode, pending_stack_adjust)); + pending_stack_adjust = 0; + } +} + +/* Data structure and subroutines used within expand_call. */ + +struct arg_data +{ + /* Tree node for this argument. */ + tree tree_value; + /* Precomputed RTL value, or 0 if it isn't precomputed. */ + rtx value; + /* Register to pass this argument in, or 0 if passed on stack. */ + rtx reg; + /* Number of registers to use. 0 means put the whole arg in registers. + Also 0 if not passed in registers. */ + int partial; + /* Offset of this argument from beginning of stack-args. */ + struct args_size offset; + /* Size of this argument on the stack, rounded up for any padding it gets, + parts of the argument passed in registers do not count. + If the FIRST_PARM_CALLER_OFFSET is negative, then register parms + are counted here as well. */ + struct args_size size; + /* Nonzero if this arg has already been stored. */ + int stored; + /* const0_rtx means should preallocate stack space for this arg. + Other non0 value is the stack slot, preallocated. + Used only for BLKmode. */ + rtx stack; +}; + +static void store_one_arg (); +static rtx target_for_arg (); + +/* Generate all the code for a function call + and return an rtx for its value. + Store the value in TARGET (specified as an rtx) if convenient. + If the value is stored in TARGET then TARGET is returned. + If IGNORE is nonzero, then we ignore the value of the function call. */ + +static rtx +expand_call (exp, target, ignore) + tree exp; + rtx target; + int ignore; +{ + /* List of actual parameters. */ + tree actparms = TREE_OPERAND (exp, 1); + /* RTX for the function to be called. */ + rtx funexp; + /* Data type of the function. */ + tree funtype; + /* Declaration of the function being called, + or 0 if the function is computed (not known by name). */ + tree fndecl = 0; + + /* Register in which non-BLKmode value will be returned, + or 0 if no value or if value is BLKmode. */ + rtx valreg; + /* Address where we should return a BLKmode value; + 0 if value not BLKmode. */ + rtx structure_value_addr = 0; + /* Nonzero if that address is being passed by treating it as + an extra, implicit first parameter. Otherwise, + it is passed by being copied directly into struct_value_rtx. */ + int structure_value_addr_parm = 0; + /* Save get_structure_value_addr data to prevent multiple use. */ + rtx saved_structure_value_addr; + int saved_structure_value_size; + /* 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; + /* Insn that was used to copy the result to the specified target, + or 0 if no such insn. */ + rtx result_copy_insn = 0; + + /* Number of actual parameters in this call, including struct value addr. */ + int num_actuals; + /* Number of named args. Args after this are anonymous ones + and they must all go on the stack. */ + int n_named_args; + /* Count arg position in order args appear. */ + int argpos; + + /* Vector of information about each argument. + Arguments are numbered in the order they will be pushed, + not the order they are written. */ + struct arg_data *args; + + /* Total size in bytes of all the stack-parms scanned so far. */ + struct args_size args_size; + /* Remember initial value of args_size.constant. */ + int starting_args_size; + /* Nonzero means count reg-parms' size in ARGS_SIZE. */ + int stack_count_regparms = 0; + /* Data on reg parms scanned so far. */ + CUMULATIVE_ARGS args_so_far; + /* Nonzero if a reg parm has been scanned. */ + int reg_parm_seen; + /* Nonzero if we must avoid push-insns in the args for this call. */ + int must_preallocate; + /* 1 if scanning parms front to back, -1 if scanning back to front. */ + int inc; + /* Address of space preallocated for stack parms + (on machines that lack push insns), or 0 if space not preallocated. */ + rtx argblock = 0; + /* Amount to align the stack by before or after we push any args. */ + int stack_align = 0; + + /* Nonzero if it is plausible that this is a call to alloca. */ + int may_be_alloca; + /* Nonzero if this is a call to setjmp or a related function. */ + int is_setjmp; + /* Nonzero if this is a call to an inline function. */ + int is_integrable = 0; + /* Nonzero if this is a call to __builtin_new. */ + int is_builtin_new; + /* Nonzero if this is a call to a `const' function. */ + int is_const = 0; + + /* Nonzero if there are BLKmode args whose data types require them + to be passed in memory, not (even partially) in registers. */ + int BLKmode_parms_forced = 0; + /* The offset of the first BLKmode parameter which + *must* be passed in memory. */ + int BLKmode_parms_first_offset = 0; + /* Total size of BLKmode parms which could usefully be preallocated. */ + int BLKmode_parms_sizes = 0; + + /* Amount stack was adjusted to protect BLKmode parameters + which are below the nominal "stack address" value. */ + rtx protected_stack = 0; + + /* The last insn before the things that are intrinsically part of the call. + The beginning reg-note goes on the insn after this one. */ + rtx insn_before; + + rtx old_stack_level = 0; + int old_pending_adj; + int old_inhibit_defer_pop = inhibit_defer_pop; + tree old_cleanups = cleanups_of_this_call; + rtx use_insns; + + register tree p; + register int i; + + /* 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. */ + + p = TREE_OPERAND (exp, 0); + if (TREE_CODE (p) == ADDR_EXPR) + { + fndecl = TREE_OPERAND (p, 0); + if (TREE_CODE (fndecl) != FUNCTION_DECL) + fndecl = 0; + else + { + extern tree current_function_decl; + + if (fndecl != current_function_decl + && DECL_SAVED_INSNS (fndecl)) + is_integrable = 1; + else + { + /* In case this function later becomes inlineable, + record that there was already a non-inline call to it. */ + mark_addressable (fndecl); + } + + if (TREE_READONLY (fndecl) && ! TREE_THIS_VOLATILE (fndecl)) + is_const = 1; + } + } + + /* When calling a const function, we must pop the stack args right away, + so that the pop is deleted or moved with the call. */ + if (is_const) + NO_DEFER_POP; + + /* Set up a place to return a structure. */ + + /* Cater to broken compilers. */ + if (aggregate_value_p (exp)) + { + /* This call returns a big structure. */ +#ifdef PCC_STATIC_STRUCT_RETURN + if (flag_pcc_struct_return) + { + pcc_struct_value = 1; + is_integrable = 0; /* Easier than making that case work right. */ + } + else +#endif + { + if (target && GET_CODE (target) == MEM) + { + structure_value_addr = XEXP (target, 0); + if (reg_mentioned_p (stack_pointer_rtx, structure_value_addr)) + structure_value_addr = copy_to_reg (structure_value_addr); + } + else + { + push_structure_value (&saved_structure_value_addr, + &saved_structure_value_size); + /* Make room on the stack to hold the value. */ + structure_value_addr + = get_structure_value_addr (expr_size (exp)); + target = 0; + } + } + } + + /* If called function is inline, try to integrate it. */ + + if (is_integrable) + { + extern rtx expand_inline_function (); + rtx temp; + + temp = expand_inline_function (fndecl, actparms, target, + ignore, TREE_TYPE (exp), + structure_value_addr); + + /* If inlining succeeded, return. */ + if ((int) temp != -1) + return temp; + + /* If inlining failed, mark FNDECL as needing to be compiled + separately after all. */ + TREE_ADDRESSABLE (fndecl) = 1; + TREE_ADDRESSABLE (DECL_NAME (fndecl)) = 1; + } + +#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 (IDENTIFIER_POINTER (DECL_NAME (fndecl)), + "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 = + (fndecl && (! strcmp (IDENTIFIER_POINTER (DECL_NAME (fndecl)), "alloca") + || ! strcmp (IDENTIFIER_POINTER (DECL_NAME (fndecl)), + "__builtin_alloca"))); +#endif + + /* See if this is a call to a function that can return more than once. */ + + is_setjmp + = (fndecl != 0 + && (!strcmp (IDENTIFIER_POINTER (DECL_NAME (fndecl)), "setjmp") + || !strcmp (IDENTIFIER_POINTER (DECL_NAME (fndecl)), "_setjmp"))); + + is_builtin_new + = (fndecl != 0 + && (!strcmp (IDENTIFIER_POINTER (DECL_NAME (fndecl)), "__builtin_new"))); + + if (may_be_alloca) + { + frame_pointer_needed = 1; + may_call_alloca = 1; + current_function_calls_alloca = 1; + } + + /* Don't let pending stack adjusts add up to too much. + Also, do all pending adjustments now + if there is any chance this might be a call to alloca + or if it is const. */ + + if (pending_stack_adjust >= 32 || is_const + || (pending_stack_adjust > 0 && may_be_alloca)) + do_pending_stack_adjust (); + + /* Operand 0 is a pointer-to-function; get the type of the function. */ + funtype = TREE_TYPE (TREE_OPERAND (exp, 0)); + if (TREE_CODE (funtype) != POINTER_TYPE) + abort (); + funtype = TREE_TYPE (funtype); + + /* If structure_value_addr is set, it means pass the address + as if it were an extra parameter. We typically avoid doing + so here, which would imply that the caller has to pop it off + the stack; but some compilers do expect caller pop. */ + if (structure_value_addr +#ifdef STRUCT_RETURN_CALLER_POP + && flag_pcc_struct_return +#else + && struct_value_rtx == 0 +#endif + ) + { + rtx tem; + + INIT_CUMULATIVE_ARGS (args_so_far, funtype); + tem = FUNCTION_ARG (args_so_far, Pmode, + build_pointer_type (TREE_TYPE (funtype)), 1); + if (tem == 0) + { + actparms = tree_cons (error_mark_node, + build (SAVE_EXPR, + type_for_size (GET_MODE_BITSIZE (Pmode), 0), + 0, + force_reg (Pmode, structure_value_addr)), + actparms); + structure_value_addr_parm = 1; + } +#ifdef STRUCT_RETURN_CALLER_POP + /* Moved in 1.39 from before the preceding open-brace. + Should be safe without the conditional because, + if STRUCT_RETURN_CALLER_POP is not defined, + this can still happen only if struct_value_rtx is 0, + and in that case, we would crash anyway if this weren't done. */ + structure_value_addr_parm = 1; +#endif + } + + /* Count the arguments and set NUM_ACTUALS. */ + for (p = actparms, i = 0; p; p = TREE_CHAIN (p)) i++; + num_actuals = i; + + /* Compute number of named args. + Don't include the last named arg if anonymous args follow. + (If no anonymous args follow, the result of list_length + is actually one too large.) */ + if (TYPE_ARG_TYPES (funtype) != 0) + n_named_args = list_length (TYPE_ARG_TYPES (funtype)) - 1; + else + /* If we know nothing, treat all args as named. */ + n_named_args = num_actuals; + + /* Make a vector to hold all the information about each arg. */ + args = (struct arg_data *) alloca (num_actuals * sizeof (struct arg_data)); + bzero (args, num_actuals * sizeof (struct arg_data)); + + args_size.constant = 0; + args_size.var = 0; +#ifdef FIRST_PARM_CALLER_OFFSET + args_size.constant = FIRST_PARM_CALLER_OFFSET (funtype); + stack_count_regparms = 1; +#endif + starting_args_size = args_size.constant; + + /* In this loop, we consider args in the order they are written. + We fill up ARGS from the front of from the back if necessary + so that in any case the first arg to be pushed ends up at the front. */ + +#ifdef PUSH_ARGS_REVERSED + i = num_actuals - 1, inc = -1; + /* In this case, must reverse order of args + so that we compute and push the last arg first. */ +#else + i = 0, inc = 1; +#endif + + INIT_CUMULATIVE_ARGS (args_so_far, funtype); + + /* I counts args in order (to be) pushed; ARGPOS counts in order written. */ + for (p = actparms, argpos = 0; p; p = TREE_CHAIN (p), i += inc, argpos++) + { + tree type = TREE_TYPE (TREE_VALUE (p)); + args[i].tree_value = TREE_VALUE (p); + args[i].offset = args_size; + + if (type == error_mark_node + || TYPE_SIZE (type) == 0) + continue; + + /* Decide where to pass this arg. */ + /* args[i].reg is nonzero if all or part is passed in registers. + args[i].partial is nonzero if part but not all is passed in registers, + and the exact value says how many words are passed in registers. */ + + if (TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST + && args_size.var == 0 + /* error_mark_node here is a flag for the fake argument + for a structure value address. */ + && TREE_PURPOSE (p) != error_mark_node) + { + args[i].reg = FUNCTION_ARG (args_so_far, TYPE_MODE (type), type, + argpos < n_named_args); + /* If this argument needs more than the usual parm alignment, do + extrinsic padding to reach that alignment. */ + +#ifdef MAX_PARM_BOUNDARY + /* If MAX_PARM_BOUNDARY is not defined, it means that the usual + alignment requirements are relaxed for parms, and that no parm + needs more than PARM_BOUNDARY, regardless of data type. */ + + if (PARM_BOUNDARY < TYPE_ALIGN (type)) + { + int boundary = PARM_BOUNDARY; + + /* Determine the boundary to pad up to. */ + if (TYPE_ALIGN (type) > boundary) + boundary = TYPE_ALIGN (type); + if (boundary > MAX_PARM_BOUNDARY) + boundary = MAX_PARM_BOUNDARY; + + /* If the previous args don't reach such a boundary, + advance to the next one. */ + boundary /= BITS_PER_UNIT; + args[i].offset.constant += boundary - 1; + args[i].offset.constant &= ~(boundary - 1); + args_size.constant += boundary - 1; + args_size.constant &= ~(boundary - 1); + + if (args_size.var != 0) + abort (); /* This case not implemented yet */ + } +#endif /* MAX_PARM_BOUNDARY */ + +#ifdef FUNCTION_ARG_PARTIAL_NREGS + args[i].partial + = FUNCTION_ARG_PARTIAL_NREGS (args_so_far, + TYPE_MODE (type), type, + argpos < n_named_args); +#endif + } + + /* Compute the stack-size of this argument. */ + + if (args[i].reg != 0 && args[i].partial == 0 + && ! stack_count_regparms) + /* On most machines, don't count stack space for a register arg. */ + ; + else if (TYPE_MODE (type) != BLKmode) + { + register int size; + + /* If we are counting "up to zero" and find a stack parm + before we reach zero, skip up to zero. + Negative offsets correspond to registers. */ + if (stack_count_regparms && args_size.constant < 0 + /* This used to check args[i].partial != 0, + but on the Sparc now that seems to be 0. */ + && args[i].reg == 0) + { + args_size.constant = 0; + args[i].offset.constant = 0; + } + size = GET_MODE_SIZE (TYPE_MODE (type)); + /* Compute how much space the push instruction will push. + On many machines, pushing a byte will advance the stack + pointer by a halfword. */ +#ifdef PUSH_ROUNDING + size = PUSH_ROUNDING (size); +#endif + /* Compute how much space the argument should get: + maybe pad to a multiple of the alignment for arguments. */ + if (none == FUNCTION_ARG_PADDING (TYPE_MODE (type), const0_rtx)) + args[i].size.constant = size; + else + args[i].size.constant + = (((size + PARM_BOUNDARY / BITS_PER_UNIT - 1) + / (PARM_BOUNDARY / BITS_PER_UNIT)) + * (PARM_BOUNDARY / BITS_PER_UNIT)); + } + else + { + register tree size = size_in_bytes (type); + + /* If we are counting "up to zero" and find a stack parm + before we reach zero, skip up to zero. + Negative offsets correspond to registers. */ + if (stack_count_regparms && args_size.constant < 0 + /* This used to check args[i].partial != 0, + but on the Sparc now that seems to be 0. */ + && args[i].reg == 0) + { + args_size.constant = 0; + args[i].offset.constant = 0; + } + + /* A nonscalar. Round its size up to a multiple + of PARM_BOUNDARY bits, unless it is not supposed to be padded. */ + if (none + != FUNCTION_ARG_PADDING (TYPE_MODE (type), + expand_expr (size, 0, VOIDmode, 0))) + size = convert_units (convert_units (size, BITS_PER_UNIT, + PARM_BOUNDARY), + PARM_BOUNDARY, BITS_PER_UNIT); + ADD_PARM_SIZE (args[i].size, size); + + /* Certain data types may not be passed in registers + (eg C++ classes with constructors). + Also, BLKmode parameters initialized from CALL_EXPRs + are treated specially, if it is a win to do so. */ + if (TREE_CODE (TREE_VALUE (p)) == CALL_EXPR + || TREE_ADDRESSABLE (type)) + { + if (TREE_ADDRESSABLE (type)) + BLKmode_parms_forced = 1; + /* This is a marker for such a parameter. */ + args[i].stack = const0_rtx; + BLKmode_parms_sizes += TREE_INT_CST_LOW (size); + + /* If this parm's location is "below" the nominal stack pointer, + note to decrement the stack pointer while it is computed. */ +#ifdef FIRST_PARM_CALLER_OFFSET + if (BLKmode_parms_first_offset == 0) + BLKmode_parms_first_offset + /* If parameter's offset is variable, assume the worst. */ + = (args[i].offset.var + ? FIRST_PARM_CALLER_OFFSET (funtype) + : args[i].offset.constant); +#endif + } + } + + /* If a part of the arg was put into registers, + don't include that part in the amount pushed. */ + if (! stack_count_regparms) + args[i].size.constant + -= ((args[i].partial * UNITS_PER_WORD) + / (PARM_BOUNDARY / BITS_PER_UNIT) + * (PARM_BOUNDARY / BITS_PER_UNIT)); + + /* Update ARGS_SIZE, the total stack space for args so far. */ + + args_size.constant += args[i].size.constant; + if (args[i].size.var) + { + ADD_PARM_SIZE (args_size, args[i].size.var); + } + + /* Increment ARGS_SO_FAR, which has info about which arg-registers + have been used, etc. */ + + FUNCTION_ARG_ADVANCE (args_so_far, TYPE_MODE (type), type, + argpos < n_named_args); + } + + /* If we would have to push a partially-in-regs parm + before other stack parms, preallocate stack space instead. */ + must_preallocate = 0; + { + int partial_seen = 0; + for (i = 0; i < num_actuals; i++) + { + if (args[i].partial > 0) + partial_seen = 1; + else if (partial_seen && args[i].reg == 0) + must_preallocate = 1; + } + } + + /* Precompute all register parameters. It isn't safe to compute anything + once we have started filling any specific hard regs. + If this function call is cse'able, precompute all the parameters. */ + + reg_parm_seen = 0; + for (i = 0; i < num_actuals; i++) + if (args[i].reg != 0 || is_const) + { + int j; + int struct_value_lossage = 0; + + /* First, see if this is a precomputed struct-returning function call + and other subsequent parms are also such. */ + if ((TYPE_MODE (TREE_TYPE (args[i].tree_value)) == BLKmode + || RETURN_IN_MEMORY (TREE_TYPE (args[i].tree_value))) + && TREE_CODE (args[i].tree_value) == CALL_EXPR) + for (j = i + 1; j < num_actuals; j++) + if ((TYPE_MODE (TREE_TYPE (args[j].tree_value)) == BLKmode + || RETURN_IN_MEMORY (TREE_TYPE (args[j].tree_value))) + && TREE_CODE (args[j].tree_value) == CALL_EXPR + && args[j].reg != 0 || is_const) + { + /* We have two precomputed structure-values call expressions + in our parm list. Both of them would normally use + the structure-value block. To avoid the conflict, + compute this parm with a different temporary block. */ + int size = int_size_in_bytes (TREE_TYPE (args[i].tree_value)); + rtx structval = assign_stack_local (BLKmode, size); + args[i].value = expand_expr (args[i].tree_value, structval, + VOIDmode, 0); + struct_value_lossage = 1; + break; + } + if (!struct_value_lossage) + args[i].value = expand_expr (args[i].tree_value, 0, VOIDmode, 0); + + if (args[i].reg != 0) + reg_parm_seen = 1; + + if (GET_CODE (args[i].value) != MEM + && ! CONSTANT_P (args[i].value) + && GET_CODE (args[i].value) != CONST_DOUBLE) + args[i].value + = force_reg (TYPE_MODE (TREE_TYPE (args[i].tree_value)), + args[i].value); + /* ANSI doesn't require a sequence point here, + but PCC has one, so this will avoid some problems. */ + emit_queue (); + } + + /* Get the function to call, in the form of RTL, if it is a constant. */ + if (fndecl && is_const) + { + /* Get a SYMBOL_REF rtx for the function address. */ + funexp = XEXP (DECL_RTL (fndecl), 0); + +#ifndef NO_FUNCTION_CSE + /* Pass the address through a pseudoreg, if desired, + before the "beginning" of the library call. + So this insn isn't "part of" the library call, in case that + is deleted, or cse'd. */ + if (! flag_no_function_cse) + funexp = copy_to_mode_reg (Pmode, funexp); +#endif + } + + /* Now we are about to start emitting insns that can be deleted + if the libcall is deleted. */ + insn_before = get_last_insn (); + + /* Maybe do additional rounding on the size of the arguments. */ +#ifdef STACK_ARGS_ADJUST + STACK_ARGS_ADJUST (args_size); +#endif + + /* If we have no actual push instructions, or shouldn't use them, + or we need a variable amount of space, make space for all args right now. + Round the needed size up to multiple of STACK_BOUNDARY. */ + + if (args_size.var != 0) + { + old_stack_level = copy_to_mode_reg (Pmode, stack_pointer_rtx); + old_pending_adj = pending_stack_adjust; + argblock = push_block (round_push (ARGS_SIZE_RTX (args_size)), 0); + } + else if (args_size.constant > 0) + { + int needed = args_size.constant; + +#ifdef STACK_BOUNDARY + needed = (needed + STACK_BYTES - 1) / STACK_BYTES * STACK_BYTES; + stack_align = needed - args_size.constant; +#endif + args_size.constant = needed; + + if ( +#ifndef PUSH_ROUNDING + 1 /* Always preallocate if no push insns. */ +#else + must_preallocate || BLKmode_parms_forced + || BLKmode_parms_sizes > (args_size.constant >> 1) +#endif + ) + { + if (inhibit_defer_pop == 0) + { + /* Try to reuse some or all of the pending_stack_adjust + to get this space. Maybe we can avoid any pushing. */ + if (needed > pending_stack_adjust) + { + needed -= pending_stack_adjust; + pending_stack_adjust = 0; + } + else + { + pending_stack_adjust -= needed; + needed = 0; + } + } + argblock = push_block (gen_rtx (CONST_INT, VOIDmode, needed), 0); + } + } +#ifndef PUSH_ROUNDING + else if (BLKmode_parms_forced) + { + /* If we have reg-parms that need to be temporarily on the stack, + set up an arg block address even though there is no space + to be allocated for it. */ + argblock = push_block (const0_rtx, 0); + } +#endif + +#if 0 + /* If stack needs padding below the args, increase all arg offsets + so the args are stored above the padding. */ + if (stack_padding) + for (i = 0; i < num_actuals; i++) + args[i].offset.constant += stack_padding; +#endif + + /* Don't try to defer pops if preallocating, not even from the first arg, + since ARGBLOCK probably refers to the SP. */ + if (argblock) + NO_DEFER_POP; + +#ifdef STACK_GROWS_DOWNWARD + /* If any BLKmode parms need to be preallocated in space + below the nominal stack-pointer address, we need to adjust the + stack pointer so that this location is temporarily above it. + This ensures that computation won't clobber that space. */ + if (BLKmode_parms_first_offset < 0 && argblock != 0) + { + int needed = -BLKmode_parms_first_offset; + argblock = copy_to_reg (argblock); + +#ifdef STACK_BOUNDARY + needed = (needed + STACK_BYTES - 1) / STACK_BYTES * STACK_BYTES; +#endif + protected_stack = gen_rtx (CONST_INT, VOIDmode, needed); + anti_adjust_stack (protected_stack); + } +#endif /* STACK_GROWS_DOWNWARD */ + +#ifdef PUSH_ARGS_REVERSED +#ifdef STACK_BOUNDARY + /* If we push args individually in reverse order, perform stack alignment + before the first push (the last arg). */ + if (argblock == 0 && stack_align > 0) + anti_adjust_stack (gen_rtx (CONST_INT, VOIDmode, stack_align)); +#endif +#endif + + /* Get the function to call, in the form of RTL. */ + if (fndecl) + /* Get a SYMBOL_REF rtx for the function address. */ + funexp = XEXP (DECL_RTL (fndecl), 0); + else + /* Generate an rtx (probably a pseudo-register) for the address. */ + { + funexp = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0); + emit_queue (); + } + + /* Now compute and store all non-register parms. + These come before register parms, since they can require block-moves, + which could clobber the registers used for register parms. + Parms which have partial registers are not stored here, + but we do preallocate space here if they want that. */ + + for (i = 0; i < num_actuals; i++) + { + /* Preallocate the stack space for a parm if appropriate + so it can be computed directly in the stack space. */ + if (args[i].stack != 0 && argblock != 0) + args[i].stack = target_for_arg (TREE_TYPE (args[i].tree_value), + ARGS_SIZE_RTX (args[i].size), + argblock, args[i].offset); + else + args[i].stack = 0; + + if (args[i].reg == 0 + && TYPE_SIZE (TREE_TYPE (args[i].tree_value)) != 0) + store_one_arg (&args[i], argblock, may_be_alloca); + } + + /* Now store any partially-in-registers parm. + This is the last place a block-move can happen. */ + if (reg_parm_seen) + for (i = 0; i < num_actuals; i++) + if (args[i].partial != 0) + store_one_arg (&args[i], argblock, may_be_alloca); + + if (protected_stack != 0) + adjust_stack (protected_stack); + +#ifndef PUSH_ARGS_REVERSED +#ifdef STACK_BOUNDARY + /* If we pushed args in forward order, perform stack alignment + after pushing the last arg. */ + if (argblock == 0 && stack_align > 0) + anti_adjust_stack (gen_rtx (CONST_INT, VOIDmode, stack_align)); +#endif +#endif + + /* If the function will be returning a structure, and if the address in + which to return the value isn't being passed as a parameter, pass it + now. This may result in a register move or in a push; if it's a push, + we count on the called routine to pop it. */ + if (structure_value_addr && ! structure_value_addr_parm) + emit_move_insn (struct_value_rtx, + force_reg (Pmode, force_operand (structure_value_addr, 0))); + + /* Now set up any wholly-register parms. They were computed already. */ + if (reg_parm_seen) + for (i = 0; i < num_actuals; i++) + if (args[i].reg != 0 && args[i].partial == 0) + store_one_arg (&args[i], argblock, may_be_alloca); + + /* Perform postincrements before actually calling the function. */ + emit_queue (); + + /* All arguments and registers used for the call must be set up by now! */ + + /* ??? Other languages need a nontrivial second argument (static chain). */ + funexp = prepare_call_address (funexp, 0); + + /* Mark all register-parms as living through the call. */ + start_sequence (); + for (i = 0; i < num_actuals; i++) + if (args[i].reg != 0) + { + if (args[i].partial > 0) + use_regs (REGNO (args[i].reg), args[i].partial); + else if (GET_MODE (args[i].reg) == BLKmode) + use_regs (REGNO (args[i].reg), + ((int_size_in_bytes (TREE_TYPE (args[i].tree_value)) + + UNITS_PER_WORD - 1) + / UNITS_PER_WORD)); + else + emit_insn (gen_rtx (USE, VOIDmode, args[i].reg)); + } + + if (structure_value_addr && ! structure_value_addr_parm + && GET_CODE (struct_value_rtx) == REG) + emit_insn (gen_rtx (USE, VOIDmode, struct_value_rtx)); + + use_insns = gen_sequence (); + end_sequence (); + + /* Figure out the register where the value, if any, will come back. */ + valreg = 0; + if (TYPE_MODE (TREE_TYPE (exp)) != VOIDmode + && ! structure_value_addr) + { + if (pcc_struct_value) + valreg = hard_libcall_value (Pmode); + else + valreg = hard_function_value (TREE_TYPE (exp), fndecl); + } + + /* Generate the actual call instruction. */ + /* This also has the effect of turning off any pop-inhibition + done in expand_call. */ + if (args_size.constant < 0) + args_size.constant = 0; + emit_call_1 (funexp, funtype, args_size.constant, + FUNCTION_ARG (args_so_far, VOIDmode, void_type_node, 1), + valreg, old_inhibit_defer_pop, use_insns); + +/* ??? Nothing has been done here to record control flow + when contained functions can do nonlocal gotos. */ + + /* For calls to `setjmp', etc., inform flow.c it should complain + if nonvolatile values are live. */ + + if (is_setjmp) + { + emit_note (IDENTIFIER_POINTER (DECL_NAME (fndecl)), NOTE_INSN_SETJMP); + current_function_calls_setjmp = 1; + } + + /* Notice functions that cannot return. + If optimizing, insns emitted below will be dead. + If not optimizing, they will exist, which is useful + if the user uses the `return' command in the debugger. */ + + if (fndecl && TREE_THIS_VOLATILE (fndecl)) + emit_barrier (); + + /* If this call is to be cse'd, then make sure it balances the stack. */ + if (is_const) + do_pending_stack_adjust (); + + /* For calls to __builtin_new, note that it can never return 0. + This is because a new handler will be called, and 0 it not + among the numbers it is supposed to return. */ +#if 0 + if (is_builtin_new) + emit_note (IDENTIFIER_POINTER (DECL_NAME (fndecl)), NOTE_INSN_BUILTIN_NEW); +#endif + + /* 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_of_this_call != old_cleanups + && target && REG_P (target) + && REGNO (target) < FIRST_PSEUDO_REGISTER) + target = 0; + + result_copy_insn = 0; + + if (TYPE_MODE (TREE_TYPE (exp)) == VOIDmode + || ignore) + { + target = const0_rtx; + } + else if (structure_value_addr) + { + if (target == 0 || GET_CODE (target) != MEM) + target = gen_rtx (MEM, TYPE_MODE (TREE_TYPE (exp)), + memory_address (BLKmode, structure_value_addr)); + } + else if (pcc_struct_value) + { + valreg = hard_function_value (build_pointer_type (TREE_TYPE (exp)), + fndecl); + if (target == 0) + target = gen_rtx (MEM, TYPE_MODE (TREE_TYPE (exp)), + copy_to_reg (valreg)); + else if (TYPE_MODE (TREE_TYPE (exp)) != BLKmode) + result_copy_insn + = 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); + } + else if (target && GET_MODE (target) == TYPE_MODE (TREE_TYPE (exp))) + { + if (GET_CODE (target) != REG && !cse_not_expected) + result_copy_insn = emit_move_insn (target, copy_to_reg (valreg)); + else if (!rtx_equal_p (target, valreg)) + result_copy_insn = emit_move_insn (target, valreg); + else + /* This tells expand_inline_function to copy valreg to its target. */ + emit_insn (gen_rtx (USE, VOIDmode, valreg)); + } + else + { + target = copy_to_reg (valreg); + result_copy_insn = get_last_insn (); + } + + /* Perform all cleanups needed for the arguments of this call + (i.e. destructors in C++). */ + while (cleanups_of_this_call != old_cleanups) + { + expand_expr (TREE_VALUE (cleanups_of_this_call), 0, VOIDmode, 0); + cleanups_of_this_call = TREE_CHAIN (cleanups_of_this_call); + } + + /* If we pushed this, pop it. */ + if (saved_structure_value_addr != 0) + pop_structure_value (saved_structure_value_addr, + saved_structure_value_size); + + /* If size of args is variable, restore saved stack-pointer value. */ + + if (old_stack_level) + { + emit_move_insn (stack_pointer_rtx, old_stack_level); + pending_stack_adjust = old_pending_adj; + } + + /* If call is cse'able, make appropriate pair of reg-notes around it. */ + if (is_const) + { + rtx insn_first = NEXT_INSN (insn_before); + rtx insn_last = get_last_insn (); + rtx note = 0; + + /* Don't put the notes on if we don't have insns that can hold them. */ + if ((GET_CODE (insn_first) == INSN + || GET_CODE (insn_first) == CALL_INSN + || GET_CODE (insn_first) == JUMP_INSN) + && (GET_CODE (insn_last) == INSN + || GET_CODE (insn_last) == CALL_INSN + || GET_CODE (insn_last) == JUMP_INSN) + && insn_last == result_copy_insn) + { + /* Construct an "equal form" for the value + which mentions all the arguments in order + as well as the function name. */ + for (i = 0; i < num_actuals; i++) + if (args[i].reg != 0 || is_const) + note = gen_rtx (EXPR_LIST, VOIDmode, args[i].value, note); + note = gen_rtx (EXPR_LIST, VOIDmode, + XEXP (DECL_RTL (fndecl), 0), note); + + REG_NOTES (insn_last) + = gen_rtx (EXPR_LIST, REG_EQUAL, note, + gen_rtx (INSN_LIST, REG_RETVAL, insn_first, + REG_NOTES (insn_last))); + REG_NOTES (insn_first) + = gen_rtx (INSN_LIST, REG_LIBCALL, insn_last, + REG_NOTES (insn_first)); + } + } + + return target; +} + +/* Return an rtx which represents a suitable home on the stack + given TYPE, the type of the argument looking for a home. + This is called only for BLKmode arguments. + + SIZE is the size needed for this target. + ARGS_ADDR is the address of the bottom of the argument block for this call. + OFFSET describes this parameter's offset into ARGS_ADDR. It is meaningless + if this machine uses push insns. */ + +static rtx +target_for_arg (type, size, args_addr, offset) + tree type; + rtx size; + rtx args_addr; + struct args_size offset; +{ + rtx target; + rtx offset_rtx = ARGS_SIZE_RTX (offset); + + /* We do not call memory_address if possible, + because we want to address as close to the stack + as possible. For non-variable sized arguments, + this will be stack-pointer relative addressing. */ + if (GET_CODE (offset_rtx) == CONST_INT) + target = plus_constant (args_addr, INTVAL (offset_rtx)); + else + { + /* 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 = memory_address (QImode, target); + } + + return gen_rtx (MEM, BLKmode, target); +} + +/* Store a single argument for a function call + into the register or memory area where it must be passed. + *ARG describes the argument value and where to pass it. + ARGBLOCK is the address of the stack-block for all the arguments, + or 0 on a machine where arguemnts are pushed individually. + MAY_BE_ALLOCA nonzero says this could be a call to `alloca' + so must be careful about how the stack is used. */ + +static void +store_one_arg (arg, argblock, may_be_alloca) + struct arg_data *arg; + rtx argblock; + int may_be_alloca; +{ + register tree pval = arg->tree_value; + int used = 0; + + if (TREE_CODE (pval) == ERROR_MARK) + return; + + if (arg->reg != 0 && arg->partial == 0) + { + /* Being passed entirely in a register. */ + if (arg->value != 0) + { + if (GET_MODE (arg->value) == BLKmode) + move_block_to_reg (REGNO (arg->reg), arg->value, + ((int_size_in_bytes (TREE_TYPE (pval)) + + UNITS_PER_WORD - 1) + / UNITS_PER_WORD)); + else + emit_move_insn (arg->reg, arg->value); + } + else + store_expr (pval, arg->reg, 0); + + /* Don't allow anything left on stack from computation + of argument to alloca. */ + if (may_be_alloca) + do_pending_stack_adjust (); + } + else if (TYPE_MODE (TREE_TYPE (pval)) != BLKmode) + { + register int size; + rtx tem; + + /* Argument is a scalar, not entirely passed in registers. + (If part is passed in registers, arg->partial says how much + and emit_push_insn will take care of putting it there.) + + Push it, and if its size is less than the + amount of space allocated to it, + also bump stack pointer by the additional space. + Note that in C the default argument promotions + will prevent such mismatches. */ + + size = GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (pval))); + /* Compute how much space the push instruction will push. + On many machines, pushing a byte will advance the stack + pointer by a halfword. */ +#ifdef PUSH_ROUNDING + size = PUSH_ROUNDING (size); +#endif + used = size; + + /* Compute how much space the argument should get: + round up to a multiple of the alignment for arguments. */ + if (none != FUNCTION_ARG_PADDING (TYPE_MODE (TREE_TYPE (pval)), const0_rtx)) + used = (((size + PARM_BOUNDARY / BITS_PER_UNIT - 1) + / (PARM_BOUNDARY / BITS_PER_UNIT)) + * (PARM_BOUNDARY / BITS_PER_UNIT)); + + tem = arg->value; + if (tem == 0) + { + tem = expand_expr (pval, 0, VOIDmode, 0); + /* ANSI doesn't require a sequence point here, + but PCC has one, so this will avoid some problems. */ + emit_queue (); + } + + /* Don't allow anything left on stack from computation + of argument to alloca. */ + if (may_be_alloca) + do_pending_stack_adjust (); + + emit_push_insn (tem, TYPE_MODE (TREE_TYPE (pval)), 0, 0, + arg->partial, arg->reg, used - size, + argblock, ARGS_SIZE_RTX (arg->offset)); + } + else if (arg->stack != 0) + { + /* BLKmode parm, not entirely passed in registers, + and with space already allocated. */ + + tree sizetree = size_in_bytes (TREE_TYPE (pval)); + /* Round the size up to multiple of PARM_BOUNDARY bits. */ + tree s1 = convert_units (sizetree, BITS_PER_UNIT, PARM_BOUNDARY); + tree s2 = convert_units (s1, PARM_BOUNDARY, BITS_PER_UNIT); + + /* Find out if the parm needs padding, and whether above or below. */ + enum direction where_pad + = FUNCTION_ARG_PADDING (TYPE_MODE (TREE_TYPE (pval)), + expand_expr (sizetree, 0, VOIDmode, 0)); + + /* If it is padded below, adjust the stack address + upward over the padding. */ + + if (where_pad == downward) + { + rtx offset_rtx; + rtx address = XEXP (arg->stack, 0); + struct args_size stack_offset; + + stack_offset.constant = 0; + stack_offset.var = 0; + + /* Compute amount of padding. */ + ADD_PARM_SIZE (stack_offset, s2); + SUB_PARM_SIZE (stack_offset, sizetree); + offset_rtx = ARGS_SIZE_RTX (stack_offset); + + /* Adjust the address to store at. */ + if (GET_CODE (offset_rtx) == CONST_INT) + address = plus_constant (address, INTVAL (offset_rtx)); + else + { + address = gen_rtx (PLUS, Pmode, address, offset_rtx); + address = memory_address (QImode, address); + } + arg->stack = change_address (arg->stack, VOIDmode, address); + } + + /* ARG->stack probably refers to the stack-pointer. If so, + stabilize it, in case stack-pointer changes during evaluation. */ + if (reg_mentioned_p (stack_pointer_rtx, arg->stack)) + arg->stack = change_address (arg->stack, VOIDmode, + copy_to_reg (XEXP (arg->stack, 0))); + /* BLKmode argument that should go in a prespecified stack location. */ + if (arg->value == 0) + /* Not yet computed => compute it there. */ + /* ??? This should be changed to tell expand_expr + that it can store directly in the target. */ + arg->value = store_expr (arg->tree_value, arg->stack, 0); + else if (arg->value != arg->stack) + /* It was computed somewhere, but not where we wanted. + For example, the value may have come from an official + local variable or parameter. In that case, expand_expr + does not fill our suggested target. */ + emit_block_move (arg->stack, arg->value, ARGS_SIZE_RTX (arg->size), + TYPE_ALIGN (TREE_TYPE (pval)) / BITS_PER_UNIT); + + /* Now, if this value wanted to be partly in registers, + move the value from the stack to the registers + that are supposed to hold the values. */ + if (arg->partial > 0) + move_block_to_reg (REGNO (arg->reg), arg->stack, arg->partial); + } + else + { + /* BLKmode, at least partly to be pushed. */ + + register rtx tem + = arg->value ? arg->value : expand_expr (pval, 0, VOIDmode, 0); + register int excess; + rtx size_rtx; + + /* Pushing a nonscalar. + If part is passed in registers, arg->partial says how much + and emit_push_insn will take care of putting it there. */ + + /* Round its size up to a multiple + of the allocation unit for arguments. */ + + if (arg->size.var != 0) + { + excess = 0; + size_rtx = ARGS_SIZE_RTX (arg->size); + } + else + { + register tree size = size_in_bytes (TREE_TYPE (pval)); + /* PUSH_ROUNDING has no effect on us, because + emit_push_insn for BLKmode is careful to avoid it. */ + excess = (arg->size.constant - TREE_INT_CST_LOW (size) + + arg->partial * UNITS_PER_WORD); + size_rtx = expand_expr (size, 0, VOIDmode, 0); + } + + if (arg->stack) + abort (); + + emit_push_insn (tem, TYPE_MODE (TREE_TYPE (pval)), size_rtx, + TYPE_ALIGN (TREE_TYPE (pval)) / BITS_PER_UNIT, + arg->partial, arg->reg, excess, argblock, + ARGS_SIZE_RTX (arg->offset)); + } + + /* Once we have pushed something, pops can't safely + be deferred during the rest of the arguments. */ + NO_DEFER_POP; +} + +/* Expand conditional expressions. */ + +/* Generate code to evaluate EXP and jump to LABEL if the value is zero. + LABEL is an rtx of code CODE_LABEL, in this function and all the + functions here. */ + +void +jumpifnot (exp, label) + tree exp; + rtx label; +{ + do_jump (exp, label, 0); +} + +/* Generate code to evaluate EXP and jump to LABEL if the value is nonzero. */ + +void +jumpif (exp, label) + tree exp; + rtx label; +{ + do_jump (exp, 0, label); +} + +/* Generate code to evaluate EXP and jump to IF_FALSE_LABEL if + the result is zero, or IF_TRUE_LABEL if the result is one. + Either of IF_FALSE_LABEL and IF_TRUE_LABEL may be zero, + meaning fall through in that case. + + This function is responsible for optimizing cases such as + &&, || and comparison operators in EXP. */ + +void +do_jump (exp, if_false_label, if_true_label) + tree exp; + rtx if_false_label, if_true_label; +{ + register enum tree_code code = TREE_CODE (exp); + /* Some cases need to create a label to jump to + in order to properly fall through. + These cases set DROP_THROUGH_LABEL nonzero. */ + rtx drop_through_label = 0; + rtx temp; + rtx comparison = 0; + + emit_queue (); + + switch (code) + { + case ERROR_MARK: + break; + + case INTEGER_CST: + temp = integer_zerop (exp) ? if_false_label : if_true_label; + if (temp) + emit_jump (temp); + break; + + case ADDR_EXPR: + /* The address of something can never be zero. */ + if (if_true_label) + emit_jump (if_true_label); + break; + + case NOP_EXPR: + do_jump (TREE_OPERAND (exp, 0), if_false_label, if_true_label); + break; + + case TRUTH_NOT_EXPR: + do_jump (TREE_OPERAND (exp, 0), if_true_label, if_false_label); + break; + + case TRUTH_ANDIF_EXPR: + if (if_false_label == 0) + if_false_label = drop_through_label = gen_label_rtx (); + do_jump (TREE_OPERAND (exp, 0), if_false_label, 0); + do_jump (TREE_OPERAND (exp, 1), if_false_label, if_true_label); + break; + + case TRUTH_ORIF_EXPR: + if (if_true_label == 0) + if_true_label = drop_through_label = gen_label_rtx (); + do_jump (TREE_OPERAND (exp, 0), 0, if_true_label); + do_jump (TREE_OPERAND (exp, 1), if_false_label, if_true_label); + break; + + case COMPOUND_EXPR: + expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode, 0); + emit_queue (); + do_jump (TREE_OPERAND (exp, 1), if_false_label, if_true_label); + break; + + case COND_EXPR: + { + register rtx label1 = gen_label_rtx (); + drop_through_label = gen_label_rtx (); + do_jump (TREE_OPERAND (exp, 0), label1, 0); + /* Now the THEN-expression. */ + do_jump (TREE_OPERAND (exp, 1), + if_false_label ? if_false_label : drop_through_label, + if_true_label ? if_true_label : drop_through_label); + 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); + } + break; + + case EQ_EXPR: + comparison = compare (exp, EQ, EQ, EQ, EQ); + break; + + case NE_EXPR: + comparison = compare (exp, NE, NE, NE, NE); + break; + + case LT_EXPR: + comparison = compare (exp, LT, LTU, GT, GTU); + break; + + case LE_EXPR: + comparison = compare (exp, LE, LEU, GE, GEU); + break; + + case GT_EXPR: + comparison = compare (exp, GT, GTU, LT, LTU); + break; + + case GE_EXPR: + comparison = compare (exp, GE, GEU, LE, LEU); + break; + + default: + temp = expand_expr (exp, 0, VOIDmode, 0); + /* Copy to register to avoid generating bad insns by cse + from (set (mem ...) (arithop)) (set (cc0) (mem ...)). */ + if (!cse_not_expected && GET_CODE (temp) == MEM) + temp = copy_to_reg (temp); + do_pending_stack_adjust (); + { + rtx zero = CONST0_RTX (GET_MODE (temp)); + + if (GET_CODE (temp) == CONST_INT) + comparison = compare_constants (NE, 0, + INTVAL (temp), 0, BITS_PER_WORD); + else if (GET_MODE (temp) != VOIDmode) + comparison = compare1 (temp, zero, NE, NE, 0, GET_MODE (temp)); + else + abort (); + } + } + + /* Do any postincrements in the expression that was tested. */ + emit_queue (); + + /* If COMPARISON is nonzero here, it is an rtx that can be substituted + straight into a conditional jump instruction as the jump condition. + Otherwise, all the work has been done already. */ + + if (comparison == const1_rtx) + { + if (if_true_label) + emit_jump (if_true_label); + } + else if (comparison == const0_rtx) + { + if (if_false_label) + emit_jump (if_false_label); + } + else if (comparison) + { + if (if_true_label) + { + if (bcc_gen_fctn[(int) GET_CODE (comparison)] != 0) + emit_jump_insn ((*bcc_gen_fctn[(int) GET_CODE (comparison)]) (if_true_label)); + else + abort (); + + if (if_false_label) + emit_jump (if_false_label); + } + else if (if_false_label) + { + rtx pat; + + if (bcc_gen_fctn[(int) GET_CODE (comparison)] == 0) + abort (); + + pat = (*bcc_gen_fctn[(int) GET_CODE (comparison)]) (if_false_label); + /* Now invert the sense of the jump by exchanging the two arms + of each IF_THEN_ELSE. Note that inverting the condition + would be incorrect for IEEE floating point with nans! */ + if (GET_CODE (pat) == SEQUENCE) + { + int i; + /* We can invert a sequence if the only jump is at the end. */ + for (i = 0; i < (int) (XVECLEN (pat, 0) - 1); i++) + if (GET_CODE (XVECEXP (pat, 0, i)) == JUMP_INSN) + abort (); + invert_exp (PATTERN (XVECEXP (pat, 0, XVECLEN (pat, 0) - 1)), + 0, 0); + } + else + invert_exp (pat, 0, 0); + + emit_jump_insn (pat); + } + } + + if (drop_through_label) + emit_label (drop_through_label); +} + +/* Compare two integer constant rtx's, OP0 and OP1. + The comparison operation is OPERATION. + Return an rtx representing the value 1 or 0. + WIDTH is the width in bits that is significant. */ + +static rtx +compare_constants (operation, unsignedp, op0, op1, width) + enum rtx_code operation; + int unsignedp; + int op0, op1; + int width; +{ + int val; + + /* Sign-extend or zero-extend the operands to a full word + from an initial width of WIDTH bits. */ + if (width < HOST_BITS_PER_INT) + { + op0 &= (1 << width) - 1; + op1 &= (1 << width) - 1; + + if (! unsignedp) + { + if (op0 & (1 << (width - 1))) + op0 |= ((-1) << width); + if (op1 & (1 << (width - 1))) + op1 |= ((-1) << width); + } + } + + switch (operation) + { + case EQ: + val = op0 == op1; + break; + + case NE: + val = op0 != op1; + break; + + case GT: + case GTU: + val = op0 > op1; + break; + + case LT: + case LTU: + val = op0 < op1; + break; + + case GE: + case GEU: + val = op0 >= op1; + break; + + case LE: + case LEU: + val = op0 <= op1; + } + + return val ? const1_rtx : const0_rtx; +} + +/* Generate code for a comparison expression EXP + (including code to compute the values to be compared) + and set (CC0) according to the result. + SIGNED_FORWARD should be the rtx operation for this comparison for + signed data; UNSIGNED_FORWARD, likewise for use if data is unsigned. + SIGNED_REVERSE and UNSIGNED_REVERSE are used if it is desirable + to interchange the operands for the compare instruction. + + We force a stack adjustment unless there are currently + things pushed on the stack that aren't yet used. */ + +static rtx +compare (exp, signed_forward, unsigned_forward, + signed_reverse, unsigned_reverse) + register tree exp; + enum rtx_code signed_forward, unsigned_forward; + enum rtx_code signed_reverse, unsigned_reverse; +{ + + register rtx op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0); + register rtx op1 = expand_expr (TREE_OPERAND (exp, 1), 0, VOIDmode, 0); + register enum machine_mode mode = GET_MODE (op0); + int unsignedp; + + /* If one operand is 0, make it the second one. */ + + if (op0 == const0_rtx + || (GET_MODE_CLASS (mode) == MODE_FLOAT && op0 == CONST0_RTX (mode))) + { + rtx tem = op0; + op0 = op1; + op1 = tem; + signed_forward = signed_reverse; + unsigned_forward = unsigned_reverse; + } + + if (flag_force_mem) + { + op0 = force_not_mem (op0); + op1 = force_not_mem (op1); + } + + do_pending_stack_adjust (); + + unsignedp = (TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0))) + || TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 1)))); + + if (GET_CODE (op0) == CONST_INT && GET_CODE (op1) == CONST_INT) + return compare_constants (signed_forward, unsignedp, + INTVAL (op0), INTVAL (op1), + GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))))); + + emit_cmp_insn (op0, op1, + (mode == BLKmode) ? expr_size (TREE_OPERAND (exp, 0)) : 0, + unsignedp, + TYPE_ALIGN (TREE_TYPE (exp)) / BITS_PER_UNIT); + + return gen_rtx ((unsignedp ? unsigned_forward : signed_forward), + VOIDmode, cc0_rtx, const0_rtx); +} + +/* Like compare but expects the values to compare as two rtx's. + The decision as to signed or unsigned comparison must be made by the caller. + BLKmode is not allowed. */ + +static rtx +compare1 (op0, op1, forward_op, reverse_op, unsignedp, mode) + register rtx op0, op1; + enum rtx_code forward_op, reverse_op; + int unsignedp; + enum machine_mode mode; +{ + /* If one operand is 0, make it the second one. */ + + if (op0 == const0_rtx + || (GET_MODE_CLASS (mode) == MODE_FLOAT && op0 == CONST0_RTX (mode))) + { + rtx tem = op0; + op0 = op1; + op1 = tem; + forward_op = reverse_op; + } + + if (flag_force_mem) + { + op0 = force_not_mem (op0); + op1 = force_not_mem (op1); + } + + do_pending_stack_adjust (); + + if (GET_CODE (op0) == CONST_INT && GET_CODE (op1) == CONST_INT) + return compare_constants (forward_op, unsignedp, + INTVAL (op0), INTVAL (op1), + GET_MODE_BITSIZE (mode)); + + emit_cmp_insn (op0, op1, 0, unsignedp, 0); + + return gen_rtx (forward_op, VOIDmode, cc0_rtx, const0_rtx); +} + +/* Generate code to calculate EXP using a store-flag instruction + and return an rtx for the result. + If TARGET is nonzero, store the result there if convenient. + + Return zero if there is no suitable set-flag instruction + available on this machine. */ + +static rtx +do_store_flag (exp, target, mode) + tree exp; + rtx target; + enum machine_mode mode; +{ + register enum tree_code code = TREE_CODE (exp); + register rtx comparison = 0; + enum machine_mode compare_mode; + rtx prev_insn = get_last_insn (); + enum insn_code icode; + + switch (code) + { +#ifdef HAVE_seq + case EQ_EXPR: + if (HAVE_seq) + { + comparison = compare (exp, EQ, EQ, EQ, EQ); + icode = CODE_FOR_seq; + compare_mode = insn_operand_mode[(int) CODE_FOR_seq][0]; + } + break; +#endif + +#ifdef HAVE_sne + case NE_EXPR: + if (HAVE_sne) + { + comparison = compare (exp, NE, NE, NE, NE); + icode = CODE_FOR_sne; + compare_mode = insn_operand_mode[(int) CODE_FOR_sne][0]; + } + break; +#endif + +#if defined (HAVE_slt) && defined (HAVE_sltu) && defined (HAVE_sgt) && defined (HAVE_sgtu) + case LT_EXPR: + if (HAVE_slt && HAVE_sltu && HAVE_sgt && HAVE_sgtu) + { + comparison = compare (exp, LT, LTU, GT, GTU); + icode = CODE_FOR_slt; + compare_mode = insn_operand_mode[(int) CODE_FOR_slt][0]; + } + break; + + case GT_EXPR: + if (HAVE_slt && HAVE_sltu && HAVE_sgt && HAVE_sgtu) + { + comparison = compare (exp, GT, GTU, LT, LTU); + icode = CODE_FOR_slt; + compare_mode = insn_operand_mode[(int) CODE_FOR_slt][0]; + } + break; +#endif + +#if defined (HAVE_sle) && defined (HAVE_sleu) && defined (HAVE_sge) && defined (HAVE_sgeu) + case LE_EXPR: + if (HAVE_sle && HAVE_sleu && HAVE_sge && HAVE_sgeu) + { + comparison = compare (exp, LE, LEU, GE, GEU); + icode = CODE_FOR_sle; + compare_mode = insn_operand_mode[(int) CODE_FOR_sle][0]; + } + break; + + case GE_EXPR: + if (HAVE_sle && HAVE_sleu && HAVE_sge && HAVE_sgeu) + { + comparison = compare (exp, GE, GEU, LE, LEU); + icode = CODE_FOR_sle; + compare_mode = insn_operand_mode[(int) CODE_FOR_sle][0]; + } + break; +#endif + } + if (comparison == 0) + return 0; + + if (target == 0 || GET_MODE (target) != mode + /* Don't use specified target unless the insn can handle it. */ + || ! (*insn_operand_predicate[(int) icode][0]) (target, mode) + /* When modes don't match, don't use specified target, + because it might be the same as an operand, + and then the CLOBBER output below would screw up. */ + || (mode != compare_mode && GET_CODE (comparison) != CONST_INT)) + target = gen_reg_rtx (mode); + + /* Store the comparison in its proper mode. */ + if (GET_CODE (comparison) == CONST_INT) + emit_move_insn (target, comparison); + else if (GET_MODE (target) != compare_mode) + { + /* We want a different mode: store result in its natural mode. + Combine the mode conversion with the truncation we must do anyway. */ + /* Put a CLOBBER before the compare, so we don't come between + the compare and the insn that uses the result. */ + emit_insn_after (gen_rtx (CLOBBER, VOIDmode, target), prev_insn); + emit_insn ((*setcc_gen_fctn[(int) GET_CODE (comparison)]) + (gen_rtx (SUBREG, compare_mode, target, 0))); + /* If the desired mode is wider than what we got, + use an AND to convert it, but not if we will do one anyway. */ +#if STORE_FLAG_VALUE == 1 + if (GET_MODE_SIZE (mode) > GET_MODE_SIZE (compare_mode)) + expand_bit_and (mode, target, const1_rtx, target); +#endif + } + else + emit_insn ((*setcc_gen_fctn[(int) GET_CODE (comparison)]) (target)); + +#if STORE_FLAG_VALUE != 1 +#if STORE_FLAG_VALUE & 1 + expand_bit_and (mode, target, const1_rtx, target); +#else + expand_shift (RSHIFT_EXPR, mode, target, + build_int_2 (GET_MODE_BITSIZE (mode) - 1, 0), + target, TRUE); +#endif +#endif + return target; +} + +/* Generate a tablejump instruction (used for switch statements). */ + +#ifdef HAVE_tablejump + +/* INDEX is the value being switched on, with the lowest value + in the table already subtracted. + RANGE is the length of the jump table. + TABLE_LABEL is a CODE_LABEL rtx for the table itself. + + DEFAULT_LABEL is a CODE_LABEL rtx to jump to if the + index value is out of range. */ + +void +do_tablejump (index, range, table_label, default_label) + rtx index, range, table_label, default_label; +{ + register rtx temp; + + emit_cmp_insn (range, index, 0, 0, 0); + emit_jump_insn (gen_bltu (default_label)); + /* If flag_force_addr were to affect this address + it could interfere with the tricky assumptions made + about addresses that contain label-refs, + which may be valid only very near the tablejump itself. */ + index = memory_address_noforce + (CASE_VECTOR_MODE, + gen_rtx (PLUS, Pmode, + gen_rtx (MULT, Pmode, index, + gen_rtx (CONST_INT, VOIDmode, + GET_MODE_SIZE (CASE_VECTOR_MODE))), + gen_rtx (LABEL_REF, VOIDmode, table_label))); + temp = gen_reg_rtx (CASE_VECTOR_MODE); + convert_move (temp, gen_rtx (MEM, CASE_VECTOR_MODE, index), 0); + + emit_jump_insn (gen_tablejump (temp, table_label)); +} + +#endif /* HAVE_tablejump */ diff --git a/gcc-1.40/expr.h b/gcc-1.40/expr.h new file mode 100644 index 0000000..3cc495c --- /dev/null +++ b/gcc-1.40/expr.h @@ -0,0 +1,386 @@ +/* Definitions for code generation pass of GNU compiler. + Copyright (C) 1987 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 1, 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. */ + + +/* Macros to access the slots of a QUEUED rtx. + Here rather than in rtl.h because only the expansion pass + should ever encounter a QUEUED. */ + +/* 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. */ +#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. */ +#define QUEUED_COPY(P) XEXP (P, 2) +/* This is the body to use for the insn to do the increment. + It is used to emit the increment. */ +#define QUEUED_BODY(P) XEXP (P, 3) +/* Next QUEUED in the queue. */ +#define QUEUED_NEXT(P) XEXP (P, 4) + +/* This is the 4th arg to `expand_expr'. + EXPAND_SUM means it is ok to return a PLUS rtx or MULT rtx. + EXPND_CONST_ADDRESS means it is ok to return a MEM whose address + is a constant that is not a legitimate address. */ +enum expand_modifier {EXPAND_NORMAL, EXPAND_SUM, EXPAND_CONST_ADDRESS}; + +/* 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 + indirect addresses so a useful potential cse is generated; + if it is used only once, instruction combination will produce + the same indirect address eventually. */ +extern int cse_not_expected; + +/* 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 stupid. */ +extern rtx save_expr_regs; + +extern int current_function_calls_alloca; + +/* This is the offset from the arg pointer to the place where the first + anonymous arg can be found, if there is one. */ +extern rtx current_function_arg_offset_rtx; + +/* Nonzero means stack pops must not be deferred, and deferred stack + pops must not be output. It is nonzero inside a function call, + inside a conditional expression, inside a statement expression, + and in other cases as well. */ +extern int inhibit_defer_pop; + +#define NO_DEFER_POP (inhibit_defer_pop += 1) +#define OK_DEFER_POP (inhibit_defer_pop -= 1) + +#ifdef TREE_CODE /* Don't lose if tree.h not included. */ +/* Structure to record the size of a sequence of arguments + as the sum of a tree-expression and a constant. */ + +struct args_size +{ + int constant; + tree var; +}; +#endif + +/* Add the value of the tree INC to the `struct args_size' TO. */ + +#define ADD_PARM_SIZE(TO, INC) \ +{ tree inc = (INC); \ + if (TREE_CODE (inc) == INTEGER_CST) \ + (TO).constant += TREE_INT_CST_LOW (inc); \ + else if ((TO).var == 0) \ + (TO).var = inc; \ + else \ + (TO).var = genop (PLUS_EXPR, (TO).var, inc); } + +#define SUB_PARM_SIZE(TO, DEC) \ +{ tree dec = (DEC); \ + if (TREE_CODE (dec) == INTEGER_CST) \ + (TO).constant -= TREE_INT_CST_LOW (dec); \ + else if ((TO).var == 0) \ + (TO).var = genop (MINUS_EXPR, integer_zero_node, dec); \ + else \ + (TO).var = genop (MINUS_EXPR, (TO).var, dec); } + +/* Convert the implicit sum in a `struct args_size' into an rtx. */ +#define ARGS_SIZE_RTX(SIZE) \ +((SIZE).var == 0 ? gen_rtx (CONST_INT, VOIDmode, (SIZE).constant) \ + : plus_constant (expand_expr ((SIZE).var, 0, VOIDmode, 0), \ + (SIZE).constant)) + +/* Supply a default definition for FUNCTION_ARG_PADDING: + usually pad upward, but pad short args downward on big-endian machines. */ + +enum direction {none, upward, downward}; /* Value has this type. */ + +#ifndef FUNCTION_ARG_PADDING +#ifdef BYTES_BIG_ENDIAN +#define FUNCTION_ARG_PADDING(mode, size) \ + (((mode) == BLKmode \ + ? (GET_CODE (size) == CONST_INT \ + && INTVAL (size) < PARM_BOUNDARY / BITS_PER_UNIT) \ + : GET_MODE_BITSIZE (mode) < PARM_BOUNDARY) \ + ? downward : upward) +#else +#define FUNCTION_ARG_PADDING(mode, size) upward +#endif +#endif + +/* Nonzero if type TYPE should be returned in memory + (even though its mode is not BLKmode). + Most machines can use the following default definition. */ + +#ifndef RETURN_IN_MEMORY +#define RETURN_IN_MEMORY(type) 0 +#endif + +/* Optabs are tables saying how to generate insn bodies + for various machine modes and numbers of operands. + Each optab applies to one operation. + For example, add_optab applies to addition. + + The insn_code slot is the enum insn_code that says how to + generate an insn for this operation on a particular machine mode. + It is CODE_FOR_nothing if there is no such insn on the target machine. + + The `lib_call' slot is the name of the library function that + can be used to perform the operation. + + A few optabs, such as move_optab and cmp_optab, are used + by special code. */ + +/* Everything that uses expr.h needs to define enum insn_code + but we don't list it in the Makefile dependencies just for that. */ +#include "insn-codes.h" + +typedef struct optab +{ + enum rtx_code code; + struct { + enum insn_code insn_code; + char *lib_call; + } handlers [NUM_MACHINE_MODES]; +} * optab; + +/* Given an enum insn_code, access the function to construct + the body of that kind of insn. */ +#define GEN_FCN(CODE) (*insn_gen_function[(int) (CODE)]) +extern rtx (*insn_gen_function[]) (); + +extern optab add_optab; +extern optab sub_optab; +extern optab smul_optab; /* Signed multiply */ +extern optab umul_optab; /* Unsigned multiply */ +extern optab smul_widen_optab; /* Signed multiply with result + one machine mode wider than args */ +extern optab umul_widen_optab; +extern optab sdiv_optab; /* Signed divide */ +extern optab sdivmod_optab; /* Signed divide-and-remainder in one */ +extern optab udiv_optab; +extern optab udivmod_optab; +extern optab smod_optab; /* Signed remainder */ +extern optab umod_optab; +extern optab flodiv_optab; /* Optab for floating divide. */ +extern optab ftrunc_optab; /* Convert float to integer in float fmt */ +extern optab and_optab; /* Logical and */ +extern optab andcb_optab; /* Logical and with complement of 2nd arg */ +extern optab ior_optab; /* Logical or */ +extern optab xor_optab; /* Logical xor */ +extern optab ashl_optab; /* Arithmetic shift left */ +extern optab ashr_optab; /* Arithmetic shift right */ +extern optab lshl_optab; /* Logical shift left */ +extern optab lshr_optab; /* Logical shift right */ +extern optab rotl_optab; /* Rotate left */ +extern optab rotr_optab; /* Rotate right */ + +extern optab mov_optab; /* Move instruction. */ +extern optab movstrict_optab; /* Move, preserving high part of register. */ + +extern optab cmp_optab; /* Compare insn; two operands. */ +extern optab tst_optab; /* tst insn; compare one operand against 0 */ + +/* Unary operations */ +extern optab neg_optab; /* Negation */ +extern optab abs_optab; /* Abs value */ +extern optab one_cmpl_optab; /* Bitwise not */ +extern optab ffs_optab; /* Find first bit set */ + +/* Passed to expand_binop and expand_unop to say which options to try to use + if the requested operation can't be open-coded on the requisite mode. + Either OPTAB_LIB or OPTAB_LIB_WIDEN says try using a library call. + Either OPTAB_WIDEN or OPTAB_LIB_WIDEN says try using a wider mode. + OPTAB_MUST_WIDEN says try widening and don't try anything else. */ + +enum optab_methods +{ + OPTAB_DIRECT, + OPTAB_LIB, + OPTAB_WIDEN, + OPTAB_LIB_WIDEN, + OPTAB_MUST_WIDEN +}; + +typedef rtx (*rtxfun) (); + +/* Indexed by the rtx-code for a conditional (eg. EQ, LT,...) + gives the gen_function to make a branch to test that condition. */ + +extern rtxfun bcc_gen_fctn[NUM_RTX_CODE]; + +/* Indexed by the rtx-code for a conditional (eg. EQ, LT,...) + gives the gen_function to make a store-condition insn + to test that condition. */ + +extern rtxfun setcc_gen_fctn[NUM_RTX_CODE]; + +/* Expand a binary operation given optab and rtx operands. */ +rtx expand_binop (); + +/* Expand a binary operation with both signed and unsigned forms. */ +rtx sign_expand_binop (); + +/* Expand a unary arithmetic operation given optab rtx operand. */ +rtx expand_unop (); + +/* Arguments MODE, RTX: return an rtx for the negation of that value. + May emit insns. */ +rtx negate_rtx (); + +/* Initialize the tables that control conversion between fixed and + floating values. */ +void init_fixtab (); +void init_floattab (); + +/* Generate code for a FIX_EXPR. */ +void expand_fix (); + +/* Generate code for a FLOAT_EXPR. */ +void expand_float (); + +/* Create but don't emit one rtl instruction to add one rtx into another. + Modes must match. + Likewise for subtraction and for just copying. + These do not call protect_from_queue; caller must do so. */ +rtx gen_add2_insn (); +rtx gen_sub2_insn (); +rtx gen_move_insn (); + +/* Emit one rtl instruction to store zero in specified rtx. */ +void emit_clr_insn (); + +/* Emit one rtl insn to store 1 in specified rtx assuming it contains 0. */ +void emit_0_to_1_insn (); + +/* Emit one rtl insn to compare two rtx's. */ +void emit_cmp_insn (); + +/* Emit some rtl insns to move data between rtx's, converting machine modes. + Both modes must be floating or both fixed. */ +void convert_move (); + +/* Convert an rtx to specified machine mode and return the result. */ +rtx convert_to_mode (); + +/* Emit code to push some arguments and call a library routine, + storing the value in a specified place. Calling sequence is + complicated. */ +void emit_library_call (); + +/* Given an rtx that may include add and multiply operations, + generate them as insns and return a pseudo-reg containing the value. + Useful after calling expand_expr with 1 as sum_ok. */ +rtx force_operand (); + +/* Return an rtx for the size in bytes of the value of an expr. */ +rtx expr_size (); + +/* Return an rtx for the sum of an rtx and an integer. */ +rtx plus_constant (); + +rtx lookup_static_chain (); + +/* Return an rtx like arg but sans any constant terms. + Returns the original rtx if it has no constant terms. + The constant terms are added and stored via a second arg. */ +rtx eliminate_constant_term (); + +/* Convert arg to a valid memory address for specified machine mode, + by emitting insns to perform arithmetic if nec. */ +rtx memory_address (); + +/* Like `memory_address' but pretent `flag_force_addr' is 0. */ +rtx memory_address_noforce (); + +/* Return a memory reference like MEMREF, but with its mode changed + to MODE and its address changed to ADDR. + (VOIDmode means don't change the mode. + NULL for ADDR means don't change the address.) */ +rtx change_address (); + +/* Return 1 if two rtx's are equivalent in structure and elements. */ +int rtx_equal_p (); + +/* Given rtx, return new rtx whose address won't be affected by + any side effects. It has been copied to a new temporary reg. */ +rtx stabilize (); + +/* Given an rtx, copy all regs it refers to into new temps + and return a modified copy that refers to the new temps. */ +rtx copy_all_regs (); + +/* Copy given rtx to a new temp reg and return that. */ +rtx copy_to_reg (); + +/* Like copy_to_reg but always make the reg Pmode. */ +rtx copy_addr_to_reg (); + +/* Like copy_to_reg but always make the reg the specified mode MODE. */ +rtx copy_to_mode_reg (); + +/* Copy given rtx to given temp reg and return that. */ +rtx copy_to_suggested_reg (); + +/* Copy a value to a register if it isn't already a register. + Args are mode (in case value is a constant) and the value. */ +rtx force_reg (); + +/* Return given rtx, copied into a new temp reg if it was in memory. */ +rtx force_not_mem (); + +/* Remove some bytes from the stack. An rtx says how many. */ +void adjust_stack (); + +/* Add some bytes to the stack. An rtx says how many. */ +void anti_adjust_stack (); + +/* Emit code to copy function value to a new temp reg and return that reg. */ +rtx function_value (); + +/* Return an rtx that refers to the value returned by a function + in its original home. This becomes invalid if any more code is emitted. */ +rtx hard_function_value (); + +/* 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. */ +rtx hard_libcall_value (); + +/* Emit code to copy function value to a specified place. */ +void copy_function_value (); + +/* Given an rtx, return an rtx for a value rounded up to a multiple + of STACK_BOUNDARY / BITS_PER_UNIT. */ +rtx round_push (); + +rtx store_bit_field (); +rtx extract_bit_field (); +rtx expand_shift (); +rtx expand_bit_and (); +rtx expand_mult (); +rtx expand_divmod (); +rtx expand_mult_add (); +rtx get_structure_value_addr (); +rtx expand_stmt_expr (); + +void jumpifnot (); +void jumpif (); +void do_jump (); + +rtx assemble_static_space (); diff --git a/gcc-1.40/final.c b/gcc-1.40/final.c new file mode 100644 index 0000000..f3527f4 --- /dev/null +++ b/gcc-1.40/final.c @@ -0,0 +1,1652 @@ +/* Convert RTL to assembler code and output it, for GNU compiler. + Copyright (C) 1987, 1988, 1989 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 1, 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 is the final pass of the compiler. + It looks at the rtl code for a function and outputs assembler code. + + Call `final_start_function' to output the assembler code for function entry, + `final' to output assembler code for some RTL code, + `final_end_function' to output assembler code for function exit. + If a function is compiled in several pieces, each piece is + output separately with `final'. + + Some optimizations are also done at this level. + Move instructions that were made unnecessary by good register allocation + are detected and omitted from the output. (Though most of these + are removed by the last jump pass.) + + Instructions to set the condition codes are omitted when it can be + seen that the condition codes already had the desired values. + + In some cases it is sufficient if the inherited condition codes + have related values, but this may require the following insn + (the one that tests the condition codes) to be modified. + + The code for the function prologue and epilogue are generated + directly as assembler code by the macros FUNCTION_PROLOGUE and + FUNCTION_EPILOGUE. Those instructions never exist as rtl. */ + +#include +#include "config.h" +#include "rtl.h" +#include "regs.h" +#include "insn-config.h" +#include "recog.h" +#include "conditions.h" +#include "gdbfiles.h" +#include "flags.h" +#include "real.h" +#include "output.h" + +/* Get N_SLINE and N_SOL from stab.h if we can expect the file to exist. */ +#ifdef DBX_DEBUGGING_INFO +#ifdef USG +#include "gstab.h" /* If doing DBX on sysV, use our own stab.h. */ +#else +#include /* On BSD, use the system's stab.h. */ +#endif /* not USG */ +#endif /* DBX_DEBUGGING_INFO */ + +/* .stabd code for line number. */ +#ifndef N_SLINE +#define N_SLINE 0x44 +#endif + +/* .stabs code for included file name. */ +#ifndef N_SOL +#define N_SOL 0x84 +#endif + +#define min(A,B) ((A) < (B) ? (A) : (B)) + +rtx peephole (); +void output_asm_insn (); +rtx alter_subreg (); +static int alter_cond (); +void output_asm_label (); +static void output_operand (); +void output_address (); +void output_addr_const (); +static void output_source_line (); +rtx final_scan_insn (); + +/* the sdb debugger needs the line given as an offset from the beginning + of the current function -wfs*/ + +extern int sdb_begin_function_line; + +/* Line number of last NOTE. */ +static int last_linenum; + +/* Number of basic blocks seen so far; + used if profile_block_flag is set. */ +static int count_basic_blocks; + +/* 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; + +/* File in which assembler code is being written. */ + +extern FILE *asm_out_file; + +/* Compare optimization flag. */ + +static rtx last_ignored_compare = 0; + +/* Flag indicating this insn is the start of a new basic block. */ + +static int new_block = 1; + +/* All the symbol-blocks (levels of scoping) in the compilation + are assigned sequence numbers in order of appearance of the + beginnings of the symbol-blocks. Both final and dbxout do this, + and assume that they will both give the same number to each block. + Final uses these sequence numbers to generate assembler label names + LBBnnn and LBEnnn for the beginning and end of the symbol-block. + Dbxout uses the sequence nunbers to generate references to the same labels + from the dbx debugging information. + + Sdb records this level at the beginning + of each function, so that when it recurses down the declarations, it may + find the current level, since it outputs the block beginning and endings + at the point in the asm file, where the blocks would begin and end. */ + +int next_block_index; + +/* Chain of all `struct gdbfile's. */ + +struct gdbfile *gdbfiles; + +/* `struct gdbfile' for the last file we wrote a line number for. */ + +static struct gdbfile *current_gdbfile; + +/* Filenum to assign to the next distinct source file encountered. */ + +static int next_gdb_filenum; + +/* This variable contains machine-dependent flags (defined in tm-...h) + set and examined by output routines + that describe how to interpret the condition codes properly. */ + +CC_STATUS cc_status; + +/* During output of an insn, this contains a copy of cc_status + from before the insn. */ + +CC_STATUS cc_prev_status; + +/* Last source file name mentioned in a NOTE insn. */ + +static char *lastfile; + +/* Indexed by hardware reg number, is 1 if that register is ever + used in the current function. + + In life_analysis, or in stupid_life_analysis, this is set + up to record the hard regs used explicitly. Reload adds + in the hard regs used for holding pseudo regs. Final uses + it to generate the code in the function prologue and epilogue + to save and restore registers as needed. */ + +char regs_ever_live[FIRST_PSEUDO_REGISTER]; + +/* Nonzero means current function must be given a frame pointer. + Set in stmt.c if anything is allocated on the stack there. + Set in reload1.c if anything is allocated on the stack there. */ + +int frame_pointer_needed; + +/* Assign unique numbers to labels generated for profiling. */ + +int profile_label_no; + +/* Length so far allocated in PENDING_BLOCKS. */ + +static int max_block_depth; + +/* Stack of sequence numbers of symbol-blocks of which we have seen the + beginning but not yet the end. Sequence numbers are assigned at + the beginning; this stack allows us to find the sequence number + of a block that is ending. */ + +static int *pending_blocks; + +/* Number of elements currently in use in PENDING_BLOCKS. */ + +static int block_depth; + +/* Nonzero if have enabled APP processing of our assembler output. */ + +static int app_on; + +/* If we are outputting an insn sequence, this contains the sequence rtx. + Zero otherwise. */ + +rtx final_sequence; + +/* Initialize data in final at the beginning of a compilation. */ + +void +init_final (filename) + char *filename; +{ + next_block_index = 2; + lastfile = filename; + app_on = 0; + max_block_depth = 20; + pending_blocks = (int *) xmalloc (20 * sizeof *pending_blocks); + gdbfiles = 0; + next_gdb_filenum = 0; + final_sequence = 0; +} + +/* Called at end of source file, + to output the block-profiling table for this entire compilation. */ + +void +end_final (filename) + char *filename; +{ + int i; + + if (profile_block_flag) + { + char name[12]; + + data_section (); + + /* Output the main header, of 6 words: + 0: 1 if this file's initialized, else 0. + 1: address of file name. + 2: address of table of counts. + 4: number of counts in the table. + 5: always 0, for compatibility with Sun. + 6: extra word added by GNU: address of address table + which contains addresses of basic blocks, + in parallel with the table of counts. */ + ASM_OUTPUT_ALIGN (asm_out_file, + exact_log2 (min (UNITS_PER_WORD, + BIGGEST_ALIGNMENT / BITS_PER_UNIT))); + + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 0); + assemble_integer_zero (); + + ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 1); + ASM_OUTPUT_INT (asm_out_file, gen_rtx (SYMBOL_REF, Pmode, name)); + ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 2); + ASM_OUTPUT_INT (asm_out_file, gen_rtx (SYMBOL_REF, Pmode, name)); + ASM_OUTPUT_INT (asm_out_file, gen_rtx (CONST_INT, VOIDmode, + count_basic_blocks)); + assemble_integer_zero (); + ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 3); + ASM_OUTPUT_INT (asm_out_file, gen_rtx (SYMBOL_REF, Pmode, name)); + + /* Output the file name. */ + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 1); + { + int len = strlen (filename); + char *data_file = (char *) alloca (len + 3); + strcpy (data_file, filename); + if (len > 2 && ! strcmp (".c", data_file + len - 2)) + data_file[len - 2] = 0; + else if (len > 2 && ! strcmp (".i", data_file + len - 2)) + data_file[len - 2] = 0; + else if (len > 3 && ! strcmp (".co", data_file + len - 3)) + data_file[len - 3] = 0; + strcat (data_file, ".d"); + assemble_string (data_file, strlen (data_file) + 1); + } + + /* Realign data section. */ + ASM_OUTPUT_ALIGN (asm_out_file, + exact_log2 (min (UNITS_PER_WORD, + BIGGEST_ALIGNMENT / BITS_PER_UNIT))); + + /* Make space for the table of counts. */ + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 2); + ASM_OUTPUT_SKIP (asm_out_file, UNITS_PER_WORD * count_basic_blocks); + + /* Output the table of addresses. */ + text_section (); + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 3); + for (i = 0; i < count_basic_blocks; i++) + { + char name[12]; + ASM_GENERATE_INTERNAL_LABEL (name, "LPB", i); + ASM_OUTPUT_INT (asm_out_file, gen_rtx (SYMBOL_REF, Pmode, name)); + } + + /* 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); + ASM_OUTPUT_INT (asm_out_file, gen_rtx (SYMBOL_REF, Pmode, name)); + } +} + +/* Enable APP processing of subsequent output. + Used before the output from an `asm' statement. */ + +void +app_enable () +{ + if (! app_on) + { + fprintf (asm_out_file, ASM_APP_ON); + app_on = 1; + } +} + +/* Enable APP processing of subsequent output. + Called from varasm.c before most kinds of output. */ + +void +app_disable () +{ + if (app_on) + { + fprintf (asm_out_file, ASM_APP_OFF); + app_on = 0; + } +} + +/* Return the number of slots filled in the current + delayed branch sequence. */ + +#ifdef HAVE_DELAYED_BRANCH +int +dbr_sequence_length () +{ + int i; + int slots = 0; + /* It's zero if we are not scheduling or not in a sequence. + (We never count the first insn.) */ + if (flag_delayed_branch && final_sequence != 0) + { + for (i = 1; i < XVECLEN (final_sequence, 0); i++) + slots += DBR_INSN_SLOTS (XVECEXP (final_sequence, 0, i)); + } + return slots; +} +#endif + +/* Output assembler code for the start of a function, + and initialize some of the variables in this file + for the new function. The label for the function and associated + assembler pseudo-ops have already been output in `assemble_function'. + + FIRST is the first insn of the rtl for the function being compiled. + FILE is the file to write assembler code to. + WRITE_SYMBOLS says which kind of debugging info to write (or none). + OPTIMIZE is nonzero if we should eliminate redundant + test and compare insns. */ + +void +final_start_function (first, file, write_symbols, optimize) + rtx first; + FILE *file; + enum debugger write_symbols; + int optimize; +{ + block_depth = 0; + + this_is_asm_operands = 0; + + /* Record beginning of the symbol-block that's the entire function. */ + + if (write_symbols == GDB_DEBUG) + { + pending_blocks[block_depth++] = next_block_index; + fprintf (file, "\t.gdbbeg %d\n", next_block_index++); + } + + /* Initial line number is supposed to be output + before the function's prologue and label + so that the function's address will not appear to be + in the last statement of the preceding function. */ + if (NOTE_LINE_NUMBER (first) != NOTE_INSN_DELETED) + { + if (write_symbols == SDB_DEBUG) + /* For sdb, let's not, but say we did. + We need to set last_linenum for sdbout_function_begin, + but we can't have an actual line number before the .bf symbol. + (sdb_begin_function_line is not set, + and other compilers don't do it.) */ + last_linenum = NOTE_LINE_NUMBER (first); + else + output_source_line (file, first, write_symbols); + } + + /* The Sun386i and perhaps other machines don't work right + if the profiling code comes after the prologue. */ +#ifdef PROFILE_BEFORE_PROLOGUE + if (profile_flag) + profile_function (file); +#endif /* PROFILE_BEFORE_PROLOGUE */ + +#ifdef FUNCTION_PROLOGUE + /* First output the function prologue: code to set up the stack frame. */ + FUNCTION_PROLOGUE (file, get_frame_size ()); +#endif + +#ifdef SDB_DEBUGGING_INFO + next_block_index = 1; +#endif + +#ifdef FUNCTION_BLOCK_PROFILER + if (profile_block_flag) + { + FUNCTION_BLOCK_PROFILER (file, profile_label_no); + } +#endif /* FUNCTION_BLOCK_PROFILER */ + +#ifndef PROFILE_BEFORE_PROLOGUE + if (profile_flag) + profile_function (file); +#endif /* not PROFILE_BEFORE_PROLOGUE */ + + profile_label_no++; +} + +profile_function (file) + FILE *file; +{ + int align = min (BIGGEST_ALIGNMENT, BITS_PER_WORD); + extern int current_function_returns_struct; + extern int current_function_needs_context; + int sval = current_function_returns_struct; + int cxt = current_function_needs_context; + + data_section (); + ASM_OUTPUT_ALIGN (file, floor_log2 (align / BITS_PER_UNIT)); + ASM_OUTPUT_INTERNAL_LABEL (file, "LP", profile_label_no); + assemble_integer_zero (); + + text_section (); + +#ifdef STRUCT_VALUE_INCOMING_REGNUM + if (sval) + ASM_OUTPUT_REG_PUSH (file, STRUCT_VALUE_INCOMING_REGNUM); +#else +#ifdef STRUCT_VALUE_REGNUM + if (sval) + ASM_OUTPUT_REG_PUSH (file, STRUCT_VALUE_REGNUM); +#endif +#endif + +#if 0 +#ifdef STATIC_CHAIN_INCOMING_REGNUM + if (cxt) + ASM_OUTPUT_REG_PUSH (file, STATIC_CHAIN_INCOMING_REGNUM); +#else +#ifdef STATIC_CHAIN_REGNUM + if (cxt) + 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 (cxt) + ASM_OUTPUT_REG_POP (file, STATIC_CHAIN_INCOMING_REGNUM); +#else +#ifdef STATIC_CHAIN_REGNUM + if (cxt) + ASM_OUTPUT_REG_POP (file, STATIC_CHAIN_REGNUM); +#endif +#endif +#endif /* 0 */ + +#ifdef STRUCT_VALUE_INCOMING_REGNUM + if (sval) + ASM_OUTPUT_REG_POP (file, STRUCT_VALUE_INCOMING_REGNUM); +#else +#ifdef STRUCT_VALUE_REGNUM + if (sval) + ASM_OUTPUT_REG_POP (file, STRUCT_VALUE_REGNUM); +#endif +#endif +} + +/* 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. */ + +void +final_end_function (first, file, write_symbols, optimize) + rtx first; + FILE *file; + enum debugger write_symbols; + int optimize; +{ + if (app_on) + { + fprintf (file, ASM_APP_OFF); + app_on = 0; + } + + if (write_symbols == GDB_DEBUG) + fprintf (file, "\t.gdbend %d\n", pending_blocks[0]); + +#ifdef SDB_DEBUGGING_INFO + if (write_symbols == SDB_DEBUG) + sdbout_end_function (last_linenum); +#endif + +#ifdef FUNCTION_EPILOGUE + /* Finally, output the function epilogue: + code to restore the stack frame and return to the caller. */ + FUNCTION_EPILOGUE (file, get_frame_size ()); +#endif + +#ifdef SDB_DEBUGGING_INFO + if (write_symbols == SDB_DEBUG) + sdbout_end_epilogue (); +#endif + + /* If FUNCTION_EPILOGUE is not defined, then the function body + itself contains return instructions wherever needed. */ +} + +/* Output assembler code for some insns: all or part of a function. + For description of args, see `final_start_function', above. + + PRESCAN is 1 if we are not really outputting, + just scanning as if we were outputting. + Prescanning deletes and rearranges insns just like ordinary output. + PRESCAN is -2 if we are outputting after having prescanned. + In this case, don't try to delete or rearrange insns + because that has already been done. + Prescanning is done only on certain machines. */ + +void +final (first, file, write_symbols, optimize, prescan) + rtx first; + FILE *file; + enum debugger write_symbols; + int optimize; + int prescan; +{ + register rtx insn; + + last_ignored_compare = 0; + new_block = 1; + + init_recog (); + + CC_STATUS_INIT; + + for (insn = NEXT_INSN (first); insn;) + insn = final_scan_insn (insn, file, write_symbols, optimize, + prescan, 0); +} + +/* 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. + + NOPEEPHOLES is the flag to disallow peephole processing (currently + used for within delayed branch sequence output). */ + +rtx +final_scan_insn (insn, file, write_symbols, optimize, prescan, nopeepholes) + rtx insn; + FILE *file; + enum debugger write_symbols; + int optimize; + int prescan; + int nopeepholes; +{ + register int i; + switch (GET_CODE (insn)) + { + case NOTE: + if (prescan > 0) + break; + if (write_symbols == NO_DEBUG) + break; + if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_FUNCTION_BEG) + { +#ifdef SDB_DEBUGGING_INFO + if (write_symbols == SDB_DEBUG) + sdbout_begin_function (last_linenum); +#endif + break; + } + if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG + || NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END) + break; + if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_DELETED) + break; /* An insn that was "deleted" */ + if (app_on) + { + fprintf (file, ASM_APP_OFF); + app_on = 0; + } + if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_BEG) + { + /* Beginning of a symbol-block. Assign it a sequence number + and push the number onto the stack PENDING_BLOCKS. */ + + if (block_depth == max_block_depth) + { + /* PENDING_BLOCKS is full; make it longer. */ + max_block_depth *= 2; + pending_blocks + = (int *) xrealloc (pending_blocks, + max_block_depth * sizeof (int)); + } + pending_blocks[block_depth++] = next_block_index; + + /* Output debugging info about the symbol-block beginning. */ + +#ifdef SDB_DEBUGGING_INFO + if (write_symbols == SDB_DEBUG) + sdbout_begin_block (file, last_linenum, next_block_index); +#endif +#ifdef DBX_DEBUGGING_INFO + if (write_symbols == DBX_DEBUG) + ASM_OUTPUT_INTERNAL_LABEL (file, "LBB", next_block_index); +#endif + if (write_symbols == GDB_DEBUG) + fprintf (file, "\t.gdbbeg %d\n", next_block_index); + + next_block_index++; + } + else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_END) + { + /* End of a symbol-block. Pop its sequence number off + PENDING_BLOCKS and output debugging info based on that. */ + + --block_depth; + +#ifdef DBX_DEBUGGING_INFO + if (write_symbols == DBX_DEBUG && block_depth >= 0) + ASM_OUTPUT_INTERNAL_LABEL (file, "LBE", + pending_blocks[block_depth]); +#endif + +#ifdef SDB_DEBUGGING_INFO + if (write_symbols == SDB_DEBUG && block_depth >= 0) + sdbout_end_block (file, last_linenum); +#endif + + if (write_symbols == GDB_DEBUG) + fprintf (file, "\t.gdbend %d\n", pending_blocks[block_depth]); + } + else if (NOTE_LINE_NUMBER (insn) > 0) + /* This note is a line-number. */ + output_source_line (file, insn, write_symbols); + break; + + case BARRIER: +#ifdef ASM_OUTPUT_ALIGN_CODE + ASM_OUTPUT_ALIGN_CODE (file); +#endif + break; + + case CODE_LABEL: + CC_STATUS_INIT; + if (prescan > 0) + break; + new_block = 1; + if (app_on) + { + fprintf (file, ASM_APP_OFF); + app_on = 0; + } +#ifdef ASM_OUTPUT_CASE_LABEL + if (NEXT_INSN (insn) != 0 + && GET_CODE (NEXT_INSN (insn)) == JUMP_INSN) + { + rtx nextbody = PATTERN (NEXT_INSN (insn)); + + /* If this label is followed by a jump-table, + output the two of them together in a special way. */ + + if (GET_CODE (nextbody) == ADDR_VEC + || GET_CODE (nextbody) == ADDR_DIFF_VEC) + { + ASM_OUTPUT_CASE_LABEL (file, "L", CODE_LABEL_NUMBER (insn), + NEXT_INSN (insn)); + break; + } + } +#endif + + ASM_OUTPUT_INTERNAL_LABEL (file, "L", CODE_LABEL_NUMBER (insn)); + break; + + default: + { + register rtx body = PATTERN (insn); + int insn_code_number; + char *template; + + /* An INSN, JUMP_INSN or CALL_INSN. + First check for special kinds that recog doesn't recognize. */ + + if (GET_CODE (body) == USE /* These are just declarations */ + || GET_CODE (body) == CLOBBER) + break; + + if (profile_block_flag && new_block) + { + rtx real_body = body; + if (GET_CODE (insn) == NOTE) + real_body = PATTERN (next_real_insn (insn)); + + /* Don't add instructions in front of jump tables. */ + if (GET_CODE (real_body) != ADDR_VEC + && GET_CODE (real_body) != ADDR_DIFF_VEC) + { + new_block = 0; + /* Enable the table of basic-block use counts + to point at the code it applies to. */ + ASM_OUTPUT_INTERNAL_LABEL (file, "LPB", count_basic_blocks); + /* Before first insn of this basic block, increment the + count of times it was entered. */ +#ifdef BLOCK_PROFILER + BLOCK_PROFILER (file, count_basic_blocks); +#endif + count_basic_blocks++; + } + } + + if (GET_CODE (body) == ASM_INPUT) + { + /* There's no telling what that did to the condition codes. */ + CC_STATUS_INIT; + if (prescan > 0) + break; + if (! app_on) + { + fprintf (file, ASM_APP_ON); + app_on = 1; + } + fprintf (asm_out_file, "\t%s\n", XSTR (body, 0)); + break; + } + + /* Detect `asm' construct with operands. */ + if (asm_noperands (body) >= 0) + { + int noperands = asm_noperands (body); + rtx *ops; + char *string; + + /* There's no telling what that did to the condition codes. */ + CC_STATUS_INIT; + if (prescan > 0) + break; + + /* alloca won't do here, since only return from `final' + would free it. */ + if (noperands > 0) + ops = (rtx *) xmalloc (noperands * sizeof (rtx)); + + if (! app_on) + { + fprintf (file, ASM_APP_ON); + app_on = 1; + } + + /* Get out the operand values. */ + string = decode_asm_operands (body, ops, 0, 0, 0); + /* Inhibit aborts on what would otherwise be compiler bugs. */ + insn_noperands = noperands; + this_is_asm_operands = insn; + /* Output the insn using them. */ + output_asm_insn (string, ops); + this_is_asm_operands = 0; + if (noperands > 0) + free (ops); + break; + } + + if (prescan <= 0 && app_on) + { + fprintf (file, ASM_APP_OFF); + app_on = 0; + } + + /* Detect insns that are really jump-tables + and output them as such. */ + + if (GET_CODE (body) == ADDR_VEC) + { + register int vlen, idx; + + if (prescan > 0) + break; + + vlen = XVECLEN (body, 0); + for (idx = 0; idx < vlen; idx++) + ASM_OUTPUT_ADDR_VEC_ELT (file, + CODE_LABEL_NUMBER (XEXP (XVECEXP (body, 0, idx), 0))); +#ifdef ASM_OUTPUT_CASE_END + ASM_OUTPUT_CASE_END (file, + CODE_LABEL_NUMBER (PREV_INSN (insn)), + insn); +#endif + break; + } + if (GET_CODE (body) == ADDR_DIFF_VEC) + { + register int vlen, idx; + + if (prescan > 0) + break; + + vlen = XVECLEN (body, 1); + for (idx = 0; idx < vlen; idx++) + ASM_OUTPUT_ADDR_DIFF_ELT (file, + CODE_LABEL_NUMBER (XEXP (XVECEXP (body, 1, idx), 0)), + CODE_LABEL_NUMBER (XEXP (XEXP (body, 0), 0))); +#ifdef ASM_OUTPUT_CASE_END + ASM_OUTPUT_CASE_END (file, + CODE_LABEL_NUMBER (PREV_INSN (insn)), + insn); +#endif + break; + } + + if (recog_memoized (insn) == -1 + && GET_CODE (body) == SEQUENCE) /* A delayed-branch sequence */ + { + register int i; + if (prescan > 0) + break; + final_sequence = body; + for (i = 0; i < XVECLEN (body, 0); i++) + final_scan_insn (XVECEXP (body, 0, i), file, write_symbols, + optimize, prescan, 1); + final_sequence = 0; +#ifdef DBR_OUTPUT_SEQEND + DBR_OUTPUT_SEQEND (file); +#endif + break; + } + + /* We have a real machine instruction as rtl. */ + + body = PATTERN (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, + it should be possible for the user to alter a variable + with the debugger in between statements + 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 (GET_CODE (SET_SRC (body)) == SUBREG) + SET_SRC (body) = alter_subreg (SET_SRC (body)); + 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))) + { + /* Don't delete insn if has an addressing side-effect */ + if (! find_reg_note (insn, REG_INC, 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; + } + } + } + + /* Following a conditional branch, we have a new basic block. */ + if (GET_CODE (insn) == JUMP_INSN && GET_CODE (body) == SET + && GET_CODE (SET_SRC (body)) != LABEL_REF) + new_block = 1; + + /* If this is a conditional branch, maybe modify it + if the cc's are in a nonstandard state + so that it accomplishes the same thing that it would + do straightforwardly if the cc's were set up normally. */ + + if (cc_status.flags != 0 + && GET_CODE (insn) == JUMP_INSN + && GET_CODE (body) == SET + && SET_DEST (body) == pc_rtx + && GET_CODE (SET_SRC (body)) == IF_THEN_ELSE + /* This is done during prescan; it is not done again + in final scan when prescan has been done. */ + && prescan >= 0) + { + /* This function may alter the contents of its argument + and clear some of the cc_status.flags bits. + It may also return 1 meaning condition now always true + or -1 meaning condition now always false + or 2 meaning condition nontrivial but altered. */ + register int result = alter_cond (XEXP (SET_SRC (body), 0)); + /* If condition now has fixed value, replace the IF_THEN_ELSE + with its then-operand or its else-operand. */ + if (result == 1) + SET_SRC (body) = XEXP (SET_SRC (body), 1); + if (result == -1) + SET_SRC (body) = XEXP (SET_SRC (body), 2); + /* The jump is now either unconditional or a no-op. + If it has become a no-op, don't try to output it. + (It would not be recognized.) */ + if (SET_SRC (body) == pc_rtx) + { + PUT_CODE (insn, NOTE); + NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED; + NOTE_SOURCE_FILE (insn) = 0; + break; + } + /* Rerecognize the instruction if it has changed. */ + if (result != 0) + INSN_CODE (insn) = -1; + } + +#ifdef STORE_FLAG_VALUE + /* Make same adjustments to instructions that examine the + condition codes without jumping (if this machine has them). */ + + if (cc_status.flags != 0 + && GET_CODE (body) == SET) + switch (GET_CODE (SET_SRC (body))) + { + case GTU: + case GT: + case LTU: + case LT: + case GEU: + case GE: + case LEU: + case LE: + case EQ: + case NE: + { + register int result; + if (GET_CODE (XEXP (SET_SRC (body), 0)) != CC0) + break; + result = alter_cond (SET_SRC (body)); + if (result == 1) + SET_SRC (body) = gen_rtx (CONST_INT, VOIDmode, + STORE_FLAG_VALUE); + if (result == -1) + SET_SRC (body) = const0_rtx; + if (result != 0) + INSN_CODE (insn) = -1; + } + } +#endif /* STORE_FLAG_VALUE */ + + /* Do machine-specific peephole optimizations if desired. */ + + if (optimize && !flag_no_peephole && !nopeepholes) + { + rtx next = peephole (insn); + /* When peepholing, if there were notes within the peephole, + emit them before the peephole. */ + if (next != 0 && next != NEXT_INSN (insn)) + { + rtx note = NEXT_INSN (insn); + rtx prev = PREV_INSN (insn); + while (note != next) + { + final_scan_insn (note, file, write_symbols, optimize, + prescan, nopeepholes); + note = NEXT_INSN (note); + } + /* In case this is prescan, put the notes + in proper position for later rescan. */ + note = NEXT_INSN (insn); + PREV_INSN (note) = prev; + NEXT_INSN (prev) = note; + NEXT_INSN (PREV_INSN (next)) = insn; + PREV_INSN (insn) = PREV_INSN (next); + NEXT_INSN (insn) = next; + PREV_INSN (next) = insn; + } + + /* PEEPHOLE might have changed this. */ + body = PATTERN (insn); + } + + /* Try to recognize the instruction. + If successful, verify that the operands satisfy the + constraints for the instruction. Crash if they don't, + since `reload' should have changed them so that they do. */ + + insn_code_number = recog_memoized (insn); + insn_extract (insn); + for (i = 0; i < insn_n_operands[insn_code_number]; i++) + { + if (GET_CODE (recog_operand[i]) == SUBREG) + recog_operand[i] = alter_subreg (recog_operand[i]); + } + +#ifdef REGISTER_CONSTRAINTS + if (! constrain_operands (insn_code_number)) + abort (); +#endif + + /* Some target machines need to prescan each insn before + it is output. */ + +#ifdef FINAL_PRESCAN_INSN + FINAL_PRESCAN_INSN (insn, recog_operand, + insn_n_operands[insn_code_number]); +#endif + + cc_prev_status = cc_status; + + /* Update `cc_status' for this instruction. + The instruction's output routine may change it further. + If the output routine for a jump insn needs to depend + on the cc status, it should look at cc_prev_status. */ + + NOTICE_UPDATE_CC (body, insn); + + /* If the proper template needs to be chosen by some C code, + run that code and get the real template. */ + + template = insn_template[insn_code_number]; + if (template == 0) + { + template = (*insn_outfun[insn_code_number]) (recog_operand, insn); + + /* If the C code returns 0, it means that it is a jump insn + which follows a deleted test insn, and that test insn + needs to be reinserted. */ + if (template == 0) + { + if (PREV_INSN (insn) != last_ignored_compare) + abort (); + new_block = 0; + return PREV_INSN (insn); + } + } + + if (prescan > 0) + break; + + /* Output assembler code from the template. */ + + output_asm_insn (template, recog_operand); + + /* Mark this insn as having been output. */ + INSN_DELETED_P (insn) = 1; + } + } + return NEXT_INSN (insn); +} + +/* Set up FILENAME as the current file for GDB line-number output. */ + +void +set_current_gdbfile (filename) + char *filename; +{ + register struct gdbfile *f; + for (f = gdbfiles; f; f = f->next) + if (!strcmp (f->name, filename)) + break; + + if (!f) + { + f = (struct gdbfile *) permalloc (sizeof (struct gdbfile)); + f->next = gdbfiles; + gdbfiles = f; + f->name = filename; + f->filenum = next_gdb_filenum++; + f->nlines = 0; + } + current_gdbfile = f; + lastfile = filename; +} + +/* Output debugging info to the assembler file FILE + based on the NOTE-insn INSN, assumed to be a line number. */ + +static void +output_source_line (file, insn, write_symbols) + FILE *file; + rtx insn; + enum debugger write_symbols; +{ + register char *filename = NOTE_SOURCE_FILE (insn); + + last_linenum = NOTE_LINE_NUMBER (insn); + + if (write_symbols == GDB_DEBUG) + { + /* Output GDB-format line number info. */ + + /* If this is not the same source file as last time, + find or assign a GDB-file-number to this file. */ + if (filename && (lastfile == 0 || strcmp (filename, lastfile) + || current_gdbfile == 0)) + set_current_gdbfile (filename); + + ++current_gdbfile->nlines; + fprintf (file, "\t.gdbline %d,%d\n", + current_gdbfile->filenum, NOTE_LINE_NUMBER (insn)); + } + + if (write_symbols == SDB_DEBUG || write_symbols == DBX_DEBUG) + { +#ifdef SDB_DEBUGGING_INFO + if (write_symbols == SDB_DEBUG +#if 0 /* People like having line numbers even in wrong file! */ + /* COFF can't handle multiple source files--lose, lose. */ + && !strcmp (filename, main_input_filename) +#endif + /* COFF relative line numbers must be positive. */ + && last_linenum > sdb_begin_function_line) + { +#ifdef ASM_OUTPUT_SOURCE_LINE + ASM_OUTPUT_SOURCE_LINE (file, last_linenum); +#else + fprintf (file, "\t.ln\t%d\n", + (sdb_begin_function_line + ? last_linenum - sdb_begin_function_line : 1)); +#endif + } +#endif + +#ifdef DBX_DEBUGGING_INFO + if (write_symbols == DBX_DEBUG) + { + /* Write DBX line number data. */ + + if (filename && (lastfile == 0 || strcmp (filename, lastfile))) + { +#ifdef ASM_OUTPUT_SOURCE_FILENAME + ASM_OUTPUT_SOURCE_FILENAME (file, filename); +#else + fprintf (file, "\t.stabs \"%s\",%d,0,0,Ltext\n", + filename, N_SOL); +#endif + lastfile = filename; + } + } + +#ifdef ASM_OUTPUT_SOURCE_LINE + ASM_OUTPUT_SOURCE_LINE (file, NOTE_LINE_NUMBER (insn)); +#else + fprintf (file, "\t.stabd %d,0,%d\n", + N_SLINE, NOTE_LINE_NUMBER (insn)); +#endif +#endif /* DBX_DEBUGGING_INFO */ + } +} + +/* If X is a SUBREG, replace it with a REG or a MEM, + based on the thing it is a subreg of. */ + +rtx +alter_subreg (x) + register rtx x; +{ + register rtx y = SUBREG_REG (x); + if (GET_CODE (y) == SUBREG) + y = alter_subreg (y); + + if (GET_CODE (y) == REG) + { + /* If the containing reg really gets a hard reg, so do we. */ + PUT_CODE (x, REG); + REGNO (x) = REGNO (y) + SUBREG_WORD (x); + } + else if (GET_CODE (y) == MEM) + { + register int offset = SUBREG_WORD (x) * UNITS_PER_WORD; +#ifdef BYTES_BIG_ENDIAN + offset -= (min (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (x))) + - min (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (y)))); +#endif + PUT_CODE (x, MEM); + MEM_VOLATILE_P (x) = MEM_VOLATILE_P (y); + XEXP (x, 0) = plus_constant (XEXP (y, 0), offset); + } + else if (GET_CODE (y) == CONST_DOUBLE) + return y; + + return x; +} + +/* Do alter_subreg on all the SUBREGs contained in X. */ + +static rtx +walk_alter_subreg (x) + rtx x; +{ + switch (GET_CODE (x)) + { + case PLUS: + case MULT: + XEXP (x, 0) = walk_alter_subreg (XEXP (x, 0)); + XEXP (x, 1) = walk_alter_subreg (XEXP (x, 1)); + break; + + case MEM: + XEXP (x, 0) = walk_alter_subreg (XEXP (x, 0)); + break; + + case SUBREG: + return alter_subreg (x); + } + + return x; +} + +/* Given BODY, the body of a jump instruction, alter the jump condition + as required by the bits that are set in cc_status.flags. + Not all of the bits there can be handled at this level in all cases. + + The value is normally 0. + 1 means that the condition has become always true. + -1 means that the condition has become always false. + 2 means that COND has been altered. */ + +static int +alter_cond (cond) + register rtx cond; +{ + int value = 0; + + if (cc_status.flags & CC_REVERSED) + { + value = 2; + switch (GET_CODE (cond)) + { + case LE: + PUT_CODE (cond, GE); + break; + case GE: + PUT_CODE (cond, LE); + break; + case LT: + PUT_CODE (cond, GT); + break; + case GT: + PUT_CODE (cond, LT); + break; + case LEU: + PUT_CODE (cond, GEU); + break; + case GEU: + PUT_CODE (cond, LEU); + break; + case LTU: + PUT_CODE (cond, GTU); + break; + case GTU: + PUT_CODE (cond, LTU); + break; + } + } + + if (cc_status.flags & CC_NOT_POSITIVE) + switch (GET_CODE (cond)) + { + case LE: + case LEU: + case GEU: + /* Jump becomes unconditional. */ + return 1; + + case GT: + case GTU: + case LTU: + /* Jump becomes no-op. */ + return -1; + + case GE: + PUT_CODE (cond, EQ); + value = 2; + break; + + case LT: + PUT_CODE (cond, NE); + value = 2; + break; + } + + if (cc_status.flags & CC_NOT_NEGATIVE) + switch (GET_CODE (cond)) + { + case GE: + case GEU: + /* Jump becomes unconditional. */ + return 1; + + case LT: + case LTU: + /* Jump becomes no-op. */ + return -1; + + case LE: + case LEU: + PUT_CODE (cond, EQ); + value = 2; + break; + + case GT: + case GTU: + PUT_CODE (cond, NE); + value = 2; + break; + } + + if (cc_status.flags & CC_NO_OVERFLOW) + switch (GET_CODE (cond)) + { + case GEU: + /* Jump becomes unconditional. */ + return 1; + + case LEU: + PUT_CODE (cond, EQ); + value = 2; + break; + + case GTU: + PUT_CODE (cond, NE); + value = 2; + break; + + case LTU: + /* Jump becomes no-op. */ + return -1; + } + + 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: + abort (); + + case NE: + PUT_CODE (cond, cc_status.flags & CC_Z_IN_N ? GE : LT); + value = 2; + break; + + case EQ: + PUT_CODE (cond, cc_status.flags & CC_Z_IN_N ? LT : GE); + value = 2; + break; + } + + return value; +} + +/* Report inconsistency between the assembler template and the operands. + In an `asm', it's the user's fault; otherwise, the compiler's fault. */ + +static void +output_operand_lossage (str) + char *str; +{ + if (this_is_asm_operands) + error_for_asm (this_is_asm_operands, "invalid `asm': %s", str); + else + abort (); +} + +/* Output of assembler code from a template, and its subroutines. */ + +/* Output text from TEMPLATE to the assembler output file, + obeying %-directions to substitute operands taken from + the vector OPERANDS. + + %N (for N a digit) means print operand N in usual manner. + %lN means require operand N to be a CODE_LABEL or LABEL_REF + and print the label name with no punctuation. + %cN means require operand N to be a constant + and print the constant expression with no punctuation. + %aN means expect operand N to be a memory address + (not a memory reference!) and print a reference + to that address. + %nN means expect operand N to be a constant + and print a constant expression for minus the value + of the operand, with no other punctuation. */ + +void +output_asm_insn (template, operands) + char *template; + rtx *operands; +{ + register char *p; + register int c; + + /* An insn may return a null string template + in a case where no assembler code is needed. */ + if (*template == 0) + return; + + p = template; + putc ('\t', asm_out_file); + +#ifdef ASM_OUTPUT_OPCODE + ASM_OUTPUT_OPCODE (asm_out_file, p); +#endif + + while (c = *p++) + { +#ifdef ASM_OUTPUT_OPCODE + if (c == '\n') + { + putc (c, asm_out_file); + while ((c = *p) == '\t') + { + putc (c, asm_out_file); + p++; + } + ASM_OUTPUT_OPCODE (asm_out_file, p); + } + else +#endif + if (c != '%') + putc (c, asm_out_file); + else + { + /* %% outputs a single %. */ + if (*p == '%') + { + p++; + putc (c, asm_out_file); + } + /* % followed by a letter and some digits + outputs an operand in a special way depending on the letter. + Letters `acln' are implemented here. + Other letters are passed to `output_operand' so that + the PRINT_OPERAND macro can define them. */ + else if ((*p >= 'a' && *p <= 'z') + || (*p >= 'A' && *p <= 'Z')) + { + int letter = *p++; + c = atoi (p); + + if (! (*p >= '0' && *p <= '9')) + output_operand_lossage ("operand number missing after %-letter"); + else if (this_is_asm_operands && c >= (unsigned) insn_noperands) + output_operand_lossage ("operand number out of range"); + else if (letter == 'l') + output_asm_label (operands[c]); + else if (letter == 'a') + output_address (operands[c]); + else if (letter == 'c') + { + if (CONSTANT_ADDRESS_P (operands[c])) + output_addr_const (asm_out_file, operands[c]); + else + output_operand (operands[c], 'c'); + } + else if (letter == 'n') + { + if (GET_CODE (operands[c]) == CONST_INT) + fprintf (asm_out_file, "%d", - INTVAL (operands[c])); + else + { + putc ('-', asm_out_file); + output_addr_const (asm_out_file, operands[c]); + } + } + else + output_operand (operands[c], letter); + + while ((c = *p) >= '0' && c <= '9') p++; + } + /* % followed by a digit outputs an operand the default way. */ + else if (*p >= '0' && *p <= '9') + { + c = atoi (p); + if (this_is_asm_operands && c >= (unsigned) insn_noperands) + output_operand_lossage ("operand number out of range"); + else + output_operand (operands[c], 0); + while ((c = *p) >= '0' && c <= '9') p++; + } + /* % followed by punctuation: output something for that + punctuation character alone, with no operand. + The PRINT_OPERAND macro decides what is actually done. */ +#ifdef PRINT_OPERAND_PUNCT_VALID_P + else if (PRINT_OPERAND_PUNCT_VALID_P (*p)) + output_operand (0, *p++); +#endif + else + output_operand_lossage ("invalid %%-code"); + } + } + + putc ('\n', asm_out_file); +} + +/* Output a LABEL_REF, or a bare CODE_LABEL, as an assembler symbol. */ + +void +output_asm_label (x) + rtx x; +{ + char buf[256]; + + if (GET_CODE (x) == LABEL_REF) + ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (XEXP (x, 0))); + else if (GET_CODE (x) == CODE_LABEL) + ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x)); + else + output_operand_lossage ("`%l' operand isn't a label"); + + assemble_name (asm_out_file, buf); +} + +/* Print operand X using machine-dependent assembler syntax. + The macro PRINT_OPERAND is defined just to control this function. + CODE is a non-digit that preceded the operand-number in the % spec, + such as 'z' if the spec was `%z3'. CODE is 0 if there was no char + between the % and the digits. + When CODE is a non-letter, X is 0. + + The meanings of the letters are machine-dependent and controlled + by PRINT_OPERAND. */ + +static void +output_operand (x, code) + rtx x; + int code; +{ + if (x && GET_CODE (x) == SUBREG) + x = alter_subreg (x); + PRINT_OPERAND (asm_out_file, x, code); +} + +/* Print a memory reference operand for address X + using machine-dependent assembler syntax. + The macro PRINT_OPERAND_ADDRESS exists just to control this function. */ + +void +output_address (x) + rtx x; +{ + walk_alter_subreg (x); + PRINT_OPERAND_ADDRESS (asm_out_file, x); +} + +/* Print an integer constant expression in assembler syntax. + Addition and subtraction are the only arithmetic + that may appear in these expressions. */ + +void +output_addr_const (file, x) + FILE *file; + rtx x; +{ + char buf[256]; + + restart: + switch (GET_CODE (x)) + { + case SYMBOL_REF: + assemble_name (file, XSTR (x, 0)); + break; + + case LABEL_REF: + ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (XEXP (x, 0))); + assemble_name (asm_out_file, buf); + break; + + case CODE_LABEL: + ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x)); + assemble_name (asm_out_file, buf); + break; + + case CONST_INT: + fprintf (file, "%d", INTVAL (x)); + break; + + case CONST: + x = XEXP (x, 0); + goto restart; + + case CONST_DOUBLE: + if (GET_MODE (x) == DImode) + { + /* 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)); + else + fprintf (file, "%d", CONST_DOUBLE_LOW (x)); + } + 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) + { + output_addr_const (file, XEXP (x, 1)); + if (INTVAL (XEXP (x, 0)) >= 0) + fprintf (file, "+"); + output_addr_const (file, XEXP (x, 0)); + } + else + { + output_addr_const (file, XEXP (x, 0)); + if (INTVAL (XEXP (x, 1)) >= 0) + fprintf (file, "+"); + output_addr_const (file, XEXP (x, 1)); + } + break; + + case MINUS: + output_addr_const (file, XEXP (x, 0)); + fprintf (file, "-"); + output_addr_const (file, XEXP (x, 1)); + break; + + default: + output_operand_lossage ("invalid expression as operand"); + } +} diff --git a/gcc-1.40/fixcpp b/gcc-1.40/fixcpp new file mode 100644 index 0000000..21b53b1 --- /dev/null +++ b/gcc-1.40/fixcpp @@ -0,0 +1,109 @@ +#!/bin/sh +# +# NAME: +# fixcpp - fix CPP errors +# +# SYNOPSIS: +# fixcpp [-c][-p patch_file][-b bak_dir][-n new_dir] files(s) +# +# DESCRIPTION: +# For each named file, use sed(1) to fixup any descriptive +# text after #else or #endif or that is not properly +# commented as this causes ANSI compilers to generate +# unnecessary warnings. +# +# Naturally this script is not guaranteed to be bullit +# proof, use of -n or -b is advisable! +# +# -c causes fixcpp to make sure that only files that +# needed changing are affected by returning the original +# file to its original location if no changes were needed. +# +# -p causes fixcpp to append to a patch file the context +# diffs of the changes wraught. +# +# SEE ALSO: +# sed(1) +# +# AMENDED: +# 90/08/08 22:46:32 (sjg) +# +# RELEASED: +# 90/08/08 22:46:34 v1.4 +# +# SCCSID: +# @(#)fixcpp.sh 1.4 90/08/08 22:46:32 (sjg) +# +# @(#)Copyright (c) 1990 Simon J. Gerraty +# +# This is free software. It comes with NO WARRANTY. +# Everyone is granted permission to copy, modify and +# redistribute this source code provided that all +# recipients are given similar rights, and that the above +# copyright notice and this notice are preserved in all +# copies. + +TMPF=/tmp/fixcpp.$$ +NEWDIR= +BAKDIR= +PATCHF= +CHECK= + +set -- `getopt "cp:b:n:" $*` +if [ $? != 0 ]; then + echo "$0 [-c][-p patch_file][-b bakup_dir][-n new_dir] file [file ...]" >&2 + exit 1 +fi +for i in $* +do + case $i in + -c) CHECK=yes; shift;; + -p) PATCHF=$2; shift 2;; + -b) BAKDIR=$2; shift 2;; + -n) NEWDIR=$2; shift 2;; + --) shift; break;; + esac +done +NEWDIR=${NEWDIR:-.} +if [ $BAKDIR ]; then + if [ ! -d $BAKDIR ]; then + echo "$0: no such directory -- $BAKDIR" >&2 + exit 1 + fi +fi + + + +for i in $* +do + if [ $BAKDIR ]; then + mv $i $BAKDIR + infile=$BAKDIR/$i + else + if [ "$NEWDIR" = "." ]; then + mv $i ${TMPF} + infile=${TMPF} + else + infile=$i + fi + fi + sed -e 's;^#\([ ]*e[nl][^ ]*[ ][ ]*\)\([^/ ][^\*].*\);#\1/* \2 */;' -e 's;^#\([ ]*e[nl][^ ]*[ ][ ]*\)\([^/ ]\)$;#\1/* \2 */;' $infile >${NEWDIR}/$i + if [ "${CHECK}" = "yes" -o ${PATCHF} ]; then + if cmp -s $infile ${NEWDIR}/$i ; then + if [ "${CHECK}" = "yes" ]; then + if [ $BAKDIR ]; then + mv $infile ${NEWDIR}/$i + else + rm ${NEWDIR}/$i + fi + fi + else + if [ $PATCHF ]; then + diff -c $infile ${NEWDIR}/$i >> ${PATCHF} + fi + fi + fi + +done + +rm -f ${TMPF} diff --git a/gcc-1.40/fixincludes b/gcc-1.40/fixincludes new file mode 100755 index 0000000..e54a0a3 --- /dev/null +++ b/gcc-1.40/fixincludes @@ -0,0 +1,378 @@ +#! /bin/sh +# Install modified versions of certain ANSI-incompatible system header files +# which are fixed to work correctly with ANSI C +# and placed in a directory that GNU C will search. +# This works properly on a Sun in system version 3.4; +# for other versions, you had better check. + +# Directory in which to store the results. +LIB=${LIB-/usr/local/lib/gcc-include} + +# Make sure it exists. +if [ ! -d $LIB ]; then + mkdir $LIB || exit 1 +fi + +# Determine whether this system has symbolic links. +if ln -s X $LIB/ShouldNotExist 2>/dev/null; then + rm -f $LIB/ShouldNotExist + LINKS=true +else + LINKS=false +fi + +echo 'Making directories:' +cd /usr/include +if $LINKS; then + files=`ls -LR | sed -n s/:$//p` +else + files=`find . -type d -print | sed '/^.$/d'` +fi +for file in $files; do + rm -rf $LIB/$file + if [ ! -d $LIB/$file ] + then mkdir $LIB/$file + fi +done + +# treetops gets an alternating list +# of old directories to copy +# and the new directories to copy to. +treetops="/usr/include ${LIB}" + +if $LINKS; then + echo 'Making internal symbolic directory links' + for file in $files; do + dest=`ls -ld $file | sed -n 's/.*-> //p'` + if [ "$dest" ]; then + cwd=`pwd` + # In case $dest is relative, get to $file's dir first. + cd /usr/include + cd `echo ./$file | sed -n 's&[^/]*$&&p'` + # Check that the target directory exists. + # Redirections changed to avoid bug in sh on Ultrix. + (cd $dest) > /dev/null 2>&1 + if [ $? = 0 ]; then + cd $dest + # X gets the dir that the link actually leads to. + x=`pwd` + # If link leads back into /usr/include, + # make a similar link here. + if expr $x : '/usr/include/.*' > /dev/null; then + # Y gets the actual target dir name, relative to /usr/include. + y=`echo $x | sed -n 's&/usr/include/&&p'` + echo $file '->' $y ': Making link' + rm -fr ${LIB}/$file > /dev/null 2>&1 + ln -s ${LIB}/$y ${LIB}/$file > /dev/null 2>&1 + else + # If the link is to outside /usr/include, + # treat this directory as if it actually contained the files. +# This line used to have $dest instead of $x. +# $dest seemed to be wrong for links found in subdirectories +# of /usr/include. Does this change break anything? + treetops="$treetops $x ${LIB}/$file" + fi + fi + cd $cwd + fi + done +fi + +set - $treetops +while [ $# != 0 ]; do + # $1 is an old directory to copy, and $2 is the new directory to copy to. + echo "Finding header files in $1:" + cd /usr/include + cd $1 + files=`find . -name '*.h' -type f -print` + echo 'Checking header files:' +# Note that BSD43_* are used on recent MIPS systems. + for file in $files; do + if egrep '[ ]_IO[A-Z]*\(|[ ]BSD43__IO[A-Z]*\(|#define._IO|#define.BSD43__IO|CTRL' $file > /dev/null; then + echo Fixing $file + if [ -r $file ]; then + cp $file $2/$file >/dev/null 2>&1 \ + || echo "Can't copy $file" + chmod +w $2/$file + sed -e ' + :loop + /\\$/ N + /\\$/ b loop + /[ ]_IO[A-Z]*[ ]*(/ s/(\(.\),/('\''\1'\'',/ + /[ ]BSD43__IO[A-Z]*[ ]*(/ s/(\(.\),/('\''\1'\'',/ + /#define._IO/ s/'\''x'\''/x/g + /#define.BSD43__IO/ s/'\''x'\''/x/g + /[^A-Z]CTRL[ ]*(/ s/\([^'\'']\))/'\''\1'\'')/ + /#define.CTRL/ s/'\''c'\''/c/g + /#define._CTRL/ s/'\''c'\''/c/g + /#define.BSD43_CTRL/ s/'\''c'\''/c/g + ' $2/$file > $2/$file.sed + mv $2/$file.sed $2/$file + if cmp $file $2/$file >/dev/null 2>&1; then + echo Deleting $2/$file\; no fixes were needed. + rm $2/$file + fi + fi + fi + done + shift; shift +done + +cd /usr/include + +# Fix one other error in this file: a mismatched quote not inside a C comment. +file=sundev/vuid_event.h +if [ -r $file ]; then + if [ ! -r ${LIB}/$file ]; then + cp $file ${LIB}/$file >/dev/null 2>&1 \ + || echo "Can't copy $file" + chmod +w ${LIB}/$file + fi +fi + +if [ -r ${LIB}/$file ]; then + echo Fixing $file comment + ex ${LIB}/$file </dev/null 2>&1; then + echo Deleting ${LIB}/$file\; no fixes were needed. + rm ${LIB}/$file + fi +fi + +# Fix this Sun file to avoid intefering with stddef.h. + +file=sys/stdtypes.h +if [ -r $file ]; then + if [ ! -r ${LIB}/$file ]; then + cp $file ${LIB}/$file >/dev/null 2>&1 \ + || echo "Can't copy $file" + chmod +w ${LIB}/$file + fi +fi + +if [ -r ${LIB}/$file ]; then + echo Fixing $file comment + ex ${LIB}/$file </dev/null 2>&1; then + echo Deleting ${LIB}/$file\; no fixes were needed. + rm ${LIB}/$file + fi +fi + +# Fix an error in this file: a missing semi-colon at the end of the statsswtch +# structure definition. +file=rpcsvc/rstat.h +if [ -r $file ]; then + if [ ! -r ${LIB}/$file ]; then + cp $file ${LIB}/$file >/dev/null 2>&1 \ + || echo "Can't copy $file" + chmod +w ${LIB}/$file + fi +fi + +if [ -r ${LIB}/$file ]; then + echo Fixing $file, definition of statsswtch + ex ${LIB}/$file </dev/null 2>&1; then + echo Deleting ${LIB}/$file\; no fixes were needed. + rm ${LIB}/$file + fi +fi + +# Fix an error in this file: a missing semi-colon at the end of the nodeent +# structure definition. +file=netdnet/dnetdb.h +if [ -r $file ]; then + if [ ! -r ${LIB}/$file ]; then + cp $file ${LIB}/$file >/dev/null 2>&1 \ + || echo "Can't copy $file" + chmod +w ${LIB}/$file + fi +fi + +if [ -r ${LIB}/$file ]; then + echo Fixing $file, definition of nodeent + ex ${LIB}/$file </dev/null 2>&1; then + echo Deleting ${LIB}/$file\; no fixes were needed. + rm ${LIB}/$file + fi +fi + +# Check for bad #ifdef line (in Ultrix 4.1) + +file=sys/file.h +if [ -r $file ]; then + if [ ! -r ${LIB}/$file ]; then + mkdir ${LIB}/rpcsvc 2>&- + cp $file ${LIB}/$file >/dev/null 2>&1 \ + || echo "Can't copy $file" + chmod +w ${LIB}/$file + fi +fi + +if [ -r ${LIB}/$file ]; then + echo Fixing $file, bad \#ifdef line + ex ${LIB}/$file </dev/null 2>&1; then + echo Deleting ${LIB}/$file\; no fixes were needed. + rm ${LIB}/$file + fi +fi + +# Check for superfluous `static' (in Ultrix 4.2) + +file=machine/cpu.h +if [ -r $file ]; then + if [ ! -r ${LIB}/$file ]; then + mkdir ${LIB}/machine 2>&- + cp $file ${LIB}/$file >/dev/null 2>&1 \ + || echo "Can't copy $file" + chmod +w ${LIB}/$file + fi +fi + +if [ -r ${LIB}/$file ]; then + echo Fixing $file, superfluous static + ex ${LIB}/$file </dev/null 2>&1; then + echo Deleting ${LIB}/$file\; no fixes were needed. + rm ${LIB}/$file + else +# This file has an alternative name, mips/cpu.h. Fix that name, too. + if cmp machine/cpu.h mips/cpu.h > /dev/null 2>& 1; then + mkdir ${LIB}/mips 2>&- + ln ${LIB}/$file ${LIB}/mips/cpu.h + fi + fi +fi + +# Deal with yet another challenge, this in X11/Xmu.h +file=X11/Xmu.h +if [ -r $file ]; then + if [ ! -r ${LIB}/$file ]; then + mkdir ${LIB}/X11 2>&- + cp $file ${LIB}/$file >/dev/null 2>&1 \ + || echo "Can't copy $file" + chmod +w ${LIB}/$file + fi +fi + +if [ -r ${LIB}/$file ]; then + echo Fixing $file sprintf declaration + ex ${LIB}/$file </dev/null 2>&1; then + echo Deleting ${LIB}/$file\; no fixes were needed. + rm ${LIB}/$file + fi +fi + +# Check for missing ';' in struct + +file=netinet/ip.h +if [ -r $file ]; then + if [ ! -r ${LIB}/$file ]; then + mkdir ${LIB}/netinet 2>&- + sed -e '/^struct/,/^};/s/}$/};/' $file > ${LIB}/$file + cmp $file ${LIB}/$file >&- && rm -f ${LIB}/$file + fi +fi + +# Fix the CAT macro in memvar.h. + +file=pixrect/memvar.h +if [ -r $file ]; then + if [ ! -r ${LIB}/$file ]; then + mkdir ${LIB}/pixrect 2>&- + sed -e '/^#define.CAT(a,b)/ s/IDENT(a)b/a##b/g' $file > ${LIB}/$file + cmp $file ${LIB}/$file >&- && rm -f ${LIB}/$file + fi +fi + +# Check for yet more missing ';' in struct (in SunOS 4.0.x) + +file=rpcsvc/rusers.h +if [ -r $file ]; then + if [ ! -r ${LIB}/$file ]; then + mkdir ${LIB}/rpcsvc 2>&- + sed -e '/^struct/,/^};/s/_cnt$/_cnt;/' $file > ${LIB}/$file + cmp $file ${LIB}/$file >&- && rm -f ${LIB}/$file + fi +fi + +echo 'Removing unneeded directories:' +cd $LIB +files=`find . -type d -print | sort -r` +for file in $files; do + rmdir $LIB/$file > /dev/null 2>&1 +done + +if $LINKS; then + echo 'Making internal symbolic non-directory links' + cd /usr/include + files=`find . -type l -print` + 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|"` + if [ -f $target ]; then + ln -s $dest ${LIB}/$file >/dev/null 2>&1 + fi + fi + done +fi + +exit 0 diff --git a/gcc-1.40/fixincludes-V4 b/gcc-1.40/fixincludes-V4 new file mode 100644 index 0000000..8138582 --- /dev/null +++ b/gcc-1.40/fixincludes-V4 @@ -0,0 +1,261 @@ +#! /bin/sh +# Install modified versions of certain ANSI-incompatible system header files +# which are fixed to work correctly with ANSI C +# and placed in a directory that GNU C will search. +# This works properly on a Sun in system version 3.4; +# for other versions, you had better check. + +# Directory in which to store the results. +LIB=${LIB-/usr/local/lib/gcc-include} + +# Make sure it exists. +if [ ! -d $LIB ]; then + mkdir $LIB || exit 1 +fi + +# Determine whether this system has symbolic links. +if ln -s X $LIB/ShouldNotExist 2>/dev/null; then + rm -f $LIB/ShouldNotExist + LINKS=true +else + LINKS=false +fi + +echo 'Making directories:' +cd /usr/include +if $LINKS; then + files=`ls -LR | sed -n s/:$//p` +else + files=`find . -type d -print | sed '/^.$/d'` +fi +for file in $files; do + rm -rf $LIB/$file + if [ ! -d $LIB/$file ] + then mkdir $LIB/$file + fi +done + +# treetops gets an alternating list +# of old directories to copy +# and the new directories to copy to. +treetops="/usr/include ${LIB}" + +if $LINKS; then + echo 'Making internal symbolic directory links' + for file in $files; do + dest=`ls -ld $file | sed -n 's/.*-> //p'` + if [ "$dest" ]; then + cwd=`pwd` + # In case $dest is relative, get to $file's dir first. + cd /usr/include + cd `echo ./$file | sed -n 's&[^/]*$&&p'` + # Check that the target directory exists. + # Redirections changed to avoid bug in sh on Ultrix. + (cd $dest) > /dev/null 2>&1 + if [ $? = 0 ]; then + cd $dest + # X gets the dir that the link actually leads to. + x=`pwd` + # If link leads back into /usr/include, + # make a similar link here. + if expr $x : '/usr/include/.*' > /dev/null; then + # Y gets the actual target dir name, relative to /usr/include. + y=`echo $x | sed -n 's&/usr/include/&&p'` + echo $file '->' $y ': Making link' + rm -fr ${LIB}/$file > /dev/null 2>&1 + ln -s ${LIB}/$y ${LIB}/$file > /dev/null 2>&1 + else + # If the link is to outside /usr/include, + # treat this directory as if it actually contained the files. +# This line used to have $dest instead of $x. +# $dest seemed to be wrong for links found in subdirectories +# of /usr/include. Does this change break anything? + treetops="$treetops $x ${LIB}/$file" + fi + fi + cd $cwd + fi + done +fi + +set - $treetops +while [ $# != 0 ]; do + # $1 is an old directory to copy, and $2 is the new directory to copy to. + echo "Finding header files in $1:" + cd /usr/include + cd $1 + files=`find . -name '*.h' -type f -print` + echo 'Checking header files:' + for file in $files; do + if egrep '[ ]_IO[A-Z]*\(|#define._IO|CTRL|#machine|#lint' $file > /dev/null; then + echo Fixing $file + if [ -r $file ]; then + cp $file $2/$file >/dev/null 2>&1 \ + || echo "Can't copy $file" + chmod +w $2/$file + sed -e ' + :loop + /\\$/ N + /\\$/ b loop + /[ ]_IO[A-Z]*[ ]*(/ s/(\(.\),/('\''\1'\'',/ + /#define._IO/ s/'\''x'\''/x/g + /[^A-Z]CTRL[ ]*(/ s/\([^'\'']\))/'\''\1'\'')/ + /#define.CTRL/ s/'\''c'\''/c/g + /#define._CTRL/ s/'\''c'\''/c/g + /^[ ]*#[ ]*if/ s/#machine/defined/g + /^[ ]*#[ ]*elif/ s/#machine/defined/g + /^[ ]*#[ ]*if/ s/#lint *(on)/defined(lint)/g + /^[ ]*#[ ]*elif/ s/#lint *(on)/defined(lint)/g + ' $2/$file > $2/$file.sed + mv $2/$file.sed $2/$file + if cmp $file $2/$file >/dev/null 2>&1; then + echo Deleting $2/$file\; no fixes were needed. + rm $2/$file + fi + fi + fi + done + shift; shift +done + +cd /usr/include + +# Fix one other error in this file: a mismatched quote not inside a C comment. +file=sundev/vuid_event.h +if [ -r $file ]; then + if [ ! -r ${LIB}/$file ]; then + cp $file ${LIB}/$file >/dev/null 2>&1 \ + || echo "Can't copy $file" + chmod +w ${LIB}/$file + fi +fi + +if [ -r ${LIB}/$file ]; then + echo Fixing $file comment + ex ${LIB}/$file </dev/null 2>&1; then + echo Deleting ${LIB}/$file\; no fixes were needed. + rm ${LIB}/$file + fi +fi + +# Fix an error in this file: a missing semi-colon at the end of the statsswtch +# structure definition. +file=rpcsvc/rstat.h +if [ -r $file ]; then + if [ ! -r ${LIB}/$file ]; then + cp $file ${LIB}/$file >/dev/null 2>&1 \ + || echo "Can't copy $file" + chmod +w ${LIB}/$file + fi +fi + +if [ -r ${LIB}/$file ]; then + echo Fixing $file, definition of statsswtch + ex ${LIB}/$file </dev/null 2>&1; then + echo Deleting $2/$file\; no fixes were needed. + rm $2/$file + fi +fi + +# Deal with yet another challenge, this in X11/Xmu.h +file=X11/Xmu.h +if [ -r $file ]; then + if [ ! -r ${LIB}/$file ]; then + mkdir ${LIB}/X11 2>&- + cp $file ${LIB}/$file >/dev/null 2>&1 \ + || echo "Can't copy $file" + chmod +w ${LIB}/$file + fi +fi + +if [ -r ${LIB}/$file ]; then + echo Fixing $file sprintf declaration + ex ${LIB}/$file </dev/null 2>&1; then + echo Deleting ${LIB}/$file\; no fixes were needed. + rm ${LIB}/$file + fi +fi + +# Check for missing ';' in struct + +file=netinet/ip.h +if [ -r $file ]; then + if [ ! -r ${LIB}/$file ]; then + mkdir ${LIB}/netinet 2>&- + sed -e '/^struct/,/^};/s/}$/};/' $file > ${LIB}/$file + cmp $file ${LIB}/$file >&- && rm -f ${LIB}/$file + fi +fi + +# Fix the CAT macro in memvar.h. + +file=pixrect/memvar.h +if [ -r $file ]; then + if [ ! -r ${LIB}/$file ]; then + mkdir ${LIB}/pixrect 2>&- + sed -e '/^#define.CAT(a,b)/ s/IDENT(a)b/a##b/g' $file > ${LIB}/$file + cmp $file ${LIB}/$file >&- && rm -f ${LIB}/$file + fi +fi + +# Check for yet more missing ';' in struct (in SunOS 4.0.x) + +file=rpcsvc/rusers.h +if [ -r $file ]; then + if [ ! -r ${LIB}/$file ]; then + mkdir ${LIB}/rpcsvc 2>&- + sed -e '/^struct/,/^};/s/_cnt$/_cnt;/' $file > ${LIB}/$file + cmp $file ${LIB}/$file >&- && rm -f ${LIB}/$file + fi +fi + +# Check for yet more missing ';' in struct (in SunOS 4.0.x) + +file=rpcsvc/rusers.h +if [ -r $file ]; then + if [ ! -r ${LIB}/$file ]; then + mkdir ${LIB}/rpcsvc 2>&- + sed -e '/^struct/,/^};/s/_cnt$/_cnt;/' $file > ${LIB}/$file + cmp $file ${LIB}/$file >&- && rm -f ${LIB}/$file + fi +fi + +echo 'Removing unneeded directories:' +cd $LIB +files=`find . -type d -print | sort -r` +for file in $files; do + rmdir $LIB/$file > /dev/null 2>&1 +done + +if $LINKS; then + echo 'Making internal symbolic non-directory links' + cd /usr/include + files=`find . -type l -print` + 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|"` + if [ -f $target ]; then + ln -s $dest ${LIB}/$file >/dev/null 2>&1 + fi + fi + done +fi + +exit 0 diff --git a/gcc-1.40/fixincludes.old b/gcc-1.40/fixincludes.old new file mode 100755 index 0000000..5727ac9 --- /dev/null +++ b/gcc-1.40/fixincludes.old @@ -0,0 +1,165 @@ +#! /bin/sh +# Install modified versions of certain ANSI-incompatible system header files +# which are fixed to work correctly with ANSI C +# and placed in a directory that GNU C will search. +# This works properly on a Sun in system version 3.4; +# for other versions, you had better check. + +# Directory in which to store the results. +LIB=${LIB-/usr/local/lib/gcc-include} + +# Make sure it exists. +if [ ! -d $LIB ]; then + mkdir $LIB || exit 1 +fi + +# Determine whether this system has symbolic links. +if ln -s X $LIB/ShouldNotExist 2>/dev/null; then + rm -f $LIB/ShouldNotExist + LINKS=true +else + LINKS=false +fi + +echo 'Making directories:' +cd /usr/include +if $LINKS; then + files=`ls -LR | sed -n s/:$//p` +else + files=`find . -type d -print` +fi +for file in $files; do + rm -rf $LIB/$file + if [ ! -d $LIB/$file ] + then mkdir $LIB/$file + fi +done + +# treetops gets an alternating list +# of old directories to copy +# and the new directories to copy to. +treetops="/usr/include ${LIB}" + +if $LINKS; then + echo 'Making internal symbolic directory links' + for file in $files; do + dest=`ls -ld $file | sed -n 's/.*-> //p'` + if [ "$dest" ]; then + cwd=`pwd` + cd $dest + if [ $? = 0 ]; then + dest=`pwd` + cd $cwd + fi + if expr $dest : '[^/.].*' > /dev/null; then + rmdir ${LIB}/$file > /dev/null 2>&1 + rm -f ${LIB}/$file > /dev/null 2>&1 + ln -s $dest ${LIB}/$file > /dev/null 2>&1 + else # dont make links outside /usr/include + treetops="$treetops $dest ${LIB}/$file" + fi + fi + done +fi + +set - $treetops +while [ $# != 0 ]; do + # $1 is an old directory to copy, and $2 is the new directory to copy to. + echo "Finding header files in $1:" + cd /usr/include + cd $1 + files=`find . -type f -print` + echo 'Checking header files:' + for file in $files; do + if egrep '[ ]_IO[A-Z]*\(|#define._IO|CTRL' $file > /dev/null; then + echo Fixing $file + if [ -r $file ]; then + cp $file $2/$file >/dev/null 2>&1 \ + || echo "Can't copy $file" + chmod +w $2/$file + sed -e ' + :loop + /\\$/ N + /\\$/ b loop + /[ ]_IO[A-Z]*(/ s/(\(.\),/('\''\1'\'',/ + /#define._IO/ s/'\''x'\''/x/g + /[^A-Z]CTRL[ ]*(/ s/\(.\))/'\''\1'\'')/ + /#define.CTRL/ s/'\''c'\''/c/g + ' $2/$file > $2/$file.sed + mv $2/$file.sed $2/$file + if cmp $file $2/$file >/dev/null 2>&1; then + echo Deleting $2/$file\; no fixes were needed. + rm $2/$file + fi + fi + fi + done + shift; shift +done + +cd /usr/include + +# Fix one other error in this file: a mismatched quote not inside a C comment. +file=sundev/vuid_event.h +if [ -r $file ]; then + if [ ! -r ${LIB}/$file ]; then + cp $file ${LIB}/$file >/dev/null 2>&1 \ + || echo "Can't copy $file" + chmod +w ${LIB}/$file + fi +fi + +if [ -r ${LIB}/sundev/vuid_event.h ]; then + echo Fixing sundev/vuid_event.h comment + ex ${LIB}/sundev/vuid_event.h <&- + cp $file ${LIB}/$file >/dev/null 2>&1 \ + || echo "Can't copy $file" + chmod +w ${LIB}/$file + fi +fi + +if [ -r ${LIB}/$file ]; then + echo Fixing $file sprintf declaration + ex ${LIB}/$file < /dev/null 2>&1 +done + +if $LINKS; then + echo 'Making internal symbolic non-directory links' + cd /usr/include + files=`find . -type l -print` + 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|"` + if [ -f $target ]; then + ln -s $dest ${LIB}/$file >/dev/null 2>&1 + fi + fi + done +fi + +exit 0 diff --git a/gcc-1.40/flags.h b/gcc-1.40/flags.h new file mode 100644 index 0000000..f9c218f --- /dev/null +++ b/gcc-1.40/flags.h @@ -0,0 +1,191 @@ +/* Compilation switch flag definitions for GNU CC. + Copyright (C) 1987, 1988 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 1, 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. */ + +/* Name of the input .c file being compiled. */ +extern char *main_input_filename; + +/* 1 => write gdb debugging output (using symout.c). + 2 => write dbx debugging output (using dbxout.c). + 3 => write sdb debugging output (using sdbout.c). */ +enum debugger { NO_DEBUG = 0, GDB_DEBUG = 1, DBX_DEBUG = 2, SDB_DEBUG = 3, + EXTENDED_DBX_DEBUG = 4 }; + +extern enum debugger write_symbols; + +/* Nonzero means use GDB-only extensions of DBX format. */ +extern int use_gdb_dbx_extensions; + +/* Nonzero means do optimizations. -opt. */ + +extern int optimize; + +/* Nonzero means do stupid register allocation. -noreg. + This and `optimize' are controlled by different switches in cc1, + but normally cc controls them both with the -O switch. */ + +extern int obey_regdecls; + +/* Don't print functions as they are compiled and don't print + times taken by the various passes. -quiet. */ + +extern int quiet_flag; + +/* Don't print warning messages. -w. */ + +extern int inhibit_warnings; + +/* Do print extra warnings (such as for uninitialized variables). -W. */ + +extern int extra_warnings; + +/* Nonzero to warn about unused local variables. */ + +extern int warn_unused; + +/* Nonzero means warn about all declarations which shadow others. */ + +extern int warn_shadow; + +/* Warn if a switch on an enum fails to have a case for every enum value. */ + +extern int warn_switch; + +/* Nonzero means warn about any identifiers that match in the first N + characters. The value N is in `id_clash_len'. */ + +extern int warn_id_clash; +extern int id_clash_len; + +/* Nonzero if generating code to do profiling. */ + +extern int profile_flag; + +/* Nonzero if generating code to do profiling on the basis of basic blocks. */ + +extern int profile_block_flag; + +/* Nonzero for -pedantic switch: warn about anything + that standard C forbids. */ + +extern int pedantic; + +/* Now the symbols that are set with `-f' switches. */ + +/* Nonzero means `char' should be signed. */ + +extern int flag_signed_char; + +/* Nonzero means give an enum type only as many bytes as it needs. */ + +extern int flag_short_enums; + +/* Nonzero for -fcaller-saves: allocate values in regs that need to + be saved across function calls, if that produces overall better code. + Optional now, so people can test it. */ + +extern int flag_caller_saves; + +/* Nonzero for -fpcc-struct-return: return values the same way PCC does. */ + +extern int flag_pcc_struct_return; + +/* Nonzero for -fforce-mem: load memory value into a register + before arithmetic on it. This makes better cse but slower compilation. */ + +extern int flag_force_mem; + +/* Nonzero for -fforce-addr: load memory address into a register before + reference to memory. This makes better cse but slower compilation. */ + +extern int flag_force_addr; + +/* Nonzero for -fdefer-pop: don't pop args after each function call; + instead save them up to pop many calls' args with one insns. */ + +extern int flag_defer_pop; + +/* Nonzero for -ffloat-store: don't allocate floats and doubles + in extended-precision registers. */ + +extern int flag_float_store; + +/* Nonzero for -fcombine-regs: + allow instruction combiner to combine an insn + that just copies one reg to another. */ + +extern int flag_combine_regs; + +/* Nonzero enables strength-reduction in loop.c. */ + +extern int flag_strength_reduce; + +/* Nonzero for -fwritable-strings: + store string constants in data segment and don't uniquize them. */ + +extern int flag_writable_strings; + +/* Nonzero means don't put addresses of constant functions in registers. + Used for compiling the Unix kernel, where strange substitutions are + done on the assembly output. */ + +extern int flag_no_function_cse; + +/* Nonzero for -fomit-frame-pointer: + don't make a frame pointer in simple functions that don't require one. */ + +extern int flag_omit_frame_pointer; + +/* This isn't a flag, but everyone who needs flag_omit_frame_pointer + also needs this. + Nonzero means current function must be given a frame pointer. + Set in stmt.c if anything is allocated on the stack there. + Set in reload1.c if anything is allocated on the stack there. */ + +extern int frame_pointer_needed; + +/* Nonzero to inhibit use of define_optimization peephole opts. */ + +extern int flag_no_peephole; + +/* Nonzero means all references through pointers are volatile. */ + +extern int flag_volatile; + +/* Nonzero means make functions that look like good inline candidates + go inline. */ + +extern int flag_inline_functions; + +/* Nonzero for -fkeep-inline-functions: even if we make a function + go inline everywhere, keep its defintion around for debugging + purposes. */ + +extern int flag_keep_inline_functions; + +/* Nonzero if we are only using compiler to check syntax errors. */ + +extern int flag_syntax_only; + +/* Nonzero means make the text shared if supported. */ + +extern int flag_shared_data; + +/* Nonzero means put things in delayed-branch slots if supported. */ + +extern int flag_delayed_branch; diff --git a/gcc-1.40/flow.c b/gcc-1.40/flow.c new file mode 100644 index 0000000..956c960 --- /dev/null +++ b/gcc-1.40/flow.c @@ -0,0 +1,2094 @@ +/* Data flow analysis for GNU compiler. + Copyright (C) 1987, 1988 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 1, 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 contains the data flow analysis pass of the compiler. + It computes data flow information + which tells combine_instructions which insns to consider combining + and controls register allocation. + + Additional data flow information that is too bulky to record + is generated during the analysis, and is used at that time to + create autoincrement and autodecrement addressing. + + The first step is dividing the function into basic blocks. + find_basic_blocks does this. Then life_analysis determines + where each register is live and where it is dead. + + ** find_basic_blocks ** + + find_basic_blocks divides the current function's rtl + into basic blocks. It records the beginnings and ends of the + basic blocks in the vectors basic_block_head and basic_block_end, + and the number of blocks in n_basic_blocks. + + find_basic_blocks also finds any unreachable loops + and deletes them. + + ** life_analysis ** + + life_analysis is called immediately after find_basic_blocks. + It uses the basic block information to determine where each + hard or pseudo register is live. + + ** live-register info ** + + The information about where each register is live is in two parts: + the REG_NOTES of insns, and the vector basic_block_live_at_start. + + basic_block_live_at_start has an element for each basic block, + and the element is a bit-vector with a bit for each hard or pseudo + register. The bit is 1 if the register is live at the beginning + of the basic block. + + To each insn's REG_NOTES is added an element for each register + that is live before the insn or set by the insn, but is dead + after the insn. + + To determine which registers are live after any insn, one can + start from the beginning of the basic block and scan insns, noting + which registers are set by each insn and which die there. + + ** Other actions of life_analysis ** + + life_analysis sets up the LOG_LINKS fields of insns because the + information needed to do so is readily available. + + life_analysis deletes insns whose only effect is to store a value + that is never used. + + life_analysis notices cases where a reference to a register as + a memory address can be combined with a preceding or following + incrementation or decrementation of the register. The separate + instruction to increment or decrement is deleted and the address + is changed to a POST_INC or similar rtx. + + Each time an incrementing or decrementing address is created, + a REG_INC element is added to the insn's REG_NOTES list. + + life_analysis fills in certain vectors containing information about + register usage: reg_n_refs, reg_n_deaths, reg_n_sets, + reg_live_length, reg_n_calls_crosses and reg_basic_block. */ + +#include +#include "config.h" +#include "rtl.h" +#include "basic-block.h" +#include "regs.h" +#include "hard-reg-set.h" +#include "flags.h" + +#include "obstack.h" +#define obstack_chunk_alloc xmalloc +#define obstack_chunk_free free + +extern int xmalloc (); +extern void free (); + +/* Get the basic block number of an insn. + This info should not be expected to remain available + after the end of life_analysis. */ + +#define BLOCK_NUM(INSN) uid_block_number[INSN_UID (INSN)] + +/* This is where the BLOCK_NUM values are really stored. + This is set up by find_basic_blocks and used there and in life_analysis, + and then freed. */ + +static short *uid_block_number; + +/* INSN_VOLATILE (insn) is 1 if the insn refers to anything volatile. */ + +#define INSN_VOLATILE(INSN) uid_volatile[INSN_UID (INSN)] +static char *uid_volatile; + +/* Number of basic blocks in the current function. */ + +int n_basic_blocks; + +/* Maximum register number used in this function, plus one. */ + +int max_regno; + +/* 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. */ + +short *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. */ + +short *reg_n_refs; + +/* Indexed by n, gives number of times (REG n) is set. + This information remains valid for the rest of the compilation + of the current function; it is used to control register allocation. */ + +short *reg_n_sets; + +/* 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; + +/* Indexed by N, gives the uid of the first insn that mentions reg N, + provided that reg is local to one basic block. + The value here is undefined otherwise. */ + +rtx *reg_first_use; + +/* 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. + + local-alloc.c may alter this number to change the priority. + + 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-alloc.c makes an allocno for this but does + not try to assign a hard register to it. */ + +int *reg_live_length; + +/* 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. + This is valid only during the final backward scan in propagate_block. */ + +static rtx *reg_next_use; + +/* Size of a regset for the current function, + in (1) bytes and (2) elements. */ + +int regset_bytes; +int regset_size; + +/* Element N is first insn in basic block N. + This info lasts until we finish compiling the function. */ + +rtx *basic_block_head; + +/* Element N is last insn in basic block N. + This info lasts until we finish compiling the function. */ + +rtx *basic_block_end; + +/* 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. */ + +regset *basic_block_live_at_start; + +/* Regset of regs live when calls to `setjmp'-like functions happen. */ + +regset regs_live_at_setjmp; + +/* Element N is nonzero if control can drop into basic block N + from the preceding basic block. Freed after life_analysis. */ + +static char *basic_block_drops_in; + +/* Element N is depth within loops of basic block number N. + Freed after life_analysis. */ + +static short *basic_block_loop_depth; + +/* Element N nonzero if basic block N can actually be reached. + Vector exists only during find_basic_blocks. */ + +static char *block_live_static; + +/* Depth within loops of basic block being scanned for lifetime analysis, + plus one. This is the weight attached to references to registers. */ + +static int loop_depth; + +/* Define AUTO_INC_DEC if machine has any kind of incrementing + or decrementing addressing. */ + +#ifdef HAVE_PRE_DECREMENT +#define AUTO_INC_DEC +#endif + +#ifdef HAVE_PRE_INCREMENT +#define AUTO_INC_DEC +#endif + +#ifdef HAVE_POST_DECREMENT +#define AUTO_INC_DEC +#endif + +#ifdef HAVE_POST_INCREMENT +#define AUTO_INC_DEC +#endif + +/* Forward declarations */ +static void find_basic_blocks (); +static void life_analysis (); +static void mark_label_ref (); +void allocate_for_life_analysis (); /* Used also in stupid_life_analysis */ +static void init_regset_vector (); +static void propagate_block (); +static void mark_set_regs (); +static void mark_used_regs (); +static int insn_dead_p (); +static int libcall_dead_p (); +static int try_pre_increment (); +static int try_pre_increment_1 (); +static rtx find_use_as_address (); +void dump_flow_info (); + +/* Find basic blocks of the current function and perform data flow analysis. + F is the first insn of the function and NREGS the number of register numbers + in use. */ + +void +flow_analysis (f, nregs, file) + rtx f; + int nregs; + FILE *file; +{ + register rtx insn; + register int i; + register int max_uid = 0; + + /* Count the basic blocks. Also find maximum insn uid value used. */ + + { + register RTX_CODE prev_code = JUMP_INSN; + register RTX_CODE code; + + for (insn = f, i = 0; insn; insn = NEXT_INSN (insn)) + { + code = GET_CODE (insn); + if (INSN_UID (insn) > max_uid) + max_uid = INSN_UID (insn); + if (code == CODE_LABEL + || (prev_code != INSN && prev_code != CALL_INSN + && prev_code != CODE_LABEL + && (code == INSN || code == CALL_INSN || code == JUMP_INSN))) + i++; + if (code != NOTE) + prev_code = code; + } + } + + /* 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)); + uid_block_number = (short *) alloca ((max_uid + 1) * sizeof (short)); + uid_volatile = (char *) alloca (max_uid + 1); + bzero (uid_volatile, max_uid + 1); + + find_basic_blocks (f); + 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 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. */ + +static void +find_basic_blocks (f) + rtx f; +{ + register rtx insn; + register int i; + + /* Initialize the ref chain of each label to 0. */ + /* Record where all the blocks start and end and their depth in loops. */ + /* For each insn, record the block it is in. */ + + { + register RTX_CODE prev_code = JUMP_INSN; + register RTX_CODE code; + int depth = 1; + + for (insn = f, i = -1; insn; insn = NEXT_INSN (insn)) + { + code = GET_CODE (insn); + if (code == NOTE) + { + if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG) + depth++; + else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END) + depth--; + } + else if (code == CODE_LABEL + || (prev_code != INSN && prev_code != CALL_INSN + && prev_code != CODE_LABEL + && (code == INSN || code == CALL_INSN || code == JUMP_INSN))) + { + basic_block_head[++i] = insn; + basic_block_end[i] = insn; + basic_block_loop_depth[i] = depth; + if (code == CODE_LABEL) + LABEL_REFS (insn) = insn; + } + else if (code == INSN || code == CALL_INSN || code == JUMP_INSN) + basic_block_end[i] = insn; + BLOCK_NUM (insn) = i; + if (code != NOTE) + prev_code = code; + } + if (i + 1 != n_basic_blocks) + abort (); + } + + /* Record which basic blocks control can drop in to. */ + + { + register int i; + for (i = 0; i < n_basic_blocks; i++) + { + register rtx insn = PREV_INSN (basic_block_head[i]); + /* TEMP1 is used to avoid a bug in Sequent's compiler. */ + register int temp1; + while (insn && GET_CODE (insn) == NOTE) + insn = PREV_INSN (insn); + temp1 = insn && GET_CODE (insn) != BARRIER; + basic_block_drops_in[i] = temp1; + } + } + + /* Now find which basic blocks can actually be reached + and put all jump insns' LABEL_REFS onto the ref-chains + of their target labels. */ + + if (n_basic_blocks > 0) + { + register char *block_live = (char *) alloca (n_basic_blocks); + register char *block_marked = (char *) alloca (n_basic_blocks); + int something_marked = 1; + + /* Initialize with just block 0 reachable and no blocks marked. */ + + bzero (block_live, n_basic_blocks); + bzero (block_marked, n_basic_blocks); + block_live[0] = 1; + block_live_static = block_live; + + /* 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. + Then blocks_live and blocks_marked are identical and correct. + In addition, all jumps actually reachable have been marked. */ + + while (something_marked) + { + something_marked = 0; + for (i = 0; i < n_basic_blocks; i++) + if (block_live[i] && !block_marked[i]) + { + block_marked[i] = 1; + something_marked = 1; + if (i + 1 < n_basic_blocks && basic_block_drops_in[i + 1]) + block_live[i + 1] = 1; + insn = basic_block_end[i]; + if (GET_CODE (insn) == JUMP_INSN) + mark_label_ref (PATTERN (insn), insn, 0); + } + } + + /* Now delete the code for any basic blocks that can't be reached. + They can occur because jump_optimize does not recognize + unreachable loops as unreachable. */ + + for (i = 0; i < n_basic_blocks; i++) + if (!block_live[i]) + { + insn = basic_block_head[i]; + while (1) + { + if (GET_CODE (insn) == BARRIER) + abort (); + if (GET_CODE (insn) != NOTE) + { + PUT_CODE (insn, NOTE); + NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED; + NOTE_SOURCE_FILE (insn) = 0; + } + if (insn == basic_block_end[i]) + { + /* BARRIERs are between basic blocks, not part of one. + Delete a BARRIER if the preceding jump is deleted. + We cannot alter a BARRIER into a NOTE + because it is too short; but we can really delete + it because it is not part of a basic block. */ + if (NEXT_INSN (insn) != 0 + && GET_CODE (NEXT_INSN (insn)) == BARRIER) + delete_insn (NEXT_INSN (insn)); + break; + } + insn = NEXT_INSN (insn); + } + /* Each time we delete some basic blocks, + see if there is a jump around them that is + being turned into a no-op. If so, delete it. */ + + if (block_live[i - 1]) + { + register int j; + for (j = i; j < n_basic_blocks; j++) + if (block_live[j]) + { + rtx label; + insn = basic_block_end[i - 1]; + if (GET_CODE (insn) == JUMP_INSN + /* An unconditional jump is the only possibility + we must check for, since a conditional one + would make these blocks live. */ + && simplejump_p (insn) + && (label = XEXP (SET_SRC (PATTERN (insn)), 0), 1) + && INSN_UID (label) != 0 + && BLOCK_NUM (label) == j) + { + PUT_CODE (insn, NOTE); + NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED; + NOTE_SOURCE_FILE (insn) = 0; + if (GET_CODE (NEXT_INSN (insn)) != BARRIER) + abort (); + delete_insn (NEXT_INSN (insn)); + } + break; + } + } + } + } +} + +/* Check expression X for label references; + if one is found, add INSN to the label's chain of references. + + CHECKDUP means check for and avoid creating duplicate references + from the same insn. Such duplicates do no serious harm but + can slow life analysis. CHECKDUP is set only when duplicates + are likely. */ + +static void +mark_label_ref (x, insn, checkdup) + rtx x, insn; + int checkdup; +{ + register RTX_CODE code = GET_CODE (x); + register int i; + register char *fmt; + + if (code == LABEL_REF) + { + register rtx label = XEXP (x, 0); + register rtx y; + if (GET_CODE (label) != CODE_LABEL) + abort (); + /* If the label was never emitted, this insn is junk, + but avoid a crash trying to refer to BLOCK_NUM (label). + This can happen as a result of a syntax error + and a diagnostic has already been printed. */ + if (INSN_UID (label) == 0) + return; + CONTAINING_INSN (x) = insn; + /* if CHECKDUP is set, check for duplicate ref from same insn + and don't insert. */ + if (checkdup) + for (y = LABEL_REFS (label); y != label; y = LABEL_NEXTREF (y)) + if (CONTAINING_INSN (y) == insn) + return; + LABEL_NEXTREF (x) = LABEL_REFS (label); + LABEL_REFS (label) = x; + block_live_static[BLOCK_NUM (label)] = 1; + return; + } + + fmt = GET_RTX_FORMAT (code); + for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) + { + if (fmt[i] == 'e') + mark_label_ref (XEXP (x, i), insn, 0); + if (fmt[i] == 'E') + { + register int j; + for (j = 0; j < XVECLEN (x, i); j++) + mark_label_ref (XVECEXP (x, i, j), insn, 1); + } + } +} + +/* Determine the 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. + We allocate the vector basic_block_live_at_start + and the regsets that it points to, and fill them with the data. + regset_size and regset_bytes are also set here. */ + +static void +life_analysis (f, nregs) + rtx f; + int nregs; +{ + register regset tem; + int first_pass; + int changed; + /* For each basic block, a bitmask of regs + live on exit from the block. */ + regset *basic_block_live_at_end; + /* For each basic block, a bitmask of regs + live on entry to a successor-block of this block. + If this does not match basic_block_live_at_end, + that must be updated, and the block must be rescanned. */ + regset *basic_block_new_live_at_end; + /* For each basic block, a bitmask of regs + whose liveness at the end of the basic block + can make a difference in which regs are live on entry to the block. + These are the regs that are set within the basic block, + possibly excluding those that are used after they are set. */ + regset *basic_block_significant; + register int i; + rtx insn; + + struct obstack flow_obstack; + + obstack_init (&flow_obstack); + + max_regno = nregs; + + bzero (regs_ever_live, sizeof regs_ever_live); + + /* Allocate and zero out many data structures + that will record the data from lifetime analysis. */ + + allocate_for_life_analysis (); + + reg_next_use = (rtx *) alloca (nregs * sizeof (rtx)); + bzero (reg_next_use, nregs * sizeof (rtx)); + + /* Set up several regset-vectors used internally within this function. + Their meanings are documented above, with their declarations. */ + + basic_block_live_at_end = (regset *) alloca (n_basic_blocks * sizeof (regset)); + /* Don't use alloca since that leads to a crash rather than an error message + 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 (tem, n_basic_blocks * regset_bytes); + init_regset_vector (basic_block_live_at_end, tem, n_basic_blocks, regset_bytes); + + 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 (tem, n_basic_blocks * regset_bytes); + init_regset_vector (basic_block_new_live_at_end, tem, n_basic_blocks, regset_bytes); + + basic_block_significant = (regset *) alloca (n_basic_blocks * sizeof (regset)); + tem = (regset) obstack_alloc (&flow_obstack, n_basic_blocks * regset_bytes); + bzero (tem, n_basic_blocks * regset_bytes); + init_regset_vector (basic_block_significant, tem, n_basic_blocks, regset_bytes); + + /* 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. */ + + for (insn = f; insn; insn = NEXT_INSN (insn)) + { + enum rtx_code code1 = GET_CODE (insn); + if (code1 == CALL_INSN) + INSN_VOLATILE (insn) = 1; + else if (code1 == INSN || code1 == JUMP_INSN) + { + 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)))) + { + PUT_CODE (insn, NOTE); + NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED; + NOTE_SOURCE_FILE (insn) = 0; + } + else if (GET_CODE (PATTERN (insn)) != USE) + INSN_VOLATILE (insn) = volatile_refs_p (PATTERN (insn)); + /* A SET that makes space on the stack cannot be dead. + (Such SETs occur only for allocating variable-size data, + so they will always have a PLUS or MINUS according to the + direction of stack growth.) + Even if this function never uses this stack pointer value, + signal handlers do! */ + else if (code1 == INSN && GET_CODE (PATTERN (insn)) == SET + && SET_DEST (PATTERN (insn)) == stack_pointer_rtx +#ifdef STACK_GROWS_DOWNWARD + && GET_CODE (SET_SRC (PATTERN (insn))) == MINUS +#else + && GET_CODE (SET_SRC (PATTERN (insn))) == PLUS +#endif + && XEXP (SET_SRC (PATTERN (insn)), 0) == stack_pointer_rtx) + INSN_VOLATILE (insn) = 1; + } + } + + if (n_basic_blocks > 0) +#ifdef EXIT_IGNORE_STACK + if (! (EXIT_IGNORE_STACK) || ! frame_pointer_needed) +#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] + |= 1 << (STACK_POINTER_REGNUM % REGSET_ELT_BITS); + basic_block_new_live_at_end[n_basic_blocks - 1] + [STACK_POINTER_REGNUM / REGSET_ELT_BITS] + |= 1 << (STACK_POINTER_REGNUM % REGSET_ELT_BITS); + } + + /* Propagate life info through the basic blocks + around the graph of basic blocks. + + This is a relaxation process: each time a new register + is live at the end of the basic block, we must scan the block + to determine which registers are, as a consequence, live at the beginning + of that block. These registers must then be marked live at the ends + of all the blocks that can transfer control to that block. + The process continues until it reaches a fixed point. */ + + first_pass = 1; + changed = 1; + while (changed) + { + changed = 0; + for (i = n_basic_blocks - 1; i >= 0; i--) + { + int consider = first_pass; + int must_rescan = first_pass; + register int j; + + /* Set CONSIDER if this block needs thinking about at all + (that is, if the regs live now at the end of it + are not the same as were live at the end of it when + we last thought about it). + Set must_rescan if it needs to be thought about + instruction by instruction (that is, if any additional + 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 int 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; + } + } + + if (! consider) + continue; + + /* The live_at_start of this block may be changing, + so another pass will be required after this one. */ + changed = 1; + + if (! must_rescan) + { + /* 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 int 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; + } + } + else + { + /* Update the basic_block_live_at_start + by propagation backwards through the block. */ + bcopy (basic_block_new_live_at_end[i], + basic_block_live_at_end[i], regset_bytes); + bcopy (basic_block_live_at_end[i], + basic_block_live_at_start[i], regset_bytes); + propagate_block (basic_block_live_at_start[i], + basic_block_head[i], basic_block_end[i], 0, + first_pass ? basic_block_significant[i] : 0, + i); + } + + { + register rtx jump, head; + /* Update the basic_block_new_live_at_end's of the block + that falls through into this one (if any). */ + head = basic_block_head[i]; + jump = PREV_INSN (head); + if (basic_block_drops_in[i]) + { + register int from_block = BLOCK_NUM (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]; + } + /* Update the basic_block_new_live_at_end's of + all the blocks that jump to this one. */ + if (GET_CODE (head) == CODE_LABEL) + for (jump = LABEL_REFS (head); + jump != head; + 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]; + } + } +#ifdef USE_C_ALLOCA + alloca (0); +#endif + } + first_pass = 0; + } + +#if 0 /* This seems unnecessary; life at start of function shouldn't + mean that the reg is live in more than one basic block. */ + + /* Process the regs live at the beginning of the function. + Mark them as not local to any 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] + & (1 << (i % REGSET_ELT_BITS))) + reg_basic_block[i] = REG_BLOCK_GLOBAL; +#endif + + /* Now the life information is accurate. + Make one more pass over each basic block + to delete dead stores, create autoincrement addressing + and record how many times each register is used, is set, or dies. + + To save time, we operate directly in basic_block_live_at_end[i], + thus destroying it (in fact, converting it into a copy of + basic_block_live_at_start[i]). This is ok now because + basic_block_live_at_end[i] is no longer used past this point. */ + + for (i = 0; i < n_basic_blocks; i++) + { + propagate_block (basic_block_live_at_end[i], + basic_block_head[i], basic_block_end[i], 1, 0, i); +#ifdef USE_C_ALLOCA + alloca (0); +#endif + } + +#if 0 + /* Something live during a setjmp should not be put in a register + on certain machines which restore regs from stack frames + rather than from the jmpbuf. + 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] & (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; + } +#endif +#endif + + /* We have a problem with any pseudoreg that + lives across the setjmp. ANSI says that if a + user variable does not change in value + between the setjmp and the longjmp, then the longjmp preserves it. + This includes longjmp from a place where the pseudo appears dead. + (In principle, the value still exists if it is in scope.) + 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] & (1 << (i % REGSET_ELT_BITS)) + && regno_reg_rtx[i] != 0) + { + reg_live_length[i] = -1; + reg_basic_block[i] = -1; + } + + obstack_free (&flow_obstack, 0); +} + +/* Subroutines of life analysis. */ + +/* Allocate the permanent data structures that represent the results + of life analysis. Not static since used also for stupid life analysis. */ + +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 = (short *) oballoc (max_regno * sizeof (short)); + bzero (reg_n_refs, max_regno * sizeof (short)); + + reg_n_sets = (short *) oballoc (max_regno * sizeof (short)); + bzero (reg_n_sets, max_regno * sizeof (short)); + + reg_n_deaths = (short *) oballoc (max_regno * sizeof (short)); + bzero (reg_n_deaths, max_regno * sizeof (short)); + + reg_first_use = (rtx *) oballoc (max_regno * sizeof (rtx)); + bzero (reg_first_use, max_regno * sizeof (rtx)); + + reg_live_length = (int *) oballoc (max_regno * sizeof (int)); + bzero (reg_live_length, max_regno * sizeof (int)); + + reg_n_calls_crossed = (int *) oballoc (max_regno * sizeof (int)); + bzero (reg_n_calls_crossed, max_regno * sizeof (int)); + + reg_basic_block = (short *) oballoc (max_regno * sizeof (short)); + for (i = 0; i < max_regno; i++) + reg_basic_block[i] = REG_BLOCK_UNKNOWN; + + basic_block_live_at_start = (regset *) oballoc (n_basic_blocks * sizeof (regset)); + tem = (regset) oballoc (n_basic_blocks * regset_bytes); + bzero (tem, n_basic_blocks * regset_bytes); + init_regset_vector (basic_block_live_at_start, tem, n_basic_blocks, regset_bytes); + + regs_live_at_setjmp = (regset) oballoc (regset_bytes); + bzero (regs_live_at_setjmp, regset_bytes); +} + +/* 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. */ + +static void +init_regset_vector (vector, space, nelts, bytes_per_elt) + regset *vector; + regset space; + int nelts; + int bytes_per_elt; +{ + register int i; + register regset p = space; + + for (i = 0; i < nelts; i++) + { + vector[i] = p; + p += bytes_per_elt / sizeof (*p); + } +} + +/* Compute the registers live at the beginning of a basic block + from those live at the end. + + When called, OLD contains those live at the end. + On return, it contains those live at the beginning. + FIRST and LAST are the first and last insns of the basic block. + + FINAL is nonzero if we are doing the final pass which is not + for computing the life info (since that has already been done) + but for acting on it. On this pass, we delete dead stores, + set up the logical links and dead-variables lists of instructions, + and merge instructions for autoincrement and autodecrement addresses. + + SIGNIFICANT is nonzero only the first time for each basic block. + If it is nonzero, it points to a regset in which we store + a 1 for each register that is set within the block. + + BNUM is the number of the basic block. */ + +static void +propagate_block (old, first, last, final, significant, bnum) + register regset old; + rtx first; + rtx last; + int final; + regset significant; + int bnum; +{ + register rtx insn; + rtx prev; + regset live; + regset dead; + + /* 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 foo { short offset; short bit; } *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. */ + regset maxlive; + + loop_depth = basic_block_loop_depth[bnum]; + + dead = (regset) alloca (regset_bytes); + live = (regset) alloca (regset_bytes); + + if (final) + { + register int i, offset, bit; + + maxlive = (regset) alloca (regset_bytes); + bcopy (old, maxlive, regset_bytes); + regs_sometimes_live + = (struct foo *) alloca (max_regno * sizeof (struct foo)); + + /* 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++; + } + } + } + + /* Include any notes at the end of the block in the scan. + This is in case the block ends with a call to setjmp. */ + + while (NEXT_INSN (last) != 0 && GET_CODE (NEXT_INSN (last)) == NOTE) + last = NEXT_INSN (last); + + /* Scan the block an insn at a time from end to beginning. */ + + for (insn = last; ; insn = prev) + { + prev = PREV_INSN (insn); + + /* If this is a call to `setjmp' et al, + warn if any non-volatile datum is live. */ + + if (final && GET_CODE (insn) == NOTE + && NOTE_LINE_NUMBER (insn) == NOTE_INSN_SETJMP) + { + int i; + for (i = 0; i < regset_size; i++) + regs_live_at_setjmp[i] |= old[i]; + } + + /* Update the life-status of regs for this insn. + First DEAD gets which regs are set in this insn + then LIVE gets which regs are used in this insn. + Then the regs live before the insn + are those live after, with DEAD regs turned off, + and then LIVE regs turned on. */ + + if (GET_CODE (insn) == INSN + || GET_CODE (insn) == JUMP_INSN + || GET_CODE (insn) == CALL_INSN) + { + register int i; + rtx note = find_reg_note (insn, REG_RETVAL, 0); + + /* If an instruction consists of just dead store(s) on final pass, + "delete" it by turning it into a NOTE of type NOTE_INSN_DELETED. + We could really delete it with delete_insn, but that + can cause trouble for first or last insn in a basic block. */ + if (final && insn_dead_p (PATTERN (insn), old, 1) + /* Don't delete something that refers to volatile storage! */ + && ! INSN_VOLATILE (insn)) + { + rtx oldpat = PATTERN (insn); + PUT_CODE (insn, NOTE); + NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED; + NOTE_SOURCE_FILE (insn) = 0; + /* If this insn is copying the return value from a library call, + delete the entire library call. */ + if (note && libcall_dead_p (oldpat, old)) + { + rtx first = XEXP (note, 0); + rtx prev = insn; + while (INSN_DELETED_P (first)) + first = NEXT_INSN (first); + while (prev != first) + { + prev = PREV_INSN (prev); + PUT_CODE (prev, NOTE); + NOTE_LINE_NUMBER (prev) = NOTE_INSN_DELETED; + NOTE_SOURCE_FILE (prev) = 0; + } + } + 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 */ + } + + /* 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); + /* Does this instruction increment or decrement a register? */ + if (final && GET_CODE (x) == SET + && GET_CODE (SET_DEST (x)) == REG + && (GET_CODE (SET_SRC (x)) == PLUS + || GET_CODE (SET_SRC (x)) == MINUS) + && XEXP (SET_SRC (x), 0) == SET_DEST (x) + && GET_CODE (XEXP (SET_SRC (x), 1)) == CONST_INT + /* Ok, look for a following memory ref we can combine with. + If one is found, change the memory ref to a PRE_INC + or PRE_DEC, cancel this insn, and return 1. + Return 0 if nothing has been done. */ + && try_pre_increment_1 (insn)) + goto flushed; + } +#endif /* AUTO_INC_DEC */ + + /* If this is not the final pass, and this insn is copying the + value of a library call and it's dead, don't scan the + insns that perform the library call, so that the call's + arguments are not marked live. */ + if (note && insn_dead_p (PATTERN (insn), old, 1) + && libcall_dead_p (PATTERN (insn), old)) + { + /* Mark the dest reg as `significant'. */ + mark_set_regs (old, dead, PATTERN (insn), 0, significant); + + insn = XEXP (note, 0); + prev = PREV_INSN (insn); + } + else if (GET_CODE (PATTERN (insn)) == SET + && SET_DEST (PATTERN (insn)) == stack_pointer_rtx + && GET_CODE (SET_SRC (PATTERN (insn))) == PLUS + && XEXP (SET_SRC (PATTERN (insn)), 0) == stack_pointer_rtx + && GET_CODE (XEXP (SET_SRC (PATTERN (insn)), 1)) == CONST_INT) + /* We have an insn to pop a constant amount off the stack. + (Such insns use PLUS regardless of the direction of the stack, + and any insn to adjust the stack by a constant is always a pop.) + These insns, if not dead stores, have no effect on life. */ + ; + else + { + /* LIVE gets the regs used in INSN; DEAD gets those set by it. */ + mark_set_regs (old, dead, PATTERN (insn), final ? insn : 0, + significant); + mark_used_regs (old, live, PATTERN (insn), final, insn); + + /* Update OLD for the registers used or set. */ + for (i = 0; i < regset_size; i++) + { + old[i] &= ~dead[i]; + old[i] |= live[i]; + } + + if (GET_CODE (insn) == CALL_INSN) + { + register int i; + + /* Each call clobbers all call-clobbered regs. + Note that the function-value reg is one of these, 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]) + dead[i / REGSET_ELT_BITS] |= + (1 << (i % REGSET_ELT_BITS)); + + /* The stack ptr is used (honorarily) by a CALL insn. */ + live[STACK_POINTER_REGNUM / REGSET_ELT_BITS] + |= (1 << (STACK_POINTER_REGNUM % REGSET_ELT_BITS)); + } + + /* Update OLD for the registers used or set. */ + for (i = 0; i < regset_size; i++) + { + old[i] &= ~dead[i]; + old[i] |= live[i]; + } + + if (GET_CODE (insn) == CALL_INSN && final) + { + /* Any regs live at the time of a call instruction + must not go in a register clobbered by calls. + Find all regs now live and record this for them. */ + + register struct foo *p = regs_sometimes_live; + + for (i = 0; i < sometimes_max; i++, p++) + if (old[p->offset] & (1 << p->bit)) + reg_n_calls_crossed[p->offset * REGSET_ELT_BITS + p->bit]+= 1; + } + } + + /* On final pass, add any additional sometimes-live regs + into MAXLIVE and REGS_SOMETIMES_LIVE. + Also update counts of how many insns each reg is live at. */ + + if (final) + { + for (i = 0; i < regset_size; i++) + { + register int diff = live[i] & ~maxlive[i]; + + if (diff) + { + register int regno; + maxlive[i] |= diff; + for (regno = 0; diff && regno < REGSET_ELT_BITS; regno++) + if (diff & (1 << regno)) + { + regs_sometimes_live[sometimes_max].offset = i; + regs_sometimes_live[sometimes_max].bit = regno; + diff &= ~ (1 << regno); + sometimes_max++; + } + } + } + + { + register struct foo *p = regs_sometimes_live; + for (i = 0; i < sometimes_max; i++, p++) + { + if (old[p->offset] & (1 << p->bit)) + reg_live_length[p->offset * REGSET_ELT_BITS + p->bit]++; + } + } + } + } + flushed: ; + if (insn == first) + break; + } +} + +/* Return 1 if X (the body of an insn, or part of it) is just dead stores + (SET expressions whose destinations are registers dead after the insn). + NEEDED is the regset that says which regs are alive after the insn. */ + +static int +insn_dead_p (x, needed, strict_low_ok) + rtx x; + regset needed; + int strict_low_ok; +{ + register RTX_CODE code = GET_CODE (x); +#if 0 + /* Make sure insns to set the stack pointer are never deleted. */ + needed[STACK_POINTER_REGNUM / REGSET_ELT_BITS] + |= 1 << (STACK_POINTER_REGNUM % REGSET_ELT_BITS); +#endif + + /* 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); + /* A SET that is a subroutine call cannot be dead. */ + if (GET_CODE (SET_SRC (x)) == CALL) + return 0; + while (GET_CODE (r) == SUBREG + || (strict_low_ok && GET_CODE (r) == STRICT_LOW_PART) + || GET_CODE (r) == ZERO_EXTRACT + || GET_CODE (r) == SIGN_EXTRACT) + r = SUBREG_REG (r); + if (GET_CODE (r) == REG) + { + register int regno = REGNO (r); + register int offset = regno / REGSET_ELT_BITS; + register int bit = 1 << (regno % REGSET_ELT_BITS); + return (! (regno < FIRST_PSEUDO_REGISTER && global_regs[regno]) + && (needed[offset] & bit) == 0); + } + } + /* 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); + for (i--; i >= 0; i--) + { + rtx elt = XVECEXP (x, 0, i); + if (!insn_dead_p (elt, needed, strict_low_ok) + && GET_CODE (elt) != CLOBBER + && GET_CODE (elt) != USE) + 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. */ + return 0; +} + +/* If X is the last insn in a libcall, and assuming X is dead, + return 1 if the entire library call is dead. + This is true if the source of X is a dead register + (as well as the destination, which we tested already). + If this insn doesn't just copy a register, then we don't + have an ordinary libcall. In that case, cse could not have + managed to substitute the source for the dest later on, + so we can assume the libcall is dead. */ + +static int +libcall_dead_p (x, needed) + rtx x; + regset needed; +{ + register RTX_CODE code = GET_CODE (x); + + if (code == SET) + { + register rtx r = SET_SRC (x); + if (GET_CODE (r) == REG) + { + register int regno = REGNO (r); + register int offset = regno / REGSET_ELT_BITS; + register int bit = 1 << (regno % REGSET_ELT_BITS); + return (needed[offset] & bit) == 0; + } + } + return 1; +} + +/* Return 1 if register REGNO was used before it was set. + In other words, if it is live at function entry. */ + +int +regno_uninitialized (regno) + int regno; +{ + if (n_basic_blocks == 0) + return 0; + + return (basic_block_live_at_start[0][regno / REGSET_ELT_BITS] + & (1 << (regno % REGSET_ELT_BITS))); +} + +/* 1 if register REGNO was alive at a place where `setjmp' was called + and was set more than once. Such regs may be clobbered by `longjmp'. */ + +int +regno_clobbered_at_setjmp (regno) + int regno; +{ + return (reg_n_sets[regno] > 1 + && (regs_live_at_setjmp[regno / REGSET_ELT_BITS] + & (1 << (regno % REGSET_ELT_BITS)))); +} + +/* Process the registers that are set within X. + Their bits are set to 1 in the regset DEAD, + because they are dead prior to this insn. + + If INSN is nonzero, it is the insn being processed + and the fact that it is nonzero implies this is the FINAL pass + in propagate_block. In this case, various info about register + usage is stored, LOG_LINKS fields of insns are set up. */ + +static void mark_set_1 (); + +static void +mark_set_regs (needed, dead, x, insn, significant) + regset needed; + regset dead; + rtx x; + rtx insn; + regset significant; +{ + register RTX_CODE code = GET_CODE (x); + + if (code == SET || code == CLOBBER) + mark_set_1 (needed, dead, x, insn, significant); + 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) + mark_set_1 (needed, dead, XVECEXP (x, 0, i), insn, significant); + } + } +} + +/* Process a single SET rtx, X. */ + +static void +mark_set_1 (needed, dead, x, insn, significant) + regset needed; + regset dead; + rtx x; + rtx insn; + regset significant; +{ + register int regno; + register rtx reg = SET_DEST (x); + int subreg_p = 0; + + if (reg == 0) + return; + /* Modifying just one hardware register of a multi-reg value + or just a byte field of a register + does not mean the value from before this insn is now dead. + But it does mean liveness of that register at the end of the block + is significant. */ + while (GET_CODE (reg) == SUBREG || GET_CODE (reg) == ZERO_EXTRACT + || GET_CODE (reg) == SIGN_EXTRACT + || GET_CODE (reg) == STRICT_LOW_PART) + { + if (GET_CODE (reg) == ZERO_EXTRACT + || GET_CODE (reg) == SIGN_EXTRACT + || (GET_CODE (reg) == SUBREG + && REG_SIZE (SUBREG_REG (reg)) > REG_SIZE (reg))) + subreg_p = 1; + + reg = XEXP (reg, 0); + } + + if (GET_CODE (reg) == REG + && (regno = REGNO (reg), regno != FRAME_POINTER_REGNUM) + && regno != ARG_POINTER_REGNUM + && ! (regno < FIRST_PSEUDO_REGISTER && global_regs[regno])) + /* && regno != STACK_POINTER_REGNUM) -- let's try without this. */ + { + register int offset = regno / REGSET_ELT_BITS; + register int bit = 1 << (regno % REGSET_ELT_BITS); + int is_needed = 0; + + /* Mark it as a significant register for this basic block. */ + if (significant) + significant[offset] |= bit; + /* That's all we do, if we are setting only part of the register. */ + if (subreg_p) + return; + + /* If entire register being set, mark it as as dead before this insn. */ + dead[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) + { + int n; + + /* Nothing below is needed for the stack pointer; get out asap. + Eg, log links aren't needed, since combine won't use them. */ + if (regno == STACK_POINTER_REGNUM) + return; + + n = HARD_REGNO_NREGS (regno, GET_MODE (reg)); + while (--n > 0) + { + dead[(regno + n) / REGSET_ELT_BITS] + |= 1 << ((regno + n) % REGSET_ELT_BITS); + if (significant) + significant[(regno + n) / REGSET_ELT_BITS] + |= 1 << ((regno + n) % REGSET_ELT_BITS); + is_needed |= (needed[(regno + n) / REGSET_ELT_BITS] + & 1 << ((regno + n) % REGSET_ELT_BITS)); + } + } + /* Additional data to record if this is the final pass. */ + if (insn) + { + register rtx y = reg_next_use[regno]; + register int blocknum = BLOCK_NUM (insn); + + /* If this is a hard reg, record this function uses the reg. + `combine.c' will get confused if LOG_LINKs are made + for hard regs. */ + + if (regno < FIRST_PSEUDO_REGISTER) + { + register int i; + i = HARD_REGNO_NREGS (regno, GET_MODE (reg)); + if (i == 0) + i = 1; + do + regs_ever_live[regno + --i] = 1; + while (i > 0); + + if (! ((needed[offset] & bit) || is_needed)) + { + /* Note that dead stores have already been deleted if poss. + If we get here, we have found a dead store that cannot + be eliminated (because the insn does something useful). + Indicate this by marking the reg set as dying here. */ + REG_NOTES (insn) + = gen_rtx (EXPR_LIST, REG_DEAD, + reg, REG_NOTES (insn)); + reg_n_deaths[REGNO (reg)]++; + } + return; + } + + /* 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; + + /* Record first insn to use this reg. */ + reg_first_use[regno] = insn; + + /* Count (weighted) references, stores, etc. */ + reg_n_refs[regno] += loop_depth; + reg_n_sets[regno]++; + /* The next use is no longer "next", since a store intervenes. */ + reg_next_use[regno] = 0; + /* 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]++; + if ((needed[offset] & bit) || is_needed) + { + /* Make a logical link from the next following insn + that uses this register, back to this insn. + The following insns have already been processed. */ + if (y && (BLOCK_NUM (y) == blocknum)) + LOG_LINKS (y) + = gen_rtx (INSN_LIST, VOIDmode, insn, LOG_LINKS (y)); + } + else + { + /* Note that dead stores have already been deleted when possible + If we get here, we have found a dead store that cannot + 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_DEAD, + reg, REG_NOTES (insn)); + reg_n_deaths[REGNO (reg)]++; + } + } + } +} + +/* Scan expression X and store a 1-bit in LIVE for each reg it uses. + This is done assuming the registers needed from X + are those that have 1-bits in NEEDED. + + On the final pass, FINAL is 1. This means try for autoincrement + and count the uses and deaths of each pseudo-reg. + + INSN is the containing instruction. */ + +static void +mark_used_regs (needed, live, x, final, insn) + regset needed; + regset live; + rtx x; + rtx insn; + int final; +{ + register RTX_CODE code; + register int regno; + + retry: + code = GET_CODE (x); + switch (code) + { + case LABEL_REF: + case SYMBOL_REF: + case CONST_INT: + case CONST: + case CONST_DOUBLE: + case CC0: + case PC: + case CLOBBER: + case ADDR_VEC: + case ADDR_DIFF_VEC: + case ASM_INPUT: + return; + +#if defined (HAVE_POST_INCREMENT) || defined (HAVE_POST_DECREMENT) + case MEM: + /* Here we detect use of an index register which might + be good for postincrement or postdecrement. */ + if (final) + { + rtx addr = XEXP (x, 0); + register int size = GET_MODE_SIZE (GET_MODE (x)); + + if (GET_CODE (addr) == REG) + { + register rtx y; + regno = REGNO (addr); + /* Is the next use an increment that might make auto-increment? */ + y = reg_next_use[regno]; + if (y && GET_CODE (PATTERN (y)) == SET + && BLOCK_NUM (y) == BLOCK_NUM (insn) + /* Can't add side effects to jumps; if reg is spilled and + reloaded, there's no way to store back the altered value. */ + && GET_CODE (insn) != JUMP_INSN + && (y = SET_SRC (PATTERN (y)), + (0 +#ifdef HAVE_POST_INCREMENT + || GET_CODE (y) == PLUS +#endif +#ifdef HAVE_POST_DECREMENT + || GET_CODE (y) == MINUS +#endif + ) + && XEXP (y, 0) == addr + && GET_CODE (XEXP (y, 1)) == CONST_INT + && INTVAL (XEXP (y, 1)) == size) + && dead_or_set_p (reg_next_use[regno], addr)) + { + rtx use = find_use_as_address (PATTERN (insn), addr, 0); + + /* Make sure this register appears only once in this insn. */ + if (use != 0 && use != (rtx) 1) + { + /* We have found a suitable auto-increment: + do POST_INC around the register here, + and patch out the increment instruction that follows. */ + XEXP (x, 0) + = gen_rtx (GET_CODE (y) == PLUS ? POST_INC : POST_DEC, + Pmode, addr); + /* Record that this insn has an implicit side effect. */ + 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. */ + y = reg_next_use[regno]; + SET_SRC (PATTERN (y)) = addr; + + /* If that makes it a no-op (copying the register + into itself) then change it to a simpler no-op + so it won't appear to be a "use" and a "set" + of this register. */ + if (SET_DEST (PATTERN (y)) == addr) + PATTERN (y) = gen_rtx (USE, VOIDmode, const0_rtx); + + /* Count an extra reference to the reg for the increment. + When a reg is incremented. + spilling it is worse, so we want to make that + less likely. */ + 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]++; + } + } + } + } + break; +#endif /* HAVE_POST_INCREMENT or HAVE_POST_DECREMENT */ + + case REG: + /* See a register other than being set + => mark it as needed. */ + + regno = REGNO (x); + if (regno != FRAME_POINTER_REGNUM) + /* && regno != ARG_POINTER_REGNUM) -- and without this. */ + /* && regno != STACK_POINTER_REGNUM) -- let's try without this. */ + { + register int offset = regno / REGSET_ELT_BITS; + register int bit = 1 << (regno % REGSET_ELT_BITS); + int is_needed = 0; + + 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) + { + int n; + + /* For stack ptr or arg pointer, + nothing below can be necessary, so waste no more time. */ + if (regno == STACK_POINTER_REGNUM + || regno == ARG_POINTER_REGNUM) + return; + /* No death notes for global register variables; + their values are live after this function exits. */ + if (global_regs[regno]) + return; + + n = HARD_REGNO_NREGS (regno, GET_MODE (x)); + while (--n > 0) + { + live[(regno + n) / REGSET_ELT_BITS] + |= 1 << ((regno + n) % REGSET_ELT_BITS); + is_needed |= (needed[(regno + n) / REGSET_ELT_BITS] + & 1 << ((regno + n) % REGSET_ELT_BITS)); + } + } + if (final) + { + if (regno < FIRST_PSEUDO_REGISTER) + { + /* If a hard reg is being used, + record that this function does use it. */ + + register int i; + i = HARD_REGNO_NREGS (regno, GET_MODE (x)); + if (i == 0) + i = 1; + do + regs_ever_live[regno + --i] = 1; + while (i > 0); + } + else + { + /* Keep track of which basic block each reg appears in. */ + + 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; + + /* Record the earliest insn that uses this reg, + provided the reg is used only in one basic block. + Do this by recording each insn, and the one that + sticks is the last one scanned (the earliest insn). */ + + reg_first_use[regno] = insn; + + /* Record where each reg is used, so when the reg + is set we know the next insn that uses it. */ + + reg_next_use[regno] = insn; + + /* Count (weighted) number of uses of each reg. */ + + reg_n_refs[regno] += loop_depth; + } + + /* Record and count the insns in which a reg dies. + If it is used in this insn and was dead below the insn + then it dies in this insn. */ + + if (!(needed[offset] & bit) && !is_needed + && ! find_regno_note (insn, REG_DEAD, regno)) + { + REG_NOTES (insn) + = gen_rtx (EXPR_LIST, REG_DEAD, x, REG_NOTES (insn)); + reg_n_deaths[regno]++; + } + } + } + return; + + case SET: + { + register rtx testreg = SET_DEST (x); + int mark_dest = 0; + + /* 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 only value being stored, + and only if the register's value is live after this insn. + If the value being computed here would never be used + then the values it uses don't need to be computed either. */ + + if (GET_CODE (testreg) == REG + && (regno = REGNO (testreg), regno != FRAME_POINTER_REGNUM) + && regno != ARG_POINTER_REGNUM + && ! (regno < FIRST_PSEUDO_REGISTER && global_regs[regno])) +#if 0 /* This was added in 1.25, but screws up death notes for hard regs. + It probably isn't really needed anyway. */ + && (regno >= FIRST_PSEUDO_REGISTER + || INSN_VOLATILE (insn))) +#endif + { + register int offset = regno / REGSET_ELT_BITS; + register int bit = 1 << (regno % REGSET_ELT_BITS); + if ((needed[offset] & bit) + /* If insn refers to volatile, we mustn't delete it, + so its inputs are all needed. */ + || INSN_VOLATILE (insn)) + { + mark_used_regs (needed, live, SET_SRC (x), final, insn); + if (mark_dest) + mark_used_regs (needed, live, SET_DEST (x), final, insn); + } + return; + } + } + 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; + } + mark_used_regs (needed, live, XEXP (x, i), final, insn); + } + else if (fmt[i] == 'E') + { + register int j; + for (j = 0; j < XVECLEN (x, i); j++) + mark_used_regs (needed, live, XVECEXP (x, i, j), final, insn); + } + } + } +} + +#ifdef AUTO_INC_DEC + +static int +try_pre_increment_1 (insn) + rtx 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); + int amount = ((GET_CODE (SET_SRC (x)) == PLUS ? 1 : -1) + * INTVAL (XEXP (SET_SRC (x), 1))); + int regno = REGNO (SET_DEST (x)); + rtx y = reg_next_use[regno]; + if (y != 0 + && BLOCK_NUM (y) == BLOCK_NUM (insn) + && try_pre_increment (y, SET_DEST (PATTERN (insn)), + amount)) + { + /* We have found a suitable auto-increment + and already changed insn Y to do it. + So flush this increment-instruction. */ + PUT_CODE (insn, NOTE); + NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED; + NOTE_SOURCE_FILE (insn) = 0; + /* Count a reference to this reg for the increment + insn we are deleting. 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_sets[regno]++; + return 1; + } + return 0; +} + +/* Try to change INSN so that it does pre-increment or pre-decrement + addressing on register REG in order to add AMOUNT to REG. + AMOUNT is negative for pre-decrement. + Returns 1 if the change could be made. + This checks all about the validity of the result of modifying INSN. */ + +static int +try_pre_increment (insn, reg, amount) + rtx insn, reg; + int amount; +{ + register rtx use; + + /* Nonzero if we can try to make a pre-increment or pre-decrement. + For example, addl $4,r1; movl (r1),... can become movl +(r1),... */ + int pre_ok = 0; + /* Nonzero if we can try to make a post-increment or post-decrement. + For example, addl $4,r1; movl -4(r1),... can become movl (r1)+,... + It is possible for both PRE_OK and POST_OK to be nonzero if the machine + supports both pre-inc and post-inc, or both pre-dec and post-dec. */ + int post_ok = 0; + + /* Nonzero if the opportunity actually requires post-inc or post-dec. */ + int do_post = 0; + + /* From the sign of increment, see which possibilities are conceivable + on this target machine. */ +#ifdef HAVE_PRE_INCREMENT + if (amount > 0) + pre_ok = 1; +#endif +#ifdef HAVE_POST_INCREMENT + if (amount > 0) + post_ok = 1; +#endif + +#ifdef HAVE_PRE_DECREMENT + if (amount < 0) + pre_ok = 1; +#endif +#ifdef HAVE_POST_DECREMENT + if (amount < 0) + post_ok = 1; +#endif + + if (! (pre_ok || post_ok)) + return 0; + + /* It is not safe to add a side effect to a jump insn + because if the incremented register is spilled and must be reloaded + there would be no way to store the incremented value back in memory. */ + + if (GET_CODE (insn) == JUMP_INSN) + return 0; + + use = 0; + if (pre_ok) + use = find_use_as_address (PATTERN (insn), reg, 0); + if (post_ok && (use == 0 || use == (rtx) 1)) + { + use = find_use_as_address (PATTERN (insn), reg, -amount); + do_post = 1; + } + + if (use == 0 || use == (rtx) 1) + return 0; + + if (GET_MODE_SIZE (GET_MODE (use)) != (amount > 0 ? amount : - amount)) + return 0; + + XEXP (use, 0) = gen_rtx (amount > 0 + ? (do_post ? POST_INC : PRE_INC) + : (do_post ? POST_DEC : PRE_DEC), + Pmode, reg); + + /* 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)); + return 1; +} + +#endif /* AUTO_INC_DEC */ + +/* Find the place in the rtx X where REG is used as a memory address. + Return the MEM rtx that so uses it. + If PLUSCONST is nonzero, search instead for a memory address equivalent to + (plus REG (const_int PLUSCONST)). + + If such an address does not appear, return 0. + If REG appears more than once, or is used other than in such an address, + return (rtx)1. */ + +static rtx +find_use_as_address (x, reg, plusconst) + register rtx x; + rtx reg; + int plusconst; +{ + enum rtx_code code = GET_CODE (x); + char *fmt = GET_RTX_FORMAT (code); + register int i; + register rtx value = 0; + register rtx tem; + + if (code == MEM && XEXP (x, 0) == reg && plusconst == 0) + return x; + + if (code == MEM && GET_CODE (XEXP (x, 0)) == PLUS + && XEXP (XEXP (x, 0), 0) == reg + && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT + && INTVAL (XEXP (XEXP (x, 0), 1)) == plusconst) + return x; + + if (code == SIGN_EXTRACT || code == ZERO_EXTRACT) + { + /* If REG occurs inside a MEM used in a bit-field reference, + that is unacceptable. */ + if (find_use_as_address (XEXP (x, 0), reg, 0) != 0) + return (rtx) 1; + } + + if (x == reg) + return (rtx) 1; + + for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) + { + if (fmt[i] == 'e') + { + tem = find_use_as_address (XEXP (x, i), reg, plusconst); + if (value == 0) + value = tem; + else if (tem != 0) + return (rtx) 1; + } + if (fmt[i] == 'E') + { + register int j; + for (j = XVECLEN (x, i) - 1; j >= 0; j--) + { + tem = find_use_as_address (XVECEXP (x, i, j), reg, plusconst); + if (value == 0) + value = tem; + else if (tem != 0) + return (rtx) 1; + } + } + } + + return value; +} + +/* Write information about registers and basic blocks into FILE. + This is part of making a debugging dump. */ + +void +dump_flow_info (file) + FILE *file; +{ + register int i; + static char *reg_class_names[] = REG_CLASS_NAMES; + + fprintf (file, "%d registers.\n", max_regno); + + for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++) + if (reg_n_refs[i]) + { + enum reg_class class; + 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) + fprintf (file, "; crosses 1 call", 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); + if (class != GENERAL_REGS) + { + if (reg_preferred_or_nothing (i)) + fprintf (file, "; %s or none", reg_class_names[(int) class]); + else + fprintf (file, "; pref %s", reg_class_names[(int) class]); + } + if (REGNO_POINTER_FLAG (i)) + fprintf (file, "; pointer"); + fprintf (file, ".\n"); + } + fprintf (file, "\n%d basic blocks.\n", n_basic_blocks); + for (i = 0; i < n_basic_blocks; i++) + { + register rtx head, jump; + register int regno; + fprintf (file, "\nBasic block %d: first insn %d, last %d.\n", + i, + INSN_UID (basic_block_head[i]), + INSN_UID (basic_block_end[i])); + /* The control flow graph's storage is freed + now when flow_analysis returns. + Don't try to print it if it is gone. */ + if (basic_block_drops_in) + { + fprintf (file, "Reached from blocks: "); + head = basic_block_head[i]; + if (GET_CODE (head) == CODE_LABEL) + for (jump = LABEL_REFS (head); + jump != head; + jump = LABEL_NEXTREF (jump)) + { + register int from_block = BLOCK_NUM (CONTAINING_INSN (jump)); + fprintf (file, " %d", from_block); + } + if (basic_block_drops_in[i]) + fprintf (file, " previous"); + } + fprintf (file, "\nRegisters live at start:"); + for (regno = 0; regno < max_regno; regno++) + { + register int offset = regno / REGSET_ELT_BITS; + register int bit = 1 << (regno % REGSET_ELT_BITS); + if (basic_block_live_at_start[i][offset] & bit) + fprintf (file, " %d", regno); + } + fprintf (file, "\n"); + } + fprintf (file, "\n"); +} diff --git a/gcc-1.40/fold-const.c b/gcc-1.40/fold-const.c new file mode 100644 index 0000000..be908f7 --- /dev/null +++ b/gcc-1.40/fold-const.c @@ -0,0 +1,1838 @@ +/* Fold a constant sub-tree into a single node for C-compiler + Copyright (C) 1987, 1988 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 1, 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. */ + +/*@@ Fix lossage on folding division of big integers. */ + +/*@@ This file should be rewritten to use an arbitary precision + @@ representation for "struct tree_int_cst" and "struct tree_real_cst". + @@ Perhaps the routines could also be used for bc/dc, and made a lib. + @@ The routines that translate from the ap rep should + @@ warn if precision et. al. is lost. + @@ This would also make life easier when this technology is used + @@ for cross-compilers. */ + + +/* There are only two entry points in this file: + fold and combine. + + fold takes a tree as argument and returns a simplified tree. + + combine takes a tree code for an arithmetic operation + and two operands that are trees for constant values + and returns the result of the specified operation on those values, + also as a tree. */ + +#include +#include +#include "config.h" +#include "tree.h" + +static void lshift_double (); +static void rshift_double (); +static void lrotate_double (); +static void rrotate_double (); + +/* To do constant folding on INTEGER_CST nodes requires 64-bit arithmetic. + We do that by representing the 64-bit integer as 8 shorts, + with only 8 bits stored in each short, as a positive number. */ + +/* Unpack a 64-bit integer into 8 shorts. + LOW and HI are the integer, as two `int' pieces. + SHORTS points to the array of shorts. */ + +static void +encode (shorts, low, hi) + short *shorts; + int low, hi; +{ + shorts[0] = low & 0xff; + shorts[1] = (low >> 8) & 0xff; + shorts[2] = (low >> 16) & 0xff; + shorts[3] = (low >> 24) & 0xff; + shorts[4] = hi & 0xff; + shorts[5] = (hi >> 8) & 0xff; + shorts[6] = (hi >> 16) & 0xff; + shorts[7] = (hi >> 24) & 0xff; +} + +/* Pack an array of 8 shorts into a 64-bit integer. + SHORTS points to the array of shorts. + The integer is stored into *LOW and *HI as two `int' pieces. */ + +static void +decode (shorts, low, hi) + short *shorts; + int *low, *hi; +{ + *low = (shorts[3] << 24) | (shorts[2] << 16) | (shorts[1] << 8) | shorts[0]; + *hi = (shorts[7] << 24) | (shorts[6] << 16) | (shorts[5] << 8) | shorts[4]; +} + +/* Make the integer constant T valid for its type + by setting to 0 or 1 all the bits in the constant + that don't belong in the type. */ + +static void +force_fit_type (t) + tree t; +{ + register int prec = TYPE_PRECISION (TREE_TYPE (t)); + + if (TREE_CODE (TREE_TYPE (t)) == POINTER_TYPE) + prec = BITS_PER_WORD; + + /* First clear all bits that are beyond the type's precision. */ + + if (prec == 2 * HOST_BITS_PER_INT) + ; + else if (prec > HOST_BITS_PER_INT) + { + TREE_INT_CST_HIGH (t) + &= ~((-1) << (prec - HOST_BITS_PER_INT)); + } + else + { + TREE_INT_CST_HIGH (t) = 0; + if (prec < HOST_BITS_PER_INT) + TREE_INT_CST_LOW (t) + &= ~((-1) << prec); + } + + /* If it's a signed type and value's sign bit is set, extend the sign. */ + + if (! TREE_UNSIGNED (TREE_TYPE (t)) + && prec != 2 * HOST_BITS_PER_INT + && (prec > HOST_BITS_PER_INT + ? TREE_INT_CST_HIGH (t) & (1 << (prec - HOST_BITS_PER_INT - 1)) + : TREE_INT_CST_LOW (t) & (1 << (prec - 1)))) + { + /* Value is negative: + set to 1 all the bits that are outside this type's precision. */ + if (prec > HOST_BITS_PER_INT) + { + TREE_INT_CST_HIGH (t) + |= ((-1) << (prec - HOST_BITS_PER_INT)); + } + else + { + TREE_INT_CST_HIGH (t) = -1; + if (prec < HOST_BITS_PER_INT) + TREE_INT_CST_LOW (t) + |= ((-1) << prec); + } + } +} + +/* Add two 64-bit integers with 64-bit result. + Each argument is given as two `int' pieces. + One argument is L1 and H1; the other, L2 and H2. + The value is stored as two `int' pieces in *LV and *HV. + We use the 8-shorts representation internally. */ + +static void +add_double (l1, h1, l2, h2, lv, hv) + int l1, h1, l2, h2; + int *lv, *hv; +{ + short arg1[8]; + short arg2[8]; + register int carry = 0; + register int i; + + encode (arg1, l1, h1); + encode (arg2, l2, h2); + + for (i = 0; i < 8; i++) + { + carry += arg1[i] + arg2[i]; + arg1[i] = carry & 0xff; + carry >>= 8; + } + + decode (arg1, lv, hv); +} + +/* Negate a 64-bit integers with 64-bit result. + The argument is given as two `int' pieces in L1 and H1. + The value is stored as two `int' pieces in *LV and *HV. + We use the 8-shorts representation internally. */ + +static void +neg_double (l1, h1, lv, hv) + int l1, h1; + int *lv, *hv; +{ + if (l1 == 0) + { + *lv = 0; + *hv = - h1; + } + else + { + *lv = - l1; + *hv = ~ h1; + } +} + +/* Multiply two 64-bit integers with 64-bit result. + Each argument is given as two `int' pieces. + One argument is L1 and H1; the other, L2 and H2. + The value is stored as two `int' pieces in *LV and *HV. + We use the 8-shorts representation internally. */ + +static void +mul_double (l1, h1, l2, h2, lv, hv) + int l1, h1, l2, h2; + int *lv, *hv; +{ + short arg1[8]; + short arg2[8]; + short prod[16]; + register int carry = 0; + register int i, j, k; + + /* These two cases are used extensively, arising from pointer + combinations. */ + if (h2 == 0) + { + if (l2 == 2) + { + unsigned temp = l1 + l1; + *hv = h1 * 2 + (temp < l1); + *lv = temp; + return; + } + if (l2 == 4) + { + unsigned temp = l1 + l1; + h1 = h1 * 4 + (temp < l1) << 1; + l1 = temp; + temp += temp; + h1 += (temp < l1); + *lv = temp; + *hv = h1; + return; + } + if (l2 == 8) + { + unsigned temp = l1 + l1; + h1 = h1 * 8 + (temp < l1) << 2; + l1 = temp; + temp += temp; + h1 += (temp < l1) << 1; + l1 = temp; + temp += temp; + h1 += (temp < l1); + *lv = temp; + *hv = h1; + return; + } + } + + encode (arg1, l1, h1); + encode (arg2, l2, h2); + + bzero (prod, sizeof prod); + + for (i = 0; i < 8; i++) + for (j = 0; j < 8; j++) + { + k = i + j; + carry = arg1[i] * arg2[j]; + while (carry) + { + carry += prod[k]; + prod[k] = carry & 0xff; + carry >>= 8; + k++; + } + } + + decode (prod, lv, hv); /* @@decode ignores prod[8] -> prod[15] */ +} + +/* Shift the 64-bit integer in L1, H1 left by COUNT places + keeping only PREC bits of result. + Shift right if COUNT is negative. + ARITH nonzero specifies arithmetic shifting; otherwise use logical shift. + Store the value as two `int' pieces in *LV and *HV. */ + +static void +lshift_double (l1, h1, count, prec, lv, hv, arith) + int l1, h1, count, prec; + int *lv, *hv; + int arith; +{ + short arg1[8]; + register int i; + register int carry; + + if (count < 0) + { + rshift_double (l1, h1, - count, prec, lv, hv, arith); + return; + } + + encode (arg1, l1, h1); + + if (count > prec) + count = prec; + + while (count > 0) + { + carry = 0; + for (i = 0; i < 8; i++) + { + carry += arg1[i] << 1; + arg1[i] = carry & 0xff; + carry >>= 8; + } + count--; + } + + decode (arg1, lv, hv); +} + +/* Shift the 64-bit integer in L1, H1 right by COUNT places + keeping only PREC bits of result. COUNT must be positive. + ARITH nonzero specifies arithmetic shifting; otherwise use logical shift. + Store the value as two `int' pieces in *LV and *HV. */ + +static void +rshift_double (l1, h1, count, prec, lv, hv, arith) + int l1, h1, count, prec; + int *lv, *hv; + int arith; +{ + short arg1[8]; + register int i; + register int carry; + + encode (arg1, l1, h1); + + if (count > prec) + count = prec; + + while (count > 0) + { + carry = arith && arg1[7] >> 7; + for (i = 7; i >= 0; i--) + { + carry <<= 8; + carry += arg1[i]; + arg1[i] = (carry >> 1) & 0xff; + } + count--; + } + + decode (arg1, lv, hv); +} + +/* Rotate the 64-bit integer in L1, H1 left by COUNT places + keeping only PREC bits of result. + Rotate right if COUNT is negative. + Store the value as two `int' pieces in *LV and *HV. */ + +static void +lrotate_double (l1, h1, count, prec, lv, hv) + int l1, h1, count, prec; + int *lv, *hv; +{ + short arg1[8]; + register int i; + register int carry; + + if (count < 0) + { + rrotate_double (l1, h1, - count, prec, lv, hv); + return; + } + + encode (arg1, l1, h1); + + if (count > prec) + count = prec; + + carry = arg1[7] >> 7; + while (count > 0) + { + for (i = 0; i < 8; i++) + { + carry += arg1[i] << 1; + arg1[i] = carry & 0xff; + carry >>= 8; + } + count--; + } + + decode (arg1, lv, hv); +} + +/* Rotate the 64-bit integer in L1, H1 left by COUNT places + keeping only PREC bits of result. COUNT must be positive. + Store the value as two `int' pieces in *LV and *HV. */ + +static void +rrotate_double (l1, h1, count, prec, lv, hv) + int l1, h1, count, prec; + int *lv, *hv; +{ + short arg1[8]; + register int i; + register int carry; + + encode (arg1, l1, h1); + + if (count > prec) + count = prec; + + carry = arg1[0] & 1; + while (count > 0) + { + for (i = 7; i >= 0; i--) + { + carry <<= 8; + carry += arg1[i]; + arg1[i] = (carry >> 1) & 0xff; + } + count--; + } + + decode (arg1, lv, hv); +} + +/* Divide 64 bit integer LNUM, HNUM by 64 bit integer LDEN, HDEN + for a quotient (stored in *LQUO, *HQUO) and remainder (in *LREM, *HREM). + CODE is a tree code for a kind of division, one of + TRUNC_DIV_EXPR, FLOOR_DIV_EXPR, CEIL_DIV_EXPR, ROUND_DIV_EXPR + or EXACT_DIV_EXPR + It controls how the quotient is rounded to a integer. + UNS nonzero says do unsigned division. */ + +static void +div_and_round_double (code, uns, + lnum_orig, hnum_orig, lden_orig, hden_orig, + lquo, hquo, lrem, hrem) + enum tree_code code; + int uns; + int lnum_orig, hnum_orig; /* num == numerator == dividend */ + int lden_orig, hden_orig; /* den == denominator == divisor */ + int *lquo, *hquo, *lrem, *hrem; +{ + int quo_neg = 0; + short num[9], den[8], quo[8]; /* extra element for scaling. */ + register int i, j, work; + register int carry = 0; + int lnum = lnum_orig, hnum = hnum_orig; + int lden = lden_orig, hden = hden_orig; + + if ((hden == 0) && (lden == 0)) + abort (); + + /* calculate quotient sign and convert operands to unsigned. */ + if (!uns) + { + if (hden < 0) + { + quo_neg = ~ quo_neg; + neg_double (lden, hden, &lden, &hden); + } + if (hnum < 0) + { + quo_neg = ~ quo_neg; + neg_double (lnum, hnum, &lnum, &hnum); + } + } + + if (hnum == 0 && hden == 0) + { /* single precision */ + *hquo = *hrem = 0; + *lquo = (unsigned) lnum / lden; /* rounds toward zero since positive args */ + goto finish_up; + } + + if (hnum == 0) + { /* trivial case: dividend < divisor */ + /* hden != 0 already checked. */ + *hquo = *lquo = 0; + *hrem = hnum; + *lrem = lnum; + goto finish_up; + } + + bzero (quo, sizeof quo); + + bzero (num, sizeof num); /* to zero 9th element */ + bzero (den, sizeof den); + + encode (num, lnum, hnum); + encode (den, lden, hden); + + if (hden == 0) + { /* simpler algorithm */ + /* hnum != 0 already checked. */ + for (i = 7; i >= 0; i--) + { + work = num[i] + (carry << 8); + quo[i] = work / lden; + carry = work % lden; + } + } + else { /* full double precision, + with thanks to Don Knuth's + "Semi-Numericial Algorithms". */ +#define BASE 256 + int quo_est, scale, num_hi_sig, den_hi_sig, quo_hi_sig; + + /* Find the highest non-zero divisor digit. */ + for (i = 7; ; i--) + if (den[i] != 0) { + den_hi_sig = i; + break; + } + for (i = 7; ; i--) + if (num[i] != 0) { + num_hi_sig = i; + break; + } + quo_hi_sig = num_hi_sig - den_hi_sig + 1; + + /* Insure that the first digit of the divisor is at least BASE/2. + This is required by the quotient digit estimation algorithm. */ + + scale = BASE / (den[den_hi_sig] + 1); + if (scale > 1) { /* scale divisor and dividend */ + carry = 0; + for (i = 0; i <= 8; i++) { + work = (num[i] * scale) + carry; + num[i] = work & 0xff; + carry = work >> 8; + if (num[i] != 0) num_hi_sig = i; + } + carry = 0; + for (i = 0; i <= 7; i++) { + work = (den[i] * scale) + carry; + den[i] = work & 0xff; + carry = work >> 8; + if (den[i] != 0) den_hi_sig = i; + } + } + + /* Main loop */ + for (i = quo_hi_sig; i > 0; i--) { + /* quess the next quotient digit, quo_est, by dividing the first + two remaining dividend digits by the high order quotient digit. + quo_est is never low and is at most 2 high. */ + + int num_hi; /* index of highest remaining dividend digit */ + + num_hi = i + den_hi_sig; + + work = (num[num_hi] * BASE) + (num_hi ? 0 : num[num_hi - 1]); + if (num[num_hi] != den[den_hi_sig]) { + quo_est = work / den[den_hi_sig]; + } + else { + quo_est = BASE - 1; + } + + /* refine quo_est so it's usually correct, and at most one high. */ + while ((den[den_hi_sig - 1] * quo_est) + > (((work - (quo_est * den[den_hi_sig])) * BASE) + + ((num_hi - 1) ? 0 : num[num_hi - 2]))) { + quo_est--; + } + + /* try quo_est as the quotient digit, by multiplying the + divisor by quo_est and subtracting from the remaining dividend. */ + + carry = 0; + + for (j = 0; j <= den_hi_sig; j++) { + int digit; + + work = num[i + j] - (quo_est * den[j]) + carry; + digit = work & 0xff; + carry = work >> 8; + if (digit < 0) { + digit += BASE; + carry--; + } + num[i + j] = digit; + } + + /* if quo_est was high by one, then num[i] went negative and + we need to correct things. */ + + if (num[num_hi] < 0) { + quo_est--; + carry = 0; /* add divisor back in */ + for (j = 0; j <= den_hi_sig; j++) { + work = num[i + j] + den[j] + carry; + if (work > BASE) { + work -= BASE; + carry = 1; + } + else { + carry = 0; + } + num[i + j] = work; + } + num [num_hi] += carry; + } + + /* store the quotient digit. */ + quo[i - 1] = quo_est; + } + } + + decode (quo, lquo, hquo); + + finish_up: + /* if result is negative, make it so. */ + if (quo_neg) + neg_double (*lquo, *hquo, lquo, hquo); + + /* compute trial remainder: rem = num - (quo * den) */ + mul_double (*lquo, *hquo, lden_orig, hden_orig, lrem, hrem); + neg_double (*lrem, *hrem, lrem, hrem); + add_double (lnum_orig, hnum_orig, *lrem, *hrem, lrem, hrem); + + switch (code) + { + case TRUNC_DIV_EXPR: + case TRUNC_MOD_EXPR: /* round toward zero */ + case EXACT_DIV_EXPR: /* for this one, it shouldn't matter */ + return; + + case FLOOR_DIV_EXPR: + case FLOOR_MOD_EXPR: /* round toward negative infinity */ + if (quo_neg && (*lrem != 0 || *hrem != 0)) /* ratio < 0 && rem != 0 */ + { + /* quo = quo - 1; */ + add_double (*lquo, *hquo, -1, -1, lquo, hquo); + } + else return; + break; + + case CEIL_DIV_EXPR: + case CEIL_MOD_EXPR: /* round toward positive infinity */ + if (!quo_neg && (*lrem != 0 || *hrem != 0)) /* ratio > 0 && rem != 0 */ + { + add_double (*lquo, *hquo, 1, 0, lquo, hquo); + } + else return; + break; + + case ROUND_DIV_EXPR: + case ROUND_MOD_EXPR: /* round to closest integer */ + { + int labs_rem = *lrem, habs_rem = *hrem; + int labs_den = lden, habs_den = hden, ltwice, htwice; + + /* get absolute values */ + if (*hrem < 0) neg_double (*lrem, *hrem, &labs_rem, &habs_rem); + if (hden < 0) neg_double (lden, hden, &labs_den, &habs_den); + + /* if (2 * abs (lrem) >= abs (lden)) */ + mul_double (2, 0, labs_rem, habs_rem, <wice, &htwice); + if (((unsigned) habs_den < (unsigned) htwice) + || (((unsigned) habs_den == (unsigned) htwice) + && ((unsigned) labs_den < (unsigned) ltwice))) + { + if (*hquo < 0) + /* quo = quo - 1; */ + add_double (*lquo, *hquo, -1, -1, lquo, hquo); + else + /* quo = quo + 1; */ + add_double (*lquo, *hquo, 1, 0, lquo, hquo); + } + else return; + } + break; + + default: + abort (); + } + + /* compute true remainder: rem = num - (quo * den) */ + mul_double (*lquo, *hquo, lden_orig, hden_orig, lrem, hrem); + neg_double (*lrem, *hrem, lrem, hrem); + add_double (lnum_orig, hnum_orig, *lrem, *hrem, lrem, hrem); +} + +/* Split a tree IN into a constant and a variable part + that could be combined with CODE to make IN. + CODE must be a commutative arithmetic operation. + Store the constant part into *CONP and the variable in &VARP. + Return 1 if this was done; zero means the tree IN did not decompose + this way. + + If CODE is PLUS_EXPR we also split trees that use MINUS_EXPR. + Therefore, we must tell the caller whether the variable part + was subtracted. We do this by storing 1 or -1 into *VARSIGNP. + The value stored is the coefficient for the variable term. + The constant term we return should always be added; + we negate it if necessary. */ + +static int +split_tree (in, code, varp, conp, varsignp) + tree in; + enum tree_code code; + tree *varp, *conp; + int *varsignp; +{ + register tree outtype = TREE_TYPE (in); + *varp = 0; + *conp = 0; + + /* Strip any conversions that don't change the machine mode. */ + while ((TREE_CODE (in) == NOP_EXPR + || TREE_CODE (in) == CONVERT_EXPR) + && (TYPE_MODE (TREE_TYPE (in)) + == TYPE_MODE (TREE_TYPE (TREE_OPERAND (in, 0))))) + in = TREE_OPERAND (in, 0); + + if (TREE_CODE (in) == code + || (TREE_CODE (TREE_TYPE (in)) != REAL_TYPE + /* We can associate addition and subtraction together + (even though the C standard doesn't say so) + for integers because the value is not affected. + For reals, the value might be affected, so we can't. */ + && + ((code == PLUS_EXPR && TREE_CODE (in) == MINUS_EXPR) + || (code == MINUS_EXPR && TREE_CODE (in) == PLUS_EXPR)))) + { + enum tree_code code = TREE_CODE (TREE_OPERAND (in, 0)); + if (code == INTEGER_CST) + { + *conp = TREE_OPERAND (in, 0); + *varp = TREE_OPERAND (in, 1); + if (TREE_TYPE (*varp) != outtype) + *varp = convert (outtype, *varp); + *varsignp = (TREE_CODE (in) == MINUS_EXPR) ? -1 : 1; + return 1; + } + if (TREE_LITERAL (TREE_OPERAND (in, 1))) + { + *conp = TREE_OPERAND (in, 1); + *varp = TREE_OPERAND (in, 0); + *varsignp = 1; + if (TREE_TYPE (*varp) != outtype) + *varp = convert (outtype, *varp); + if (TREE_CODE (in) == MINUS_EXPR) + { + /* If operation is subtraction and constant is second, + must negate it to get an additive constant. + And this cannot be done unless it is a manifest constant. + It could also be the address of a static variable. + We cannot negate that, so give up. */ + if (TREE_CODE (*conp) == INTEGER_CST) + *conp = fold (build (NEGATE_EXPR, TREE_TYPE (*conp), *conp)); + else + return 0; + } + return 1; + } + if (TREE_LITERAL (TREE_OPERAND (in, 0))) + { + *conp = TREE_OPERAND (in, 0); + *varp = TREE_OPERAND (in, 1); + if (TREE_TYPE (*varp) != outtype) + *varp = convert (outtype, *varp); + *varsignp = (TREE_CODE (in) == MINUS_EXPR) ? -1 : 1; + return 1; + } + } + return 0; +} + +/* Combine two constants NUM 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. */ + +/* Handle floating overflow for `combine'. */ +static jmp_buf combine_error; + +tree +combine (code, arg1, arg2) + enum tree_code code; + register tree arg1, arg2; +{ + if (TREE_CODE (arg1) == INTEGER_CST) + { + register int int1l = TREE_INT_CST_LOW (arg1); + register int int1h = TREE_INT_CST_HIGH (arg1); + int int2l = TREE_INT_CST_LOW (arg2); + int int2h = TREE_INT_CST_HIGH (arg2); + int low, hi; + int garbagel, garbageh; + register tree t; + int uns = TREE_UNSIGNED (TREE_TYPE (arg1)); + + switch (code) + { + case BIT_IOR_EXPR: + t = build_int_2 (int1l | int2l, int1h | int2h); + break; + + case BIT_XOR_EXPR: + t = build_int_2 (int1l ^ int2l, int1h ^ int2h); + break; + + case BIT_AND_EXPR: + t = build_int_2 (int1l & int2l, int1h & int2h); + break; + + case BIT_ANDTC_EXPR: + t = build_int_2 (int1l & ~int2l, int1h & ~int2h); + break; + + case RSHIFT_EXPR: + int2l = - int2l; + case LSHIFT_EXPR: + lshift_double (int1l, int1h, int2l, + TYPE_PRECISION (TREE_TYPE (arg1)), + &low, &hi, + !uns); + t = build_int_2 (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: + if (int1h == 0) + { + int2l += int1l; + if ((unsigned) int2l < int1l) + int2h += 1; + t = build_int_2 (int2l, int2h); + break; + } + if (int2h == 0) + { + int1l += int2l; + if ((unsigned) int1l < int2l) + int1h += 1; + t = build_int_2 (int1l, int1h); + break; + } + add_double (int1l, int1h, int2l, int2h, &low, &hi); + t = build_int_2 (low, hi); + break; + + case MINUS_EXPR: + if (int1h == 0 && int1l == 0) + { + t = build_int_2 (- int2l, - int2h - (int2l != 0)); + break; + } + if (int2h == 0 && int2l == 0) + { + t = build_int_2 (int1l, int1h); + break; + } + neg_double (int2l, int2h, &int2l, &int2h); + add_double (int1l, int1h, int2l, int2h, &low, &hi); + t = build_int_2 (low, hi); + break; + + case MULT_EXPR: + /* Optimize simple cases. */ + if (int1h == 0) + { + unsigned temp; + + switch (int1l) + { + case 0: + t = build_int_2 (0, 0); + goto got_it; + case 1: + t = build_int_2 (int2l, int2h); + goto got_it; + case 2: + temp = int2l + int2l; + int2h = int2h * 2 + (temp < int2l); + t = build_int_2 (temp, int2h); + goto got_it; + case 3: + temp = int2l + int2l + int2l; + int2h = int2h * 3 + (temp < int2l); + t = build_int_2 (temp, int2h); + goto got_it; + case 4: + temp = int2l + int2l; + int2h = int2h * 4 + (temp < int2l) << 1; + int2l = temp; + temp += temp; + int2h += (temp < int2l); + t = build_int_2 (temp, int2h); + goto got_it; + case 8: + temp = int2l + int2l; + int2h = int2h * 8 + (temp < int2l) << 2; + int2l = temp; + temp += temp; + int2h += (temp < int2l) << 1; + int2l = temp; + temp += temp; + int2h += (temp < int2l); + t = build_int_2 (temp, int2h); + goto got_it; + default: + break; + } + } + + if (int2h == 0) + { + if (int2l == 0) + { + t = build_int_2 (0, 0); + break; + } + if (int2l == 1) + { + t = build_int_2 (int1l, int1h); + break; + } + } + + mul_double (int1l, int1h, int2l, int2h, &low, &hi); + t = build_int_2 (low, hi); + break; + + case TRUNC_DIV_EXPR: case ROUND_DIV_EXPR: + case FLOOR_DIV_EXPR: case CEIL_DIV_EXPR: + case EXACT_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; + } + div_and_round_double (code, uns, int1l, int1h, int2l, int2h, + &low, &hi, &garbagel, &garbageh); + t = build_int_2 (low, hi); + break; + + case TRUNC_MOD_EXPR: case ROUND_MOD_EXPR: + case FLOOR_MOD_EXPR: case CEIL_MOD_EXPR: + div_and_round_double (code, uns, int1l, int1h, int2l, int2h, + &garbagel, &garbageh, &low, &hi); + t = build_int_2 (low, hi); + break; + + case MIN_EXPR: + case MAX_EXPR: + if (uns) + { + low = (((unsigned) int1h < (unsigned) int2h) + || (((unsigned) int1h == (unsigned) int2h) + && ((unsigned) int1l < (unsigned) int2l))); + } + else + { + low = ((int1h < int2h) + || ((int1h == int2h) + && ((unsigned) int1l < (unsigned) int2l))); + } + if (low == (code == MIN_EXPR)) + t = build_int_2 (int1l, int1h); + else + t = build_int_2 (int2l, int2h); + break; + + default: + abort (); + } + got_it: + TREE_TYPE (t) = TREE_TYPE (arg1); + force_fit_type (t); + return t; + } +#if ! defined (REAL_IS_NOT_DOUBLE) || defined (REAL_ARITHMETIC) + if (TREE_CODE (arg1) == REAL_CST) + { + register REAL_VALUE_TYPE d1 = TREE_REAL_CST (arg1); + register REAL_VALUE_TYPE d2 = TREE_REAL_CST (arg2); + register REAL_VALUE_TYPE value; + + if (setjmp (combine_error)) + { + warning ("floating overflow in constant folding"); + return build (code, TREE_TYPE (arg1), arg1, arg2); + } + set_float_handler (combine_error); + +#ifdef REAL_ARITHMETIC + REAL_ARITHMETIC (value, code, d1, d2); +#else + switch (code) + { + case PLUS_EXPR: + value = d1 + d2; + break; + + case MINUS_EXPR: + value = d1 - d2; + break; + + case MULT_EXPR: + value = d1 * d2; + break; + + case RDIV_EXPR: + if (d2 == 0) + abort (); + + value = d1 / d2; + break; + + case MIN_EXPR: + value = d1 < d2 ? d1 : d2; + break; + + case MAX_EXPR: + value = d1 > d2 ? d1 : d2; + break; + + default: + abort (); + } +#endif /* no REAL_ARITHMETIC */ + set_float_handler (0); + return build_real (TREE_TYPE (arg1), value); + } +#endif /* not REAL_IS_NOT_DOUBLE, or REAL_ARITHMETIC */ + if (TREE_CODE (arg1) == COMPLEX_CST) + { + register tree r1 = TREE_REALPART (arg1); + register tree i1 = TREE_IMAGPART (arg1); + register tree r2 = TREE_REALPART (arg2); + register tree i2 = TREE_IMAGPART (arg2); + register tree t; + + switch (code) + { + case PLUS_EXPR: + t = build_complex (combine (PLUS_EXPR, r1, r2), + combine (PLUS_EXPR, i1, i2)); + break; + + case MINUS_EXPR: + t = build_complex (combine (MINUS_EXPR, r1, r2), + combine (MINUS_EXPR, i1, i2)); + break; + + case MULT_EXPR: + t = build_complex (combine (MINUS_EXPR, + combine (MULT_EXPR, r1, r2), + combine (MULT_EXPR, i1, i2)), + combine (PLUS_EXPR, + combine (MULT_EXPR, r1, i2), + combine (MULT_EXPR, i1, r2))); + break; + + case RDIV_EXPR: + { + register tree magsquared + = combine (PLUS_EXPR, + combine (MULT_EXPR, r2, r2), + combine (MULT_EXPR, i2, i2)); + t = build_complex (combine (RDIV_EXPR, + combine (PLUS_EXPR, + combine (MULT_EXPR, r1, r2), + combine (MULT_EXPR, i1, i2)), + magsquared), + combine (RDIV_EXPR, + combine (MINUS_EXPR, + combine (MULT_EXPR, i1, r2), + combine (MULT_EXPR, r1, i2)), + magsquared)); + } + break; + + default: + abort (); + } + TREE_TYPE (t) = TREE_TYPE (arg1); + return t; + } + return 0; +} + +/* Given T, a tree representing type conversion of a constant, + return a constant tree representing the result of conversion. */ + +static tree +fold_convert (t) + register tree t; +{ + register tree arg1 = TREE_OPERAND (t, 0); + register tree type = TREE_TYPE (t); + + if (TREE_CODE (type) == POINTER_TYPE + || TREE_CODE (type) == INTEGER_TYPE + || TREE_CODE (type) == ENUMERAL_TYPE) + { + if (TREE_CODE (arg1) == INTEGER_CST) + { + /* Given an integer constant, make new constant with new type, + appropriately sign-extended or truncated. */ + t = build_int_2 (TREE_INT_CST_LOW (arg1), + TREE_INT_CST_HIGH (arg1)); + TREE_TYPE (t) = type; + force_fit_type (t); + } +#if !defined (REAL_IS_NOT_DOUBLE) || defined (REAL_ARITHMETIC) + else if (TREE_CODE (arg1) == REAL_CST) + { + if (REAL_VALUES_LESS (real_value_from_int_cst (TYPE_MAX_VALUE (type)), + TREE_REAL_CST (arg1)) + || REAL_VALUES_LESS (TREE_REAL_CST (arg1), + real_value_from_int_cst (TYPE_MIN_VALUE (type)))) + { + warning ("real constant out of range for integer conversion"); + return t; + } +#ifndef REAL_ARITHMETIC + { + REAL_VALUE_TYPE d; + int low, high; + int half_word = 1 << (HOST_BITS_PER_INT / 2); + + d = TREE_REAL_CST (arg1); + if (d < 0) + d = -d; + + high = (int) (d / half_word / half_word); + d -= (REAL_VALUE_TYPE) high * half_word * half_word; + low = (unsigned) d; + if (TREE_REAL_CST (arg1) < 0) + neg_double (low, high, &low, &high); + t = build_int_2 (low, high); + } +#else + { + int low, high; + REAL_VALUE_TO_INT (low, high, TREE_REAL_CST (arg1)); + t = build_int_2 (low, high); + } +#endif + TREE_TYPE (t) = type; + force_fit_type (t); + } +#endif /* not REAL_IS_NOT_DOUBLE, or REAL_ARITHMETIC */ + TREE_TYPE (t) = type; + } + else if (TREE_CODE (type) == REAL_TYPE) + { +#if !defined (REAL_IS_NOT_DOUBLE) || defined (REAL_ARITHMETIC) + if (TREE_CODE (arg1) == INTEGER_CST) + return build_real_from_int_cst (type, arg1); +#endif /* not REAL_IS_NOT_DOUBLE, or REAL_ARITHMETIC */ + if (TREE_CODE (arg1) == REAL_CST) + return build_real (type, TREE_REAL_CST (arg1)); + } + TREE_LITERAL (t) = 1; + return t; +} + +/* Return nonzero if two constants (that are not manifest constants) + are necessarily equal. It detects only the easiest, common case of + equality. */ + +static int +operand_equal_p (arg0, arg1) + tree arg0, arg1; +{ + while ((TREE_CODE (arg0) == NOP_EXPR + || TREE_CODE (arg0) == CONVERT_EXPR) + && TYPE_MODE (TREE_TYPE (arg0)) == TYPE_MODE (TREE_TYPE (TREE_OPERAND (arg0, 0)))) + arg0 = TREE_OPERAND (arg0, 0); + while ((TREE_CODE (arg1) == NOP_EXPR + || TREE_CODE (arg1) == CONVERT_EXPR) + && TYPE_MODE (TREE_TYPE (arg1)) == TYPE_MODE (TREE_TYPE (TREE_OPERAND (arg1, 0)))) + arg1 = TREE_OPERAND (arg1, 0); + + if (TREE_CODE (arg0) == TREE_CODE (arg1) + && TREE_CODE (arg0) == ADDR_EXPR + && TREE_OPERAND (arg0, 0) == TREE_OPERAND (arg1, 0)) + return 1; + return 0; +} + +#if !defined (REAL_IS_NOT_DOUBLE) || defined (REAL_ARITHMETIC) + +/* Return 1 if ARG is a real constant with value zero. + This function is not defined in the case where it is impossible + to tell whether a real constant is zero (for cross-compilation). */ + +static int +real_zerop (arg) + tree arg; +{ +#ifdef REAL_IS_NOT_DOUBLE + tree t1 = build_real_from_int_cst (TREE_TYPE (arg), integer_zero_node); + return REAL_VALUES_EQUAL (TREE_REAL_CST (arg), TREE_REAL_CST (t1)); +#else + return TREE_REAL_CST (arg) == 0; +#endif +} +#endif /* not REAL_IS_NOT_DOUBLE, or REAL_ARITHMETIC */ + +/* 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. + NOP_EXPR conversions may be removed freely (as long as we + are careful not to change the C type of the overall expression) + We cannot simplify through a CONVERT_EXPR, FIX_EXPR or FLOAT_EXPR, + but we can constant-fold them if they have constant operands. */ + +tree +fold (expr) + tree expr; +{ + register tree t = expr; + tree type = TREE_TYPE (expr); + register tree arg0, arg1; + register enum tree_code code = TREE_CODE (t); + register int kind; + + /* WINS will be nonzero when the switch is done + if all operands are constant. + + LOSES will be nonzero when the switch is done + if any operand is volatile. + This inhibits optimizations such as (foo () * 0) => 0. + But identity-element optimizations such as + (foo () * 1) => (foo ()) can be done even if LOSES is set. */ + + int wins = 1; + int loses = 0; + + /* Return right away if already constant. */ + if (TREE_LITERAL (t)) + { + if (code == CONST_DECL) + return DECL_INITIAL (t); + return t; + } + + kind = *tree_code_type[(int) code]; + if (kind == 'e' || kind == 'r') + { + register int len = tree_code_length[(int) code]; + register int i; + for (i = 0; i < len; i++) + { + if (TREE_OPERAND (t, i) == 0) + continue; /* Valid for CALL_EXPR, at least. */ + if (TREE_CODE (TREE_OPERAND (t, i)) != INTEGER_CST +#if ! defined (REAL_IS_NOT_DOUBLE) || defined (REAL_ARITHMETIC) + && TREE_CODE (TREE_OPERAND (t, i)) != REAL_CST +#endif /* not REAL_IS_NOT_DOUBLE, or REAL_ARITHMETIC */ + ) + /* Note that TREE_LITERAL isn't enough: + static var addresses are constant but we can't + do arithmetic on them. */ + wins = 0; + if (TREE_VOLATILE (TREE_OPERAND (t, i))) + loses = 1; + } + arg0 = TREE_OPERAND (t, 0); + if (len > 1) + arg1 = TREE_OPERAND (t, 1); + } + + /* Now WINS and LOSES are set as described above, + ARG0 is the first operand of EXPR, + and ARG1 is the second operand (if it has more than one operand). */ + + switch (code) + { + case INTEGER_CST: + case REAL_CST: + case STRING_CST: + case COMPLEX_CST: + case CONSTRUCTOR: + return t; + + case CONST_DECL: + return fold (DECL_INITIAL (t)); + + case NOP_EXPR: + case FLOAT_EXPR: + case CONVERT_EXPR: + case FIX_TRUNC_EXPR: + /* Other kinds of FIX are not handled properly by fold_convert. */ + if (!wins) + { + TREE_LITERAL (t) = TREE_LITERAL (arg0); + return t; + } + return fold_convert (t); + +#if 0 /* This loses on &"foo"[0]. */ + case ARRAY_REF: + { + int i; + + /* Fold an expression like: "foo"[2] */ + if (TREE_CODE (arg0) == STRING_CST + && TREE_CODE (arg1) == INTEGER_CST + && !TREE_INT_CST_HIGH (arg1) + && (i = TREE_INT_CST_LOW (arg1)) < TREE_STRING_LENGTH (arg0)) + { + t = build_int_2 (TREE_STRING_POINTER (arg0)[i], 0); + TREE_TYPE (t) = TREE_TYPE (TREE_TYPE (arg0)); + force_fit_type (t); + } + } + return t; +#endif /* 0 */ + + case RANGE_EXPR: + TREE_LITERAL (t) = wins; + return t; + + case NEGATE_EXPR: + if (wins) + { + if (TREE_CODE (arg0) == INTEGER_CST) + { + if (TREE_INT_CST_LOW (arg0) == 0) + t = build_int_2 (0, - TREE_INT_CST_HIGH (arg0)); + else + t = build_int_2 (- TREE_INT_CST_LOW (arg0), + ~ TREE_INT_CST_HIGH (arg0)); + TREE_TYPE (t) = type; + force_fit_type (t); + } + else if (TREE_CODE (arg0) == REAL_CST) + t = build_real (type, REAL_VALUE_NEGATE (TREE_REAL_CST (arg0))); + TREE_TYPE (t) = type; + } + return t; + + case ABS_EXPR: + if (wins) + { + if (TREE_CODE (arg0) == INTEGER_CST) + { + if (! TREE_UNSIGNED (type) + && TREE_INT_CST_HIGH (arg0) < 0) + { + if (TREE_INT_CST_LOW (arg0) == 0) + t = build_int_2 (0, - TREE_INT_CST_HIGH (arg0)); + else + t = build_int_2 (- TREE_INT_CST_LOW (arg0), + ~ TREE_INT_CST_HIGH (arg0)); + } + } + else if (TREE_CODE (arg0) == REAL_CST) + { + if ( +#if defined (REAL_IS_NOT_DOUBLE) + REAL_VALUES_LESS (TREE_REAL_CST (arg0), + REAL_VALUE_ATOF ("0.0")) +#else + REAL_VALUES_LESS (TREE_REAL_CST (arg0), 0) +#endif + ) + t = build_real (type, + REAL_VALUE_NEGATE (TREE_REAL_CST (arg0))); + } + TREE_TYPE (t) = type; + } + return t; + + 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)); + TREE_TYPE (t) = type; + force_fit_type (t); + } + return t; + + case PLUS_EXPR: + if (integer_zerop (arg0)) + return convert (type, arg1); + if (integer_zerop (arg1)) + return convert (type, arg0); + associate: + /* In most languages, can't associate operations on floats + through parentheses. Rather than remember where the parentheses + were, we don't associate floats at all. It shouldn't matter much. */ + if (TREE_CODE (type) == REAL_TYPE) + goto binary; + /* The varsign == -1 cases happen only for addition and subtraction. + It says that the arg that was split was really CON minus VAR. + The rest of the code applies to all associative operations. */ + if (!wins) + { + tree var, con, tem; + int varsign; + + if (split_tree (arg0, code, &var, &con, &varsign)) + { + if (varsign == -1) + { + /* EXPR is (CON-VAR) +- ARG1. */ + /* If it is + and VAR==ARG1, return just CONST. */ + if (code == PLUS_EXPR && operand_equal_p (var, arg1)) + return convert (TREE_TYPE (t), con); + + /* Otherwise return (CON +- ARG1) - VAR. */ + TREE_SET_CODE (t, MINUS_EXPR); + TREE_OPERAND (t, 1) = var; + TREE_OPERAND (t, 0) + = fold (build (code, TREE_TYPE (t), con, arg1)); + } + else + { + /* EXPR is (VAR+CON) +- ARG1. */ + /* If it is - and VAR==ARG1, return just CONST. */ + if (code == MINUS_EXPR && operand_equal_p (var, arg1)) + return convert (TREE_TYPE (t), con); + + /* Otherwise return VAR +- (ARG1 +- CON). */ + TREE_OPERAND (t, 1) = tem + = fold (build (code, TREE_TYPE (t), arg1, con)); + TREE_OPERAND (t, 0) = var; + if (integer_zerop (tem) + && (code == PLUS_EXPR || code == MINUS_EXPR)) + return var; + /* If we have x +/- (c - d) [c an explicit integer] + change it to x -/+ (d - c) since if d is relocatable + then the latter can be a single immediate insn + and the former cannot. */ + if (TREE_CODE (tem) == MINUS_EXPR + && TREE_CODE (TREE_OPERAND (tem, 0)) == INTEGER_CST) + { + tree tem1 = TREE_OPERAND (tem, 1); + TREE_OPERAND (tem, 1) = TREE_OPERAND (tem, 0); + TREE_OPERAND (tem, 0) = tem1; + TREE_SET_CODE (t, + (code == PLUS_EXPR ? MINUS_EXPR : PLUS_EXPR)); + } + } + return t; + } + + if (split_tree (arg1, code, &var, &con, &varsign)) + { + /* EXPR is ARG0 +- (CON +- VAR). */ + if (varsign == -1) + TREE_SET_CODE (t, + (code == PLUS_EXPR ? MINUS_EXPR : PLUS_EXPR)); + if (TREE_CODE (t) == MINUS_EXPR && operand_equal_p (var, arg0)) + { + /* If VAR and ARG0 cancel, return just CON or -CON. */ + if (code == PLUS_EXPR) + return convert (TREE_TYPE (t), con); + return fold (build (NEGATE_EXPR, TREE_TYPE (t), + convert (TREE_TYPE (t), con))); + } + TREE_OPERAND (t, 0) + = fold (build (code, TREE_TYPE (t), arg0, con)); + TREE_OPERAND (t, 1) = var; + if (integer_zerop (TREE_OPERAND (t, 0)) + && TREE_CODE (t) == PLUS_EXPR) + return convert (TREE_TYPE (t), var); + return t; + } + } + binary: +#if defined (REAL_IS_NOT_DOUBLE) && ! defined (REAL_ARITHMETIC) + if (TREE_CODE (arg1) == REAL_CST) + return t; +#endif /* REAL_IS_NOT_DOUBLE, and no REAL_ARITHMETIC */ + { + register tree t1 = NULL_TREE; + if (wins) + t1 = combine (code, arg0, arg1); + if (t1 != NULL_TREE) return t1; + return t; + } + + case MINUS_EXPR: + if (! wins && integer_zerop (arg0)) + return build (NEGATE_EXPR, type, arg1); + if (integer_zerop (arg1)) + return convert (type, arg0); + /* Fold &x - &x. This can happen from &x.foo - &x. */ + if (operand_equal_p (arg0, arg1)) + return convert (TREE_TYPE (t), integer_zero_node); + goto associate; + + case MULT_EXPR: + if (!loses && integer_zerop (arg0)) + return convert (type, arg0); + if (!loses && integer_zerop (arg1)) + return convert (type, arg1); + if (integer_onep (arg0)) + return convert (type, arg1); + if (integer_onep (arg1)) + return convert (type, arg0); + goto associate; + + case BIT_IOR_EXPR: + if (!loses && integer_all_onesp (arg0)) + return convert (type, arg0); + if (!loses && integer_all_onesp (arg1)) + return convert (type, arg1); + case BIT_XOR_EXPR: + if (integer_zerop (arg0)) + return convert (type, arg1); + if (integer_zerop (arg1)) + return convert (type, arg0); + goto associate; + + case BIT_AND_EXPR: + if (integer_all_onesp (arg0)) + return convert (type, arg1); + if (integer_all_onesp (arg1)) + return convert (type, arg0); + if (!loses && integer_zerop (arg0)) + return convert (type, arg0); + if (!loses && integer_zerop (arg1)) + return convert (type, arg1); + /* Simplify ((int)c & 0x377) into (int)c, if c is unsigned char. */ + if (TREE_CODE (arg0) == INTEGER_CST && TREE_CODE (arg1) == NOP_EXPR + && TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (arg1, 0)))) + { + int prec = TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (arg1, 0))); + if (prec < BITS_PER_WORD && prec < HOST_BITS_PER_INT + && (~TREE_INT_CST_LOW (arg0) & ((1 << prec) - 1)) == 0) + return build (NOP_EXPR, type, TREE_OPERAND (arg1, 0)); + } + if (TREE_CODE (arg1) == INTEGER_CST && TREE_CODE (arg0) == NOP_EXPR + && TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (arg0, 0)))) + { + int prec = TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (arg0, 0))); + if (prec < BITS_PER_WORD && prec < HOST_BITS_PER_INT + && (~TREE_INT_CST_LOW (arg1) & ((1 << prec) - 1)) == 0) + return build (NOP_EXPR, type, TREE_OPERAND (arg0, 0)); + } + goto associate; + + case BIT_ANDTC_EXPR: + if (integer_all_onesp (arg0)) + return convert (type, arg1); + if (integer_zerop (arg1)) + return convert (type, arg0); + if (!loses && integer_zerop (arg0)) + return convert (type, arg0); + if (!loses && integer_all_onesp (arg1)) + return combine (code, arg1, arg1); + goto binary; + + case TRUNC_DIV_EXPR: + case ROUND_DIV_EXPR: + case FLOOR_DIV_EXPR: + case CEIL_DIV_EXPR: + case EXACT_DIV_EXPR: + case RDIV_EXPR: + if (integer_onep (arg1)) + return convert (type, arg0); + if (integer_zerop (arg1)) + return t; +#if !defined (REAL_IS_NOT_DOUBLE) || defined (REAL_ARITHMETIC) + if (TREE_CODE (arg1) == REAL_CST + && real_zerop (arg1)) + return t; +#endif /* not REAL_IS_NOT_DOUBLE, or REAL_ARITHMETIC */ + + goto binary; + + case CEIL_MOD_EXPR: + case FLOOR_MOD_EXPR: + case ROUND_MOD_EXPR: + case TRUNC_MOD_EXPR: + if (!loses && integer_onep (arg1)) + return combine (code, arg1, arg1); + if (integer_zerop (arg1)) + return t; + goto binary; + + case LSHIFT_EXPR: + case RSHIFT_EXPR: + case LROTATE_EXPR: + case RROTATE_EXPR: + if (integer_zerop (arg1)) + return convert (type, arg0); + goto binary; + + case MIN_EXPR: case MAX_EXPR: + goto associate; + + case TRUTH_NOT_EXPR: + /* Note that the operand of this must be an int + and its values must be 0 or 1. + ("true" is a fixed value perhaps depending on the language, + but we don't handle values other than 1 correctly yet.) */ + if (TREE_CODE (arg0) == INTEGER_CST) + { + t = build_int_2 ((TREE_INT_CST_LOW (arg0) == 0 + && TREE_INT_CST_HIGH (arg0) == 0), + 0); + TREE_TYPE (t) = integer_type_node; + } + return t; + + case TRUTH_ANDIF_EXPR: + /* Note that the operands of this must be ints + and their values must be 0 or 1. + ("true" is a fixed value perhaps depending on the language.) */ + /* If first arg is constant zero, return it. */ + if (TREE_CODE (arg0) == INTEGER_CST && integer_zerop (arg0)) + return arg0; + case TRUTH_AND_EXPR: + /* If either arg is constant true, drop it. */ + if (TREE_CODE (arg0) == INTEGER_CST && ! integer_zerop (arg0)) + return arg1; + if (TREE_CODE (arg1) == INTEGER_CST && ! integer_zerop (arg1)) + return arg0; + /* Both known to be zero => return zero. */ + if (TREE_CODE (arg0) == INTEGER_CST && TREE_CODE (arg1) == INTEGER_CST) + return arg0; + return t; + + case TRUTH_ORIF_EXPR: + /* Note that the operands of this must be ints + and their values must be 0 or true. + ("true" is a fixed value perhaps depending on the language.) */ + /* If first arg is constant true, return it. */ + if (TREE_CODE (arg0) == INTEGER_CST && ! integer_zerop (arg0)) + return arg0; + case TRUTH_OR_EXPR: + /* If either arg is constant zero, drop it. */ + if (TREE_CODE (arg0) == INTEGER_CST && integer_zerop (arg0)) + return arg1; + if (TREE_CODE (arg1) == INTEGER_CST && integer_zerop (arg1)) + return arg0; + /* Both known to be true => return true. */ + if (TREE_CODE (arg0) == INTEGER_CST && TREE_CODE (arg1) == INTEGER_CST) + return arg0; + return t; + + case EQ_EXPR: + case NE_EXPR: + case LT_EXPR: + case GT_EXPR: + case LE_EXPR: + case GE_EXPR: + /* If one arg is a constant integer, put it last. */ + if (TREE_CODE (arg0) == INTEGER_CST + && TREE_CODE (arg1) != INTEGER_CST) + { + TREE_OPERAND (t, 0) = arg1; + TREE_OPERAND (t, 1) = arg0; + arg0 = TREE_OPERAND (t, 0); + arg1 = TREE_OPERAND (t, 1); + switch (code) + { + case GT_EXPR: + code = LT_EXPR; + break; + case GE_EXPR: + code = LE_EXPR; + break; + case LT_EXPR: + code = GT_EXPR; + break; + case LE_EXPR: + code = GE_EXPR; + break; + } + TREE_SET_CODE (t, code); + } + + /* Convert foo++ == CONST into ++foo == CONST + INCR. + First, see if one arg is constant; find the constant arg + and the other one. */ + { + tree constop = 0, varop; + tree *constoploc; + + if (TREE_LITERAL (arg1)) + constoploc = &TREE_OPERAND (t, 1), constop = arg1, varop = arg0; + if (TREE_LITERAL (arg0)) + constoploc = &TREE_OPERAND (t, 0), constop = arg0, varop = arg1; + + if (constop && TREE_CODE (varop) == POSTINCREMENT_EXPR) + { + tree newconst + = fold (build (PLUS_EXPR, TREE_TYPE (constop), + constop, TREE_OPERAND (varop, 1))); + /* This optimization is invalid for ordered comparisons + if CONST+INCR overflows or if foo+incr might overflow. + For pointer types we assume overflow doesn't happen. */ + if (TREE_CODE (TREE_TYPE (varop)) == POINTER_TYPE + || code == EQ_EXPR || code == NE_EXPR) + { + TREE_SET_CODE (varop, PREINCREMENT_EXPR); + *constoploc = newconst; + return t; + } + } + else if (constop && TREE_CODE (varop) == POSTDECREMENT_EXPR) + { + tree newconst + = fold (build (MINUS_EXPR, TREE_TYPE (constop), + constop, TREE_OPERAND (varop, 1))); + if (TREE_CODE (TREE_TYPE (varop)) == POINTER_TYPE + || code == EQ_EXPR || code == NE_EXPR) + { + TREE_SET_CODE (varop, PREDECREMENT_EXPR); + *constoploc = newconst; + return t; + } + } + } + + /* Change X >= CST to X > (CST - 1) if CST is positive. */ + if (TREE_CODE (arg1) == INTEGER_CST + && TREE_CODE (arg0) != INTEGER_CST + && ! tree_int_cst_lt (arg1, integer_one_node)) + { + switch (TREE_CODE (t)) + { + case GE_EXPR: + code = GT_EXPR; + TREE_SET_CODE (t, code); + arg1 = combine (MINUS_EXPR, arg1, integer_one_node); + TREE_OPERAND (t, 1) = arg1; + break; + + case LT_EXPR: + code = LE_EXPR; + TREE_SET_CODE (t, code); + arg1 = combine (MINUS_EXPR, arg1, integer_one_node); + TREE_OPERAND (t, 1) = arg1; + } + } + + /* An unsigned comparison against 0 can be simplified. */ + if (integer_zerop (arg1) + && (TREE_CODE (TREE_TYPE (arg1)) == INTEGER_TYPE + || TREE_CODE (TREE_TYPE (arg1)) == POINTER_TYPE) + && TREE_UNSIGNED (TREE_TYPE (arg1))) + { + switch (TREE_CODE (t)) + { + case GT_EXPR: + TREE_SET_CODE (t, NE_EXPR); + break; + case LE_EXPR: + TREE_SET_CODE (t, EQ_EXPR); + break; + case GE_EXPR: + return build (COMPOUND_EXPR, integer_type_node, + arg0, integer_one_node); + case LT_EXPR: + return build (COMPOUND_EXPR, integer_type_node, + arg0, integer_zero_node); + } + } + + /* To compute GT, swap the arguments and do LT. + To compute GE, do LT and invert the result. + To compute LE, swap the arguments, do LT and invert the result. + To compute NE, do EQ and invert the result. */ + if (code == LE_EXPR || code == GT_EXPR) + { + register tree temp = arg0; + arg0 = arg1; + arg1 = temp; + } + + /* Compute a result for LT or EQ if args permit; + otherwise return T. */ + if (TREE_CODE (arg0) == INTEGER_CST + && TREE_CODE (arg1) == INTEGER_CST) + { + if (code == EQ_EXPR || code == NE_EXPR) + t = build_int_2 + (TREE_INT_CST_LOW (arg0) == TREE_INT_CST_LOW (arg1) + && TREE_INT_CST_HIGH (arg0) == TREE_INT_CST_HIGH (arg1), + 0); + else + t = build_int_2 ((TREE_UNSIGNED (TREE_TYPE (arg0)) + ? INT_CST_LT_UNSIGNED (arg0, arg1) + : INT_CST_LT (arg0, arg1)), + 0); + } + else if (TREE_CODE (arg1) == INTEGER_CST + && TREE_LITERAL (arg0) + && TREE_CODE (arg0) == ADDR_EXPR + && (code == EQ_EXPR || code == NE_EXPR)) + { + t = build_int_2 (0, 0); + } + else if (TREE_CODE (arg0) == REAL_CST + && TREE_CODE (arg1) == REAL_CST) + { + if (code == EQ_EXPR || code == NE_EXPR) + t = build_int_2 (REAL_VALUES_EQUAL (TREE_REAL_CST (arg0), + TREE_REAL_CST (arg1)), + 0); + else + t = build_int_2 (REAL_VALUES_LESS (TREE_REAL_CST (arg0), + TREE_REAL_CST (arg1)), + 0); + } + else + return t; + + /* If what we want is other than LT or EQ, invert the result. */ + if (code == GE_EXPR || code == LE_EXPR || code == NE_EXPR) + TREE_INT_CST_LOW (t) ^= 1; + TREE_TYPE (t) = type; + return t; + + case COND_EXPR: + if (TREE_LITERAL (arg0)) + return TREE_OPERAND (expr, (integer_zerop (arg0) ? 2 : 1)); + return t; + + default: + return t; + } /* switch (code) */ +} diff --git a/gcc-1.40/gcc.1 b/gcc-1.40/gcc.1 new file mode 100644 index 0000000..b65b8c2 --- /dev/null +++ b/gcc-1.40/gcc.1 @@ -0,0 +1,1310 @@ +.TH GCC 1 "28 November 1990" "Version 1.40" +.de BP +.sp +.ti -.2i +\(** +.. +.SH NAME +gcc \- GNU project C Compiler +.SH SYNOPSIS +.B gcc +[ options ] files +.SH WARNING +This man page is an extract of the documentation of the +.I GNU C compiler +and is limited to the meaning of the options. +.B It is not kept up to date. +If you want to be certain of the information +below, check it in the manual "Using and Porting GCC". Refer to the Info file +.B gcc.info +or the DVI file +.B gcc.dvi +which are made from the Texinfo source file +.BR gcc.texinfo . +.SH DESCRIPTION +The +.I GNU C compiler +uses a command syntax much like the Unix C compiler. +The +.I gcc +program accepts options and file names as operands. +Multiple single-letter options may +.I not +be grouped: +.B \-dr +is very different from +.BR "\-d \-r" . +.P +When you invoke GNU CC, it normally does preprocessing, compilation, +assembly and linking. +File names which end in +.B .c +are taken as C source to be preprocessed and compiled; +file names ending in +.B .i +are taken as preprocessor output to be compiled; +compiler output files plus any input files with names ending in +.B .s +are assembled; +then the resulting object files, plus any other input files, +are linked together to produce an executable. +.P +Command options allow you to stop this process at an intermediate stage. +For example, the +.B \-c +option says not to run the linker. +Then the output consists of object files output by the assembler. +.P +Other command options are passed on to one stage of processing. +Some options control the preprocessor and others the compiler itself. +Yet other options control the assembler and linker; +these are not documented here, but you rarely need to use any of them. +.SH OPTIONS +Here are the options to control the overall compilation process, +including those that say whether to link, whether to assemble, and so on. +.TP +.BI \-o " file" +Place output in file +.IR file . +This applies regardless to whatever sort of output is being produced, +whether it be an executable file, an object file, +an assembler file or preprocessed C code. +.sp +If +.B \-o +is not specified, the default is to put an executable file in +.BR a.out , +the object file +.IB source .c +in +.IB source .o\fR, +an assembler file in +.IB source .s\fR, +and preprocessed C on standard output. +.TP +.B \-c +Compile or assemble the source files, but do not link. +Produce object files with names made by replacing +.B .c +or +.B .s +with +.B .o +at the end of the input file names. +Do nothing at all for object files specified as input. +.TP +.B \-S +Compile into assembler code but do not assemble. +The assembler output file name is made by replacing +.B .c +with +.B .s +at the end of the input file name. +Do nothing at all for assembler source files or +object files specified as input. +.TP +.B \-E +Run only the C preprocessor. +Preprocess all the C source files specified and output +the results to standard output. +.TP +.B \-v +Compiler driver program prints the commands it executes as it runs +the preprocessor, compiler proper, assembler and linker. +Some of these are directed to print their own version numbers. +.TP +.B \-pipe +Use pipes rather than temporary files for communication between the +various stages of compilation. +This fails to work on some systems where the assembler is unable +to read from a pipe; but the GNU assembler has no trouble. +.TP +.BI \-B prefix +Compiler driver program tries +.I prefix +as a prefix for each program it tries to run. +These programs are +.IR cpp , +.IR cc1 , +.I as +and +.IR ld . +.sp +For each subprogram to be run, the compiler driver first tries the +.B \-B +prefix, if any. +If that name is not found, or if +.B \-B +was not specified, the driver tries two standard prefixes, which are +.B /usr/lib/gcc- +and +.BR /usr/local/lib/gcc- . +If neither of those results in a file name that is found, the +unmodified program name is searched for using the directories +specified in your +.B PATH +environment variable. +.sp +The run-time support file +.B gnulib +is also searched for using the +.B \-B +prefix, if needed. +If it is not found there, the two standard prefixes above +are tried, and that is all. +The file is left out of the link if it is not found by those means. +Most of the time, on most machines, you can do without it. +.sp +You can get a similar result from the environment variable +.BR GCC_EXEC_PREFIX ; +if it is defined, its value is used as a prefix in the same way. +If both the +.B \-B +option and the +.B GCC_EXEC_PREFIX +variable are present, the +.B \-B +option is used first and the environment variable value second. +.TP +.BI -b prefix +The argument +.I prefix +is used as a second prefix for the compiler executables and libraries. +This prefix is optional: the compiler tries each file first with it, +then without it. +This prefix follows the prefix specified with +.B \-B +or the default prefixes. +.sp +Thus, +.B \-bvax- \-Bcc/ +in the presence of environment variable +.B GCC_EXEC_PREFIX +with definition +.B /u/foo/ +causes GNU CC to try the following file names for the preprocessor executable: +.sp + \fBcc/vax-cpp +.br + cc/cpp +.br + /u/foo/vax-cpp +.br + /u/foo/cpp +.br + /usr/local/lib/gcc-vax-cpp +.br + /usr/local/lib/gcc-cpp +.br + /usr/lib/gcc-vax-cpp +.br + /usr/lib/gcc-cpp\fR +.P +These options control the details of C compilation itself. +.TP +.B \-ansi +Support all ANSI standard C programs. +.sp +This turns off certain features of GNU C that are incompatible with +ANSI C, such as the +.BR asm , +.B inline +and +.B typeof +keywords, and predefined macros such as +.B unix +and +.B vax +that identify the type of system you are using. +It also enables the undesirable and rarely used ANSI trigraph feature. +.sp +The alternate keywords +.BR __asm__ , +.B __inline__ +and +.B __typeof__ +continue to work despite +.BR \-ansi . +You would not want to use them in an ANSI C program, of course, +but it useful to put them in header files that might be included +in compilations done with +.BR \-ansi . +Alternate predefined macros such as +.B __unix__ +and +.B __vax__ +are also available, with or without +.BR \-ansi . +.sp +The +.B \-ansi +option does not cause non-ANSI programs to be rejected gratuitously. +For that, +.B \-pedantic +is required in addition to +.BR \-ansi . +.sp +The macro +.B __STRICT_ANSI__ +is predefined when the +.B \-ansi +option is used. +Some header files may notice this macro and refrain from declaring +certain functions or defining certain macros that the ANSI standard +doesn't call for; this is to avoid interfering with any programs +that might use these names for other things. +.TP +.B \-traditional +Attempt to support some aspects of traditional C compilers. +Specifically: +.BP +All +.B extern +declarations take effect globally even if they are +written inside of a function definition. +This includes implicit declarations of functions. +.BP +The keywords +.BR typeof , +.BR inline , +.BR signed , +.B const +and +.B volatile +are not recognized. +.BP +Comparisons between pointers and integers are always allowed. +.BP +Integer types +.B "unsigned short" +and +.B "unsigned char" +promote to +.BR "unsigned int" . +.BP +Out-of-range floating point literals are not an error. +.BP +All automatic variables not declared +.B register +are preserved by +.IR longjmp (3C). +Ordinarily, GNU C follows ANSI C: automatic variables not declared +.B volatile +may be clobbered. +.BP +In the preprocessor, comments convert to nothing at all, +rather than to a space. +This allows traditional token concatenation. +.BP +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. +.BP +The predefined macro +.B __STDC__ +is not defined when you use +.BR \-traditional , +but +.B __GNUC__ +is (since the GNU extensions which +.B __GNUC__ +indicates are not affected by +.BR \-traditional ). +If you need to write header files that work differently depending on whether +.B \-traditional +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. +.TP +.B \-O +Optimize. +Optimizing compilation takes somewhat more time, +and a lot more memory for a large function. +.sp +Without +.BR \-O , +the compiler's goal is to reduce the cost of compilation and +to make debugging produce the expected results. +Statements are independent: if you stop the program with a breakpoint +between statements, you can then assign a new value to any variable or +change the program counter to any other statement in the function and +get exactly the results you would expect from the source code. +.sp +Without +.BR \-O , +only variables declared +.B register +are allocated in registers. +The resulting compiled code is a little worse than produced by PCC without +.BR \-O . +.sp +With +.BR \-O , +the compiler tries to reduce code size and execution time. +.sp +Some of the +.B \-f +options described below turn specific kinds of optimization on or off. +.TP +.B \-g +Produce debugging information in the operating system's +native format (for DBX or SDB). +GDB also can work with this debugging information. +.sp +Unlike most other C compilers, GNU CC allows you to use +.B \-g +with +.BR \-O . +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 +.B \-w +Inhibit all warning messages. +.TP +.B \-W +Print extra warning messages for these events: +.BP +An automatic variable is used without first being initialized. +.sp +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 +.BR \-O , +you simply won't get these warnings. +.sp +These warnings occur only for variables that are candidates for +register allocation. +Therefore, they do not occur for a variable that is declared +.BR volatile , +or whose address is taken, or whose size is other than 1, 2, 4 or 8 bytes. +Also, they do not occur for structures, unions or arrays, even when +they are in registers. +.sp +Note that there may be no warning about a variable that is used only +to compute a value that itself is never used, because such +computations may be deleted by data flow analysis before the warnings +are printed. +.sp +These warnings are made optional because GNU CC 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: +.sp + { +.br + \ \ int x; +.br + \ \ switch (y) +.br + \ \ \ \ { +.br + \ \ \ \ case 1: x = 1; +.br + \ \ \ \ \ \ break; +.br + \ \ \ \ case 2: x = 4; +.br + \ \ \ \ \ \ break; +.br + \ \ \ \ case 3: x = 5; +.br + \ \ \ \ } +.br + \ \ foo (x); +.br + } +.sp +If the value of +.I y +is always 1, 2 or 3, then +.I x +is always initialized, but GNU CC doesn't know this. +Here is another common case: +.sp + { +.br + \ \ int save_y; +.br + \ \ if (change_y) save_y = y, y = new_y; +.br + \ \ ... +.br + \ \ if (change_y) y = save_y; +.br + } +.sp +This has no bug because +.I save_y +is used only if it is set. +.sp +Some spurious warnings can be avoided if you declare as +.B volatile +all the functions you use that never return. +.BP +A nonvolatile automatic variable might be changed by a call to +.IR longjmp (3C). +These warnings as well are possible only in optimizing compilation. +.sp +The compiler sees only the calls to +.IR setjmp (3C). +It cannot know where +.IR longjmp (3C) +will be called; in fact, a signal handler could +call it at any point in the code. +As a result, you may get a warning even when there is +in fact no problem because +.IR longjmp (3C) +cannot in fact be called at the place which would cause a problem. +.BP +A function can return either with or without a value. +(Falling off the end of the function body is considered returning without +a value.) +For example, this function would evoke such a warning: +.sp + foo (a) +.br + { +.br + \ \ if (a > 0) +.br + \ \ \ \ return a; +.br + } +.sp +Spurious warnings can occur because GNU CC does not realize that +certain functions (including +.IR abort (3C) +and +.IR longjmp (3C)) +will never return. +.BP +An expression-statement contains no side effects. +.sp +In the future, other useful warnings may also be enabled by this option. +.TP +.B \-Wimplicit +Warn whenever a function is implicitly declared. +.TP +.B \-Wreturn-type +Warn whenever a function is defined with a return-type that defaults to +.BR int . +Also warn about any +.B return +statement with no return-value in a function whose return-type is not +.BR void . +.TP +.B \-Wunused +Warn whenever a local variable is unused aside from its declaration, +and whenever a function is declared static but never defined. +.TP +.B \-Wswitch +Warn whenever a +.B switch +statement has an index of enumeral type and lacks a +.B case +for one or more of the named codes of that enumeration. +(The presence of a +.B default +label prevents this warning.) +.B case +labels outside the enumeration range also provoke +warnings when this option is used. +.TP +.B \-Wcomment +Warn whenever a comment-start sequence +.B /\(** +appears in a comment. +.TP +.B \-Wtrigraphs +Warn if any trigraphs are encountered (assuming they are enabled). +.TP +.B \-Wall +All of the above +.B \-W +options combined. +These are all the options which pertain to usage that we do not recommend and +that we believe is always easy to avoid, even in conjunction with macros. +.sp +The other +.BR \-W ... +options below are not implied by +.B \-Wall +because certain kinds of useful macros are almost impossible to write +without causing those warnings. +.TP +.B \-Wshadow +Warn whenever a local variable shadows another local variable. +.TP +.BI \-Wid-clash- len +Warn whenever two distinct identifiers match in the first +.I len +characters. +This may help you prepare a program that will compile with certain obsolete, +brain-damaged compilers. +.TP +.B \-Wpointer-arith +Warn about anything that depends on the size of a function type or of +.BR void . +GNU C assigns these types a size of 1, for convenience in calculations with +.B void \(** +pointers and pointers to functions. +.TP +.B \-Wcast-qual +Warn whenever a pointer is cast so as to remove a type qualifier from +the target type. +For example, warn if a +.B const char \(** +is cast to an ordinary +.BR "char \(**" . +.TP +.B \-Wwrite-strings +Give string constants the type +.B const char[\fIlength\fB] +so that copying the address of one into a +.RB non- "const char \(**" +pointer will get a warning. +These warnings will help you find at compile time +code that can try to write into a string constant, +but only if you have been very careful about using +.B const +in declarations and prototypes. +Otherwise, it will just be a nuisance; this is why we did not make +.B \-Wall +request these warnings. +.TP +.B \-p +Generate extra code to write profile information suitable +for the analysis program +.IR prof (1). +.TP +.B \-pg +Generate extra code to write profile information suitable for the +analysis program +.IR gprof (1). +.TP +.B \-a +Generate extra code to write profile information for basic blocks, +suitable for the analysis program +.IR tcov (1). +Eventually GNU +.IR gprof (1) +should be extended to process this data. +.TP +.BI \-l library +Search a standard list of directories for a library named +.IR library , +which is actually a file named +.BR lib\fIlibrary\fB.a . +The linker uses this file as if it had been specified precisely by name. +.sp +The directories searched include several standard system directories +plus any that you specify with +.BR \-L . +.sp +Normally the files found this way are library files--archive files +whose members are object files. +The linker handles an archive file by scanning through it for members +which define symbols that have so far been referenced but not defined. +But if the file that is found is an ordinary object file, it is linked +in the usual fashion. +The only difference between using an +.B \-l +option and specifying a file name is that +.B \-l +searches several directories. +.TP +.BI \-L dir +Add directory +.I dir +to the list of directories to be searched for +.BR \-l . +.TP +.B \-nostdlib +Don't use the standard system libraries and startup files when linking. +Only the files you specify (plus +.BR gnulib ) +will be passed to the linker. +.TP +.BI \-m machinespec +Machine-dependent option specifying something about the type of target machine. +These options are defined by the macro +.B TARGET_SWITCHES +in the machine description. +The default for the options is also defined by that macro, +which enables you to change the defaults. +.sp +These are the +.B \-m +options defined in the 68000 machine description: +.sp +.B \-m68020 +.br +.B \-mc68020 +.in +.5i +Generate output for a 68020 (rather than a 68000). +This is the default if you use the unmodified sources. +.in -.5i +.sp +.B \-m68000 +.br +.B \-mc68000 +.in +.5i +Generate output for a 68000 (rather than a 68020). +.in -.5i +.sp +.B \-m68881 +.in +.5i +Generate output containing 68881 instructions for floating point. +This is the default if you use the unmodified sources. +.in -.5i +.sp +.B \-mfpa +.in +.5i +Generate output containing Sun FPA instructions for floating point. +.in -.5i +.sp +.B \-msoft-float +.in +.5i +Generate output containing library calls for floating point. +.in -.5i +.sp +.B \-mshort +.in +.5i +Consider type +.B int +to be 16 bits wide, like +.BR "short int" . +.in -.5i +.sp +.B \-mnobitfield +.in +.5i +Do not use the bit-field instructions. +.B \-m68000 +implies +.BR \-mnobitfield . +.in -.5i +.sp +.B \-mbitfield +.in +.5i +Do use the bit-field instructions. +.B \-m68020 +implies +.BR \-mbitfield . +This is the default if you use the unmodified sources. +.in -.5i +.sp +.B \-mrtd +.in +.5i +Use a different function-calling convention, in which functions +that take a fixed number of arguments return with the +.B rtd +instruction, which pops their arguments while returning. +This saves one instruction in the caller since there is no need to pop +the arguments there. +.sp +This calling convention is incompatible with the one normally +used on Unix, so you cannot use it if you need to call libraries +compiled with the Unix compiler. +.sp +Also, you must provide function prototypes for all functions that +take variable numbers of arguments (including +.BR printf (3S)); +otherwise incorrect code will be generated for calls to those functions. +.sp +In addition, seriously incorrect code will result if you call a +function with too many arguments. +(Normally, extra arguments are harmlessly ignored.) +.sp +The +.B rtd +instruction is supported by the 68010 and 68020 processors, +but not by the 68000. +.in -.5i +.sp +These +.B \-m +options are defined in the Vax machine description: +.sp +.B \-munix +.in +.5i +Do not output certain jump instructions +.RB ( aobleq +and so on) that the Unix assembler for the Vax +cannot handle across long ranges. +.in -.5i +.sp +.B \-mgnu +.in +.5i +Do output those jump instructions, on the assumption that you +will assemble with the GNU assembler. +.in -.5i +.sp +.B \-mg +.in +.5i +Output code for g-format floating point numbers instead of d-format. +.in -.5i +.sp +These +.B \-m +switches are supported on the Sparc: +.sp +.B \-mfpu +.in +.5i +Generate output containing floating point instructions. +This is the default if you use the unmodified sources. +.in -.5i +.sp +.B \-msoft-float +.in +.5i +Generate output containing library calls for floating point. +.in -.5i +.sp +.B \-mno-epilogue +.in +.5i +Generate separate return instructions for +.B return +statements. +This has both advantages and disadvantages; I don't recall what they are. +.in -.5i +.sp +These +.B \-m +options are defined in the Convex machine description: +.sp +.B \-mc1 +.in +.5i +Generate output for a C1. +This is the default when the compiler is configured for a C1. +.in -.5i +.sp +.B \-mc2 +.in +.5i +Generate output for a C2. +This is the default when the compiler is configured for a C2. +.in -.5i +.sp +.B \-margcount +.in +.5i +Generate code which puts an argument count in the word preceding each +argument list. +Some nonportable Convex and Vax programs need this word. +(Debuggers don't; this info is in the symbol table.) +.in -.5i +.sp +.B \-mnoargcount +.in +.5i +Omit the argument count word. +This is the default if you use the unmodified sources. +.in -.5i +.TP +.BI \-f flag +Specify machine-independent flags. +Most flags have both positive and negative forms; the negative form of +.B \-ffoo +would be +.BR \-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 +.B no- +or adding it. +.TP +.B \-fpcc-struct-return +Use the same convention for returning +.B struct +and +.B union +values that is used by the usual C compiler on your system. +This convention is less efficient for small structures, and on many +machines it fails to be reentrant; but it has the advantage of allowing +intercallability between GCC-compiled code and PCC-compiled code. +.TP +.B \-ffloat-store +Do not store floating-point variables in registers. +This prevents undesirable excess precision on machines such as the +68000 where the floating registers (of the 68881) keep more +precision than a +.B double +is supposed to have. +.sp +For most programs, the excess precision does only good, but a few +programs rely on the precise definition of IEEE floating point. +Use +.B \-ffloat-store +for such programs. +.TP +.B \-fno-asm +Do not recognize +.BR asm , +.B inline +or +.B typeof +as a keyword. +These words may then be used as identifiers. +You can use +.BR __asm__ , +.B __inline__ +and +.B __typeof__ +instead. +.TP +.B \-fno-defer-pop +Always pop the arguments to each function call as soon as that +function returns. +Normally the compiler (when optimizing) lets arguments accumulate +on the stack for several function calls and pops them all at once. +.TP +.B \-fstrength-reduce +Perform the optimizations of loop strength reduction and +elimination of iteration variables. +.TP +.B \-fcombine-regs +Allow the combine pass to combine an instruction that copies one +register into another. +This might or might not produce better code when used in addition to +.BR \-O . +I am interested in hearing about the difference this makes. +.TP +.B \-fforce-mem +Force memory operands to be copied into registers before doing +arithmetic on them. +This may produce better code by making all memory references +potential common subexpressions. +When they are not common subexpressions, instruction combination should +eliminate the separate register-load. +I am interested in hearing about the difference this makes. +.TP +.B \-fforce-addr +Force memory address constants to be copied into registers before +doing arithmetic on them. +This may produce better code just as +.B \-fforce-mem +may. +I am interested in hearing about the difference this makes. +.TP +.B \-fomit-frame-pointer +Don't keep the frame pointer in a register for functions that +don't need one. +This avoids the instructions to save, set up and restore frame pointers; +it also makes an extra register available in many functions. +.B "It also makes debugging impossible." +.sp +On some machines, such as the Vax, this flag has no effect, because +the standard calling sequence automatically handles the frame pointer +and nothing is saved by pretending it doesn't exist. +The machine-description macro +.B FRAME_POINTER_REQUIRED +controls whether a target machine supports this flag. +.TP +.B \-finline-functions +Integrate all simple functions into their callers. +The compiler heuristically decides which functions are simple +enough to be worth integrating in this way. +.sp +If all calls to a given function are integrated, and the function is declared +.BR static , +then the function is normally not output as assembler code in its own right. +.TP +.B \-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 +registers around such calls. +Such allocation is done only when it seems to result in better code than +would otherwise be produced. +.sp +This option is enabled by default on certain machines, usually those +which have no call-preserved registers to use instead. +.TP +.B \-fkeep-inline-functions +Even if all calls to a given function are integrated, and the function is +declared +.BR static , +nevertheless output a separate run-time callable version of the function. +.TP +.B \-fwritable-strings +Store string constants in the writable data segment and don't uniquize them. +This is for compatibility with old programs which assume they can write +into string constants. +Writing into string constants is a very bad idea; +constants should be constant. +.TP +.B \-fcond-mismatch +Allow conditional expressions with mismatched types in the second and +third arguments. +The value of such an expression is void. +.TP +.B \-fno-function-cse +Do not put function addresses in registers; make each instruction that +calls a constant function contain the function's address explicitly. +.sp +This option results in less efficient code, but some strange hacks that +alter the assembler output may be confused by the optimizations performed +when this option is not used. +.TP +.B \-fvolatile +Consider all memory references through pointers to be volatile. +.TP +.B \-fshared-data +Requests that the data and +.RB non- const +variables of this compilation be shared data rather than private data. +The distinction makes sense only on certain operating systems, where +shared data is shared between processes running the same program, while +private data exists in one copy per process. +.TP +.B \-funsigned-char +Let the type +.B char +be the unsigned, like +.BR "unsigned char" . +.sp +Each kind of machine has a default for what +.B char +should be. +It is either like +.B "unsigned char" +by default or like +.B "signed char" +by default. +(Actually, at present, the default is always signed.) +.sp +The type +.B char +is always a distinct type from either +.B "signed char" +or +.BR "unsigned char" , +even though its behavior is always just like one of those two. +.sp +Note that this is equivalent to +.BR \-fno-signed-char , +which is the negative form of +.BR \-fsigned-char . +.TP +.B \-fsigned-char +Let the type +.B char +be signed, like +.BR "signed char" . +.sp +Note that this is equivalent to +.BR \-fno-unsigned-char , +which is the negative form of +.BR \-funsigned-char . +.TP +.B \-fdelayed-branch +If supported for the target machine, attempt to reorder instructions to +exploit instruction slots available after delayed branch instructions. +.TP +.BI \-ffixed- reg +Treat the register named +.I reg +as a fixed register; generated code should never refer to it +(except perhaps as a stack pointer, frame pointer or in some other fixed role). +.sp +.I reg +must be the name of a register. +The register names accepted are machine-specific and are defined in the +.B REGISTER_NAMES +macro in the machine description macro file. +.sp +This flag does not have a negative form, because it specifies a +three-way choice. +.TP +.BI \-fcall-used- reg +Treat the register named +.I reg +as an allocatable 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 REG. +.sp +Use of this flag for a register that has a fixed pervasive role +in the machine's execution model, such as the stack pointer or +frame pointer, will produce disastrous results. +.sp +This flag does not have a negative form, because it specifies a +three-way choice. +.TP +.BI \-fcall-saved- reg +Treat the register named +.I reg +as an allocatable 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 +.I reg +if they use it. +.sp +Use of this flag for a register that has a fixed pervasive role +in the machine's execution model, such as the stack pointer or +frame pointer, will produce disastrous results. +.sp +A different sort of disaster will result from the use of this +flag for a register in which function values may be returned. +.sp +This flag does not have a negative form, because it specifies a +three-way choice. +.TP +.BI \-d letters +Says to make debugging dumps at times specified by +.IR letters . +Here are the possible letters: +.sp +.B r +.in +.5i +Dump after RTL generation. +.in -.5i +.B j +.in +.5i +Dump after first jump optimization. +.in -.5i +.B J +.in +.5i +Dump after last jump optimization. +.in -.5i +.B s +.in +.5i +Dump after CSE (including the jump optimization that sometimes follows CSE). +.in -.5i +.B L +.in +.5i +Dump after loop optimization. +.in -.5i +.B f +.in +.5i +Dump after flow analysis. +.in -.5i +.B c +.in +.5i +Dump after instruction combination. +.in -.5i +.B l +.in +.5i +Dump after local register allocation. +.in -.5i +.B g +.in +.5i +Dump after global register allocation. +.in -.5i +.B d +.in +.5i +Dump after delayed branch scheduling. +.in -.5i +.B m +.in +.5i +Print statistics on memory usage, at the end of the run. +.in -.5i +.TP +.B \-pedantic +Issue all the warnings demanded by strict ANSI standard C; reject +all programs that use forbidden extensions. +.sp +Valid ANSI standard C programs should compile properly with or without +this option (though a rare few will require +.BR \-ansi ). +However, without this option, certain GNU extensions and traditional C +features are supported as well. +With this option, they are rejected. +There is no reason to use this option; it exists only to satisfy pedants. +.sp +.B \-pedantic +does not cause warning messages for use of the alternate keywords whose +names begin and end with +.BR __ . +.TP +.B \-static +On Suns running version 4, this prevents linking with the shared +libraries. +.RB ( \-g +has the same effect.) +.P +These options control the C preprocessor, which is run on each C source +file before actual compilation. If you use the `-E' option, nothing +is done except C preprocessing. Some of these options make sense only +together with `-E' because they request preprocessor output that is +not suitable for actual compilation. +.TP +.B \-C +Tell the preprocessor not to discard comments. +Used with the +.B \-E +option. +.TP +.BI \-I dir +Search directory +.I dir +for include files. +.TP +.B \-I- +Any directories specified with +.B \-I +options before the +.B \-I- +option are searched only for the case of +.B #include +\fB"\fIfile\fB"\fR; they are not searched for +.BR "#include <\fIfile\fB>" . +.sp +If additional directories are specified with +.B \-I +options after the +.BR \-I- , +these directories are searched for all +.B #include +directives. +(Ordinarily +.I all +.B \-I +directories are used this way.) +.sp +In addition, the +.B \-I- +option inhibits the use of the current directory as the first +search directory for +.B #include +\fB"\fIfile\fB"\fR. +Therefore, the current directory is searched only if it is requested +explicitly with +.BR \-I. . +Specifying both +.B \-I- +and +.B -I. +allows you to control precisely which directories are searched before +the current one and which are searched after. +.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. +.sp +Between +.B \-nostdinc +and +.BR \-I- , +you can eliminate all directories from the search path +except those you specify. +.TP +.B \-M +Tell the preprocessor to output a rule suitable for +.BI make (1) +describing the dependencies of each source file. +For each source file, the preprocessor outputs one +.BR make -rule +whose target is the object file name for that source file and whose +dependencies are all the files +.BR #include d +in it. +This rule may be a single line or may be continued with +.B \\\\-newline +if it is long. +.sp +.B \-M +implies +.BR \-E . +.TP +.B \-MM +Like +.B \-M +but the output mentions only the user-header files included with +.B #include +\fB"\fIfile\fB"\fR. +System header files included with +.B "#include <\fIfile\fB>" +are omitted. +.sp +.B \-MM +implies +.BR \-E . +.TP +.BI \-D macro +Define macro +.I macro +with the empty string as its definition. +.TP +.BI \-D macro\fR=\fIdefn +Define macro +.I macro +as +.IR defn . +.TP +.BI \-U macro +Undefine macro +.IR macro . +.TP +.B \-trigraphs +Support ANSI C trigraphs. +You don't want to know about this brain-damage. +The +.B \-ansi +option also has this effect. +.SH FILES +.ta \w'LIBDIR/gcc-include 'u +file.c C source file +.br +file.s assembly language file +.br +file.o object file +.br +a.out link edited output +.br +/tmp/cc\(** temporary files +.br +\fILIBDIR\fR/gcc-cpp preprocessor +.br +\fILIBDIR\fR/gcc-cc1 compiler +.br +\fILIBDIR\fR/gcc-gnulib library needed by GCC on some machines +.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/gcc-include standard gcc directory for +.B #include +files +.sp +.I LIBDIR +is usually +.BR /usr/local/lib . +.SH "SEE ALSO" +as(1), ld(1), adb(1), dbx(1), sdb(1). +.SH BUGS +Bugs should be reported to +.BR bug-gcc@prep.ai.mit.edu . +Bugs tend actually to be fixed if they can be isolated, so it is in your +interest to report them in such a way that they can be easily reproduced. +.SH COPYING +Copyright (c) 1988 Free Software Foundation, Inc. +.P +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. +.P +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. +.P +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. diff --git a/gcc-1.40/gcc.aux b/gcc-1.40/gcc.aux new file mode 100644 index 0000000..aabda2e --- /dev/null +++ b/gcc-1.40/gcc.aux @@ -0,0 +1,192 @@ +'xrdef {Copying-pg}{1} +'xrdef {Copying-snt}{} +'xrdef {Copying-pg}{1} +'xrdef {Copying-snt}{} +'xrdef {Copying-pg}{2} +'xrdef {Copying-snt}{} +'xrdef {Copying-pg}{5} +'xrdef {Copying-snt}{} +'xrdef {Contributors-pg}{7} +'xrdef {Contributors-snt}{} +'xrdef {Boycott-pg}{9} +'xrdef {Boycott-snt}{chapter'tie1} +'xrdef {Options-pg}{13} +'xrdef {Options-snt}{chapter'tie2} +'xrdef {Installation-pg}{27} +'xrdef {Installation-snt}{chapter'tie3} +'xrdef {Other Dir-pg}{34} +'xrdef {Other Dir-snt}{section'tie3.1} +'xrdef {Sun Install-pg}{35} +'xrdef {Sun Install-snt}{section'tie3.2} +'xrdef {3b1 Install-pg}{36} +'xrdef {3b1 Install-snt}{section'tie3.3} +'xrdef {SCO Install-pg}{36} +'xrdef {SCO Install-snt}{section'tie3.4} +'xrdef {VMS Install-pg}{37} +'xrdef {VMS Install-snt}{section'tie3.5} +'xrdef {HPUX Install-pg}{40} +'xrdef {HPUX Install-snt}{section'tie3.6} +'xrdef {Tower Install-pg}{40} +'xrdef {Tower Install-snt}{section'tie3.7} +'xrdef {Trouble-pg}{41} +'xrdef {Trouble-snt}{chapter'tie4} +'xrdef {Service-pg}{43} +'xrdef {Service-snt}{chapter'tie5} +'xrdef {Incompatibilities-pg}{45} +'xrdef {Incompatibilities-snt}{chapter'tie6} +'xrdef {Extensions-pg}{49} +'xrdef {Extensions-snt}{chapter'tie7} +'xrdef {Statement Exprs-pg}{49} +'xrdef {Statement Exprs-snt}{section'tie7.1} +'xrdef {Naming Types-pg}{50} +'xrdef {Naming Types-snt}{section'tie7.2} +'xrdef {Typeof-pg}{50} +'xrdef {Typeof-snt}{section'tie7.3} +'xrdef {Lvalues-pg}{51} +'xrdef {Lvalues-snt}{section'tie7.4} +'xrdef {Conditionals-pg}{52} +'xrdef {Conditionals-snt}{section'tie7.5} +'xrdef {Zero-Length-pg}{53} +'xrdef {Zero-Length-snt}{section'tie7.6} +'xrdef {Variable-Length-pg}{53} +'xrdef {Variable-Length-snt}{section'tie7.7} +'xrdef {Subscripting-pg}{54} +'xrdef {Subscripting-snt}{section'tie7.8} +'xrdef {Pointer Arith-pg}{55} +'xrdef {Pointer Arith-snt}{section'tie7.9} +'xrdef {Initializers-pg}{55} +'xrdef {Initializers-snt}{section'tie7.10} +'xrdef {Constructors-pg}{55} +'xrdef {Constructors-snt}{section'tie7.11} +'xrdef {Function Attributes-pg}{56} +'xrdef {Function Attributes-snt}{section'tie7.12} +'xrdef {Dollar Signs-pg}{57} +'xrdef {Dollar Signs-snt}{section'tie7.13} +'xrdef {Alignment-pg}{57} +'xrdef {Alignment-snt}{section'tie7.14} +'xrdef {Inline-pg}{58} +'xrdef {Inline-snt}{section'tie7.15} +'xrdef {Extended Asm-pg}{59} +'xrdef {Extended Asm-snt}{section'tie7.16} +'xrdef {Asm Labels-pg}{63} +'xrdef {Asm Labels-snt}{section'tie7.17} +'xrdef {Explicit Reg Vars-pg}{64} +'xrdef {Explicit Reg Vars-snt}{section'tie7.18} +'xrdef {Global Reg Vars-pg}{64} +'xrdef {Global Reg Vars-snt}{section'tie7.18.1} +'xrdef {Local Reg Vars-pg}{66} +'xrdef {Local Reg Vars-snt}{section'tie7.18.2} +'xrdef {Alternate Keywords-pg}{66} +'xrdef {Alternate Keywords-snt}{section'tie7.19} +'xrdef {Bugs-pg}{69} +'xrdef {Bugs-snt}{chapter'tie8} +'xrdef {Bug Criteria-pg}{69} +'xrdef {Bug Criteria-snt}{section'tie8.1} +'xrdef {Bug Reporting-pg}{70} +'xrdef {Bug Reporting-snt}{section'tie8.2} +'xrdef {Portability-pg}{75} +'xrdef {Portability-snt}{chapter'tie9} +'xrdef {Interface-pg}{77} +'xrdef {Interface-snt}{chapter'tie10} +'xrdef {Passes-pg}{79} +'xrdef {Passes-snt}{chapter'tie11} +'xrdef {RTL-pg}{85} +'xrdef {RTL-snt}{chapter'tie12} +'xrdef {RTL Objects-pg}{85} +'xrdef {RTL Objects-snt}{section'tie12.1} +'xrdef {Accessors-pg}{86} +'xrdef {Accessors-snt}{section'tie12.2} +'xrdef {Flags-pg}{88} +'xrdef {Flags-snt}{section'tie12.3} +'xrdef {Machine Modes-pg}{90} +'xrdef {Machine Modes-snt}{section'tie12.4} +'xrdef {Constants-pg}{92} +'xrdef {Constants-snt}{section'tie12.5} +'xrdef {Regs and Memory-pg}{94} +'xrdef {Regs and Memory-snt}{section'tie12.6} +'xrdef {Arithmetic-pg}{96} +'xrdef {Arithmetic-snt}{section'tie12.7} +'xrdef {Comparisons-pg}{98} +'xrdef {Comparisons-snt}{section'tie12.8} +'xrdef {Bit Fields-pg}{100} +'xrdef {Bit Fields-snt}{section'tie12.9} +'xrdef {Conversions-pg}{100} +'xrdef {Conversions-snt}{section'tie12.10} +'xrdef {RTL Declarations-pg}{101} +'xrdef {RTL Declarations-snt}{section'tie12.11} +'xrdef {Side Effects-pg}{102} +'xrdef {Side Effects-snt}{section'tie12.12} +'xrdef {Incdec-pg}{105} +'xrdef {Incdec-snt}{section'tie12.13} +'xrdef {Assembler-pg}{106} +'xrdef {Assembler-snt}{section'tie12.14} +'xrdef {Insns-pg}{107} +'xrdef {Insns-snt}{section'tie12.15} +'xrdef {Calls-pg}{111} +'xrdef {Calls-snt}{section'tie12.16} +'xrdef {Sharing-pg}{112} +'xrdef {Sharing-snt}{section'tie12.17} +'xrdef {Machine Desc-pg}{115} +'xrdef {Machine Desc-snt}{chapter'tie13} +'xrdef {Patterns-pg}{115} +'xrdef {Patterns-snt}{section'tie13.1} +'xrdef {Example-pg}{116} +'xrdef {Example-snt}{section'tie13.2} +'xrdef {RTL Template-pg}{117} +'xrdef {RTL Template-snt}{section'tie13.3} +'xrdef {Output Template-pg}{120} +'xrdef {Output Template-snt}{section'tie13.4} +'xrdef {Output Statement-pg}{121} +'xrdef {Output Statement-snt}{section'tie13.5} +'xrdef {Constraints-pg}{122} +'xrdef {Constraints-snt}{section'tie13.6} +'xrdef {Simple Constraints-pg}{122} +'xrdef {Simple Constraints-snt}{section'tie13.6.1} +'xrdef {Multi-Alternative-pg}{126} +'xrdef {Multi-Alternative-snt}{section'tie13.6.2} +'xrdef {Class Preferences-pg}{127} +'xrdef {Class Preferences-snt}{section'tie13.6.3} +'xrdef {Modifiers-pg}{128} +'xrdef {Modifiers-snt}{section'tie13.6.4} +'xrdef {No Constraints-pg}{129} +'xrdef {No Constraints-snt}{section'tie13.6.5} +'xrdef {Standard Names-pg}{129} +'xrdef {Standard Names-snt}{section'tie13.7} +'xrdef {Pattern Ordering-pg}{135} +'xrdef {Pattern Ordering-snt}{section'tie13.8} +'xrdef {Dependent Patterns-pg}{135} +'xrdef {Dependent Patterns-snt}{section'tie13.9} +'xrdef {Jump Patterns-pg}{138} +'xrdef {Jump Patterns-snt}{section'tie13.10} +'xrdef {Peephole Definitions-pg}{138} +'xrdef {Peephole Definitions-snt}{section'tie13.11} +'xrdef {Expander Definitions-pg}{142} +'xrdef {Expander Definitions-snt}{section'tie13.12} +'xrdef {Machine Macros-pg}{147} +'xrdef {Machine Macros-snt}{chapter'tie14} +'xrdef {Run-time Target-pg}{147} +'xrdef {Run-time Target-snt}{section'tie14.1} +'xrdef {Storage Layout-pg}{148} +'xrdef {Storage Layout-snt}{section'tie14.2} +'xrdef {Registers-pg}{150} +'xrdef {Registers-snt}{section'tie14.3} +'xrdef {Register Classes-pg}{155} +'xrdef {Register Classes-snt}{section'tie14.4} +'xrdef {Stack Layout-pg}{159} +'xrdef {Stack Layout-snt}{section'tie14.5} +'xrdef {Library Calls-pg}{167} +'xrdef {Library Calls-snt}{section'tie14.6} +'xrdef {Addressing Modes-pg}{168} +'xrdef {Addressing Modes-snt}{section'tie14.7} +'xrdef {Delayed Branch-pg}{170} +'xrdef {Delayed Branch-snt}{section'tie14.8} +'xrdef {Condition Code-pg}{171} +'xrdef {Condition Code-snt}{section'tie14.9} +'xrdef {Cross-compilation-pg}{172} +'xrdef {Cross-compilation-snt}{section'tie14.10} +'xrdef {Misc-pg}{174} +'xrdef {Misc-snt}{section'tie14.11} +'xrdef {Assembler Format-pg}{177} +'xrdef {Assembler Format-snt}{section'tie14.12} +'xrdef {Config-pg}{189} +'xrdef {Config-snt}{chapter'tie15} diff --git a/gcc-1.40/gcc.c b/gcc-1.40/gcc.c new file mode 100644 index 0000000..e882801 --- /dev/null +++ b/gcc-1.40/gcc.c @@ -0,0 +1,2131 @@ +/* Compiler driver program that can handle many languages. + Copyright (C) 1987,1989 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 1, 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 paragraph is here to try to keep Sun CC from dying. +The number of chars here seems crucial!!!! */ + +void record_temp_file (); + +/* This program is the user interface to the C compiler and possibly to +other compilers. It is used because compilation is a complicated procedure +which involves running several programs and passing temporary files between +them, forwarding the users switches to those programs selectively, +and deleting the temporary files at the end. + +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". + +Specs are strings containing lines, each of which (if not blank) +is made up of a program name, and arguments separated by spaces. +The program name must be exact and start from root, since no path +is searched and it is unreliable to depend on the current working directory. +Redirection of input or output is not supported; the subprograms must +accept filenames saying what files to read and write. + +In addition, the specs can contain %-sequences to substitute variable text +or for conditional text. Here is a table of all defined %-sequences. +Note that spaces are not generated automatically around the results of +expanding these sequences; therefore, you can concatenate them together +or with constant text in a single argument. + + %% substitute one % into the program name or argument. + %i substitute the name of the input file being processed. + %b substitute the basename of the input file being processed. + This is the substring up to (and not including) the last period. + %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. + %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. + %w marks the argument containing or following the %w as the + "output file" of this compilation. This puts the argument + into the sequence of arguments that %o will substitute later. + %W{...} + like %{...} but mark last argument supplied within + as a file to be deleted on failure. + %o substitutes the names of all the output files, with spaces + automatically placed around them. You should write spaces + around the %o as well or the results are undefined. + %o is for use in the specs for running the linker. + 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. + %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. + This is for ANSI C. + %s current argument is the name of a library or startup file of some sort. + Search for that file in a standard list of directories + and substitute the full pathname found. + %eSTR Print STR as an error message. STR is terminated by a newline. + Use this when inconsistent options are detected. + %a process ASM_SPEC as a spec. + This allows config.h to specify part of the spec for running as. + %l process LINK_SPEC as a spec. + %L process LIB_SPEC as a spec. + %G process LIBG_SPEC as a spec. A capital G is actually used here. + %S process STARTFILE_SPEC as a spec. A capital S is actually used here. + %E process ENDFILE_SPEC as a spec. A capital E is actually used here. + %c process SIGNED_CHAR_SPEC as a spec. + %C process CPP_SPEC as a spec. A capital C is actually used here. + %1 process CC1_SPEC as a spec. + %{S} substitutes the -S switch, if that switch was given to CC. + If that switch was not specified, this substitutes nothing. + Here S is a metasyntactic variable. + %{S*} substitutes all the switches specified to CC whose names start + with -S. This is used for -o, -D, -I, etc; switches that take + 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:X} substitutes X, but only if the -S switch was given to CC. + %{!S:X} substitutes X, but only if the -S switch was NOT given to CC. + %{|S:X} like %{S:X}, but if no S switch, substitute `-'. + %{|!S:X} like %{!S:X}, but if there is an S switch, substitute `-'. + +The conditional text X in a %{S:X} or %{!S:X} construct may contain +other nested % constructs or spaces, or even newlines. +They are processed as usual, as described above. + +The character | 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 +allow each compiler's spec to say which switches take arguments. But +this cannot be done in a consistent fashion. CC cannot even decide +which input files have been specified without knowing which switches +take arguments, and it must know which input files to compile in order +to tell which compilers to run. + +CC also knows implicitly that arguments starting in `-l' are to +be treated as compiler output files, and passed to the linker in their proper +position among the other output files. + +*/ + +#include +#include +#include +#include +#include + +#include "config.h" +#include "obstack.h" +#include "gvarargs.h" + +#ifdef USG +#ifndef R_OK +#define R_OK 4 +#define W_OK 2 +#define X_OK 1 +#endif + +#define vfork fork +#endif /* USG */ + +#define obstack_chunk_alloc xmalloc +#define obstack_chunk_free free +extern int xmalloc (); +extern void free (); + +/* If a stage of compilation returns an exit status >= 1, + compilation of that file ceases. */ + +#define MIN_FATAL_STATUS 1 + +/* This is the obstack which we use to allocate many strings. */ + +struct obstack obstack; + +char *handle_braces (); +char *save_string (); +char *concat (); +int do_spec (); +int do_spec_1 (); +char *find_file (); +static char *find_exec_file (); +void validate_switches (); +void validate_all_switches (); +void fancy_abort (); + +/* config.h can define ASM_SPEC to provide extra args to the assembler + or extra switch-translations. */ +#ifndef ASM_SPEC +#define ASM_SPEC "" +#endif + +/* config.h can define CPP_SPEC to provide extra args to the C preprocessor + or extra switch-translations. */ +#ifndef CPP_SPEC +#define CPP_SPEC "" +#endif + +/* config.h can define CC1_SPEC to provide extra args to cc1 + or extra switch-translations. */ +#ifndef CC1_SPEC +#define CC1_SPEC "" +#endif + +/* config.h can define LINK_SPEC to provide extra args to the linker + or extra switch-translations. */ +#ifndef LINK_SPEC +#define LINK_SPEC "" +#endif + +/* config.h can define LIB_SPEC to override the default libraries. */ +#ifndef LIB_SPEC +#define LIB_SPEC "%{!p:%{!pg:-lc}}%{p:-lc_p}%{pg:-lc_p}" +#endif + +/* config.h can define ENDFILE_SPEC to override the default crtn files. */ +#ifndef ENDFILE_SPEC +#define ENDFILE_SPEC "" +#endif + +/* config.h can define LIBG_SPEC to override the default debug libraries. */ +#ifndef LIBG_SPEC +#define LIBG_SPEC "%{g:-lg}" +#endif + +/* config.h can define STARTFILE_SPEC to override the default crt0 files. */ +#ifndef STARTFILE_SPEC +#define STARTFILE_SPEC \ + "%{pg:gcrt0.o%s}%{!pg:%{p:mcrt0.o%s}%{!p:crt0.o%s}}" +#endif + +/* This spec is used for telling cpp whether char is signed or not. */ +#define SIGNED_CHAR_SPEC \ + (DEFAULT_SIGNED_CHAR ? "%{funsigned-char:-D__CHAR_UNSIGNED__}" \ + : "%{!fsigned-char:-D__CHAR_UNSIGNED__}") + +/* This defines which switch letters take arguments. */ + +#ifndef SWITCH_TAKES_ARG +#define SWITCH_TAKES_ARG(CHAR) \ + ((CHAR) == 'D' || (CHAR) == 'U' || (CHAR) == 'o' \ + || (CHAR) == 'e' || (CHAR) == 'T' || (CHAR) == 'u' \ + || (CHAR) == 'I' || (CHAR) == 'Y' || (CHAR) == 'm' \ + || (CHAR) == 'L' || (CHAR) == 'i' || (CHAR) == 'A') +#endif + +/* This defines which multi-letter switches take arguments. */ + +#ifndef WORD_SWITCH_TAKES_ARG +#define WORD_SWITCH_TAKES_ARG(STR) (!strcmp (STR, "Tdata")) +#endif + +/* This structure says how to run one compiler, and when to do so. */ + +struct compiler +{ + char *suffix; /* Use this compiler for input files + whose names end in this suffix. */ + char *spec; /* To use this compiler, pass this spec + to do_spec. */ +}; + +/* Here are the specs for compiling files with various known suffixes. + A file that does not end in any of these suffixes will be passed + unchanged to the loader and nothing else will be done to it. */ + +struct compiler compilers[] = +{ + {".c", + "cpp %{nostdinc} %{C} %{v} %{D*} %{U*} %{I*} %{M*} %{i*} %{trigraphs} -undef \ + -D__GNUC__ %{ansi:-trigraphs -$ -D__STRICT_ANSI__} %{!ansi:%p} %P\ + %c %{O:-D__OPTIMIZE__} %{traditional} %{pedantic} %{P}\ + %{Wcomment*} %{Wtrigraphs} %{Wall} %{w} %C\ + %i %{!M*:%{!E:%{!pipe:%g.cpp}}}%{E:%W{o*}}%{M*:%W{o*}} |\n\ + %{!M*:%{!E:cc1 %{!pipe:%g.cpp} %1 \ + %{!Q:-quiet} -dumpbase %i %{Y*} %{d*} %{m*} %{f*} %{a}\ + %{g} %{O} %{W*} %{w} %{pedantic} %{ansi} %{traditional}\ + %{v:-version} %{gg:-symout %g.sym} %{pg:-p} %{p}\ + %{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 %{R} %{j} %{J} %{h} %{d2} %a %{gg:-G %g.sym}\ + %{c:%W{o*}%{!o*:-o %w%b.o}}%{!c:-o %d%w%b.o}\ + %{!pipe:%g.s}\n }}}"}, + {".cc", + "cpp -+ %{nostdinc} %{C} %{v} %{D*} %{U*} %{I*} %{M*} %{i*} \ + -undef -D__GNUC__ -D__GNUG__ %p %P\ + %c %{O:-D__OPTIMIZE__} %{traditional} %{pedantic} %{P}\ + %{Wcomment*} %{Wtrigraphs} %{Wall} %{w} %C\ + %i %{!M*:%{!E:%{!pipe:%g.cpp}}}%{E:%W{o*}}%{M*:%W{o*}} |\n\ + %{!M*:%{!E:cc1plus %{!pipe:%g.cpp} %1\ + %{!Q:-quiet} -dumpbase %i %{Y*} %{d*} %{m*} %{f*} %{a}\ + %{g} %{O} %{W*} %{w} %{pedantic} %{traditional}\ + %{v:-version} %{gg:-symout %g.sym} %{pg:-p} %{p}\ + %{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 %{R} %{j} %{J} %{h} %{d2} %a %{gg:-G %g.sym}\ + %{c:%W{o*}%{!o*:-o %w%b.o}}%{!c:-o %d%w%b.o}\ + %{!pipe:%g.s}\n }}}"}, + {".i", + "cc1 %i %1 %{!Q:-quiet} %{Y*} %{d*} %{m*} %{f*} %{a}\ + %{g} %{O} %{W*} %{w} %{pedantic} %{ansi} %{traditional}\ + %{v:-version} %{gg:-symout %g.sym} %{pg:-p} %{p}\ + %{S:%W{o*}%{!o*:-o %b.s}}%{!S:-o %{|!pipe:%g.s}} |\n\ + %{!S:as %{R} %{j} %{J} %{h} %{d2} %a %{gg:-G %g.sym}\ + %{c:%W{o*}%{!o*:-o %w%b.o}}%{!c:-o %d%w%b.o} %{!pipe:%g.s}\n }"}, + {".s", + "%{!S:as %{R} %{j} %{J} %{h} %{d2} %a \ + %{c:%W{o*}%{!o*:-o %w%b.o}}%{!c:-o %d%w%b.o} %i\n }"}, + {".S", + "cpp %{nostdinc} %{C} %{v} %{D*} %{U*} %{I*} %{M*} %{trigraphs} \ + -undef -D__GNUC__ -$ %p %P\ + %c %{O:-D__OPTIMIZE__} %{traditional} %{pedantic} %{P}\ + %{Wcomment*} %{Wtrigraphs} %{Wall} %{w} %C\ + %i %{!M*:%{!E:%{!pipe:%g.s}}}%{E:%W{o*}}%{M*:%W{o*}} |\n\ + %{!M*:%{!E:%{!S:as %{R} %{j} %{J} %{h} %{d2} %a \ + %{c:%W{o*}%{!o*:-o %w%b.o}}%{!c:-o %d%w%b.o}\ + %{!pipe:%g.s}\n }}}"}, + /* Mark end of table */ + {0, 0} +}; + +/* Here is the spec for running the linker, after compiling all files. */ +char *link_spec = "%{!c:%{!M*:%{!E:%{!S:ld %{o*} %l\ + %{A} %{d} %{e*} %{N} %{n} %{r} %{s} %{S} %{T*} %{t} %{u*} %{X} %{x} %{z}\ + %{y*} %{!A:%{!nostdlib:%S}} \ + %{L*} %o %{!nostdlib:%G gnulib%s %L gnulib%s %{!A:%E}}\n }}}}"; + +/* Accumulate a command (program name and args), and run it. */ + +/* Vector of pointers to arguments in the current line of specifications. */ + +char **argbuf; + +/* Number of elements allocated in argbuf. */ + +int argbuf_length; + +/* Number of elements in argbuf currently in use (containing args). */ + +int argbuf_index; + +/* Number of commands executed so far. */ + +int execution_count; + +/* Flag indicating whether we should print the command and arguments */ + +unsigned char vflag; + +/* Name with which this program was invoked. */ + +char *programname; + +/* User-specified -B prefix to attach to command names, + or 0 if none specified. */ + +char *user_exec_prefix = 0; + +/* Environment-specified prefix to attach to command names, + or 0 if none specified. */ + +char *env_exec_prefix = 0; + +/* Suffix to attach to directories searched for commands. */ + +char *machine_suffix = 0; + +/* Default prefixes to attach to command names. */ + +#ifndef STANDARD_EXEC_PREFIX +#define STANDARD_EXEC_PREFIX "/usr/local/lib/gcc-" +#endif /* !defined STANDARD_EXEC_PREFIX */ + +char *standard_exec_prefix = STANDARD_EXEC_PREFIX; +char *standard_exec_prefix_1 = "/usr/lib/gcc-"; + +#ifndef STANDARD_STARTFILE_PREFIX +#define STANDARD_STARTFILE_PREFIX "/usr/local/lib/" +#endif /* !defined STANDARD_STARTFILE_PREFIX */ + +char *standard_startfile_prefix = STANDARD_STARTFILE_PREFIX; +char *standard_startfile_prefix_1 = "/lib/"; +char *standard_startfile_prefix_2 = "/usr/lib/"; + +/* Clear out the vector of arguments (after a command is executed). */ + +void +clear_args () +{ + argbuf_index = 0; +} + +/* Add one argument to the vector at the end. + This is done when a space is seen or at the end of the line. + If DELETE_ALWAYS is nonzero, the arg is a filename + and the file should be deleted eventually. + If DELETE_FAILURE is nonzero, the arg is a filename + and the file should be deleted if this compilation fails. */ + +void +store_arg (arg, delete_always, delete_failure) + char *arg; + int delete_always, delete_failure; +{ + if (argbuf_index + 1 == argbuf_length) + argbuf = (char **) xrealloc (argbuf, (argbuf_length *= 2) * sizeof (char *)); + + argbuf[argbuf_index++] = arg; + argbuf[argbuf_index] = 0; + + if (delete_always || delete_failure) + record_temp_file (arg, delete_always, delete_failure); +} + +/* Record the names of temporary files we tell compilers to write, + and delete them at the end of the run. */ + +/* This is the common prefix we use to make temp file names. + It is chosen once for each run of this program. + It is substituted into a spec by %g. + Thus, all temp file names contain this prefix. + In practice, all temp file names start with this prefix. + + 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. */ + +char *temp_filename; + +/* Length of the prefix. */ + +int temp_filename_length; + +/* Define the list of temporary files to delete. */ + +struct temp_file +{ + char *name; + struct temp_file *next; +}; + +/* Queue of files to delete on success or failure of compilation. */ +struct temp_file *always_delete_queue; +/* Queue of files to delete on failure of compilation. */ +struct temp_file *failure_delete_queue; + +/* Record FILENAME as a file to be deleted automatically. + ALWAYS_DELETE nonzero means delete it if all compilation succeeds; + otherwise delete it in any case. + FAIL_DELETE nonzero means delete it if a compilation step fails; + otherwise delete it in any case. */ + +void +record_temp_file (filename, always_delete, fail_delete) + char *filename; + int always_delete; + int fail_delete; +{ + register char *name; + name = (char *) xmalloc (strlen (filename) + 1); + strcpy (name, filename); + + if (always_delete) + { + register struct temp_file *temp; + 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:; + } + + if (fail_delete) + { + register struct temp_file *temp; + 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:; + } +} + +/* Delete all the temporary files whose names we previously recorded. */ + +void +delete_temp_files () +{ + register struct temp_file *temp; + + for (temp = always_delete_queue; temp; temp = temp->next) + { +#ifdef DEBUG + int i; + printf ("Delete %s? (y or n) ", temp->name); + fflush (stdout); + i = getchar (); + if (i != '\n') + while (getchar () != '\n') ; + if (i == 'y' || i == 'Y') +#endif /* DEBUG */ + { + struct stat st; + if (stat (temp->name, &st) >= 0) + { + /* Delete only ordinary files. */ + if ((st.st_mode & S_IFMT) == S_IFREG) + if (unlink (temp->name) < 0) + if (vflag) + perror_with_name (temp->name); + } + } + } + + always_delete_queue = 0; +} + +/* Delete all the files to be deleted on error. */ + +void +delete_failure_queue () +{ + register struct temp_file *temp; + + for (temp = failure_delete_queue; temp; temp = temp->next) + { +#ifdef DEBUG + int i; + printf ("Delete %s? (y or n) ", temp->name); + fflush (stdout); + i = getchar (); + if (i != '\n') + while (getchar () != '\n') ; + if (i == 'y' || i == 'Y') +#endif /* DEBUG */ + { + if (unlink (temp->name) < 0) + if (vflag) + perror_with_name (temp->name); + } + } +} + +void +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. */ + +void +choose_temp_base () +{ + extern char *getenv (); + 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 = (char *) xmalloc (len + sizeof("/ccXXXXXX")); + 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); +} + +/* Search for an execute file through our search path. + Return 0 if not found, otherwise return its name, allocated with malloc. */ + +static char * +find_exec_file (prog) + char *prog; +{ + int win = 0; + char *temp; + int size; + + size = strlen (standard_exec_prefix); + if (user_exec_prefix != 0 && strlen (user_exec_prefix) > size) + size = strlen (user_exec_prefix); + if (env_exec_prefix != 0 && strlen (env_exec_prefix) > size) + size = strlen (env_exec_prefix); + if (strlen (standard_exec_prefix_1) > size) + size = strlen (standard_exec_prefix_1); + size += strlen (prog) + 1; + if (machine_suffix) + size += strlen (machine_suffix) + 1; + temp = (char *) xmalloc (size); + + /* Determine the filename to execute. */ + + if (user_exec_prefix) + { + if (machine_suffix) + { + strcpy (temp, user_exec_prefix); + strcat (temp, machine_suffix); + strcat (temp, prog); + win = (access (temp, X_OK) == 0); + } + if (!win) + { + strcpy (temp, user_exec_prefix); + strcat (temp, prog); + win = (access (temp, X_OK) == 0); + } + } + + if (!win && env_exec_prefix) + { + if (machine_suffix) + { + strcpy (temp, env_exec_prefix); + strcat (temp, machine_suffix); + strcat (temp, prog); + win = (access (temp, X_OK) == 0); + } + if (!win) + { + strcpy (temp, env_exec_prefix); + strcat (temp, prog); + win = (access (temp, X_OK) == 0); + } + } + + if (!win) + { + if (machine_suffix) + { + strcpy (temp, standard_exec_prefix); + strcat (temp, machine_suffix); + strcat (temp, prog); + win = (access (temp, X_OK) == 0); + } + if (!win) + { + strcpy (temp, standard_exec_prefix); + strcat (temp, prog); + win = (access (temp, X_OK) == 0); + } + } + + if (!win) + { + if (machine_suffix) + { + strcpy (temp, standard_exec_prefix_1); + strcat (temp, machine_suffix); + strcat (temp, prog); + win = (access (temp, X_OK) == 0); + } + if (!win) + { + strcpy (temp, standard_exec_prefix_1); + strcat (temp, prog); + win = (access (temp, X_OK) == 0); + } + } + + if (win) + return temp; + else + return 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). */ + +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.) */ + +static int +pexecute (func, program, argv, not_last) + char *program; + int (*func)(); + char *argv[]; + int not_last; +{ + int pid; + int pdes[2]; + int input_desc = last_pipe_input; + int output_desc = STDOUT_FILE_NO; + + /* 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; + + pid = vfork (); + + switch (pid) + { + case -1: + pfatal_with_name ("vfork"); + break; + + 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 */ + + 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; + } +} + +/* Execute the command specified by the arguments on the current line of spec. + When using pipes, this includes several piped-together commands + with `|' between them. + + Return 0 if successful, -1 if failed. */ + +int +execute () +{ + int i, j; + int n_commands; /* # of command. */ + char *string; + struct command + { + char *prog; /* program name. */ + char **argv; /* vector of args. */ + int pid; /* pid of process for this command. */ + }; + + struct command *commands; /* each command buffer with above info. */ + + /* Count # of piped commands. */ + for (n_commands = 1, i = 0; i < argbuf_index; i++) + if (strcmp (argbuf[i], "|") == 0) + n_commands++; + + /* Get storage for each command. */ + commands + = (struct command *) alloca (n_commands * sizeof (struct command)); + + /* Split argbuf into its separate piped processes, + and record info about each one. + Also search for the programs that are to be run. */ + + commands[0].prog = argbuf[0]; /* first command. */ + commands[0].argv = &argbuf[0]; + string = find_exec_file (commands[0].prog); + if (string) + commands[0].argv[0] = string; + + for (n_commands = 1, i = 0; i < argbuf_index; i++) + if (strcmp (argbuf[i], "|") == 0) + { /* each command. */ + argbuf[i] = 0; /* termination of command args. */ + commands[n_commands].prog = argbuf[i + 1]; + commands[n_commands].argv = &argbuf[i + 1]; + string = find_exec_file (commands[n_commands].prog); + if (string) + commands[n_commands].argv[0] = string; + n_commands++; + } + + argbuf[argbuf_index] = 0; + + /* If -v, print what we are about to do, and maybe query. */ + + if (vflag) + { + /* Print each piped command as a separate line. */ + for (i = 0; i < n_commands ; i++) + { + char **j; + + for (j = commands[i].argv; *j; j++) + fprintf (stderr, " %s", *j); + + /* Print a pipe symbol after all but the last command. */ + if (i + 1 != n_commands) + fprintf (stderr, " |"); + fprintf (stderr, "\n"); + } + fflush (stderr); +#ifdef DEBUG + fprintf (stderr, "\nGo ahead? (y or n) "); + fflush (stderr); + j = getchar (); + if (j != '\n') + while (getchar () != '\n') ; + if (j != 'y' && j != 'Y') + return 0; +#endif /* DEBUG */ + } + + /* Run each piped subprocess. */ + + last_pipe_input = STDIN_FILE_NO; + for (i = 0; i < n_commands; i++) + { + extern int execv(), execvp(); + char *string = commands[i].argv[0]; + + commands[i].pid = pexecute ((string != commands[i].prog ? execv : execvp), + string, commands[i].argv, + i + 1 < n_commands); + + if (string != commands[i].prog) + free (string); + } + + execution_count++; + + /* Wait for all the subprocesses to finish. + We don't care what order they finish in; + we know that N_COMMANDS waits will get them all. */ + + { + int ret_code = 0; + + for (i = 0; i < n_commands; i++) + { + int status; + int pid; + char *prog; + + pid = wait (&status); + if (pid < 0) + abort (); + + if (status != 0) + { + int j; + for (j = 0; j < n_commands; j++) + if (commands[j].pid == pid) + prog = commands[j].prog; + + if ((status & 0x7F) != 0) + fatal ("Program %s got fatal signal %d.", prog, (status & 0x7F)); + if (((status & 0xFF00) >> 8) >= MIN_FATAL_STATUS) + ret_code = -1; + } + } + return ret_code; + } +} + +/* Find all the switches given to us + and make a vector describing them. + The elements of the vector a strings, one per switch given. + If a switch uses the following argument, then the `part1' field + is the switch itself and the `part2' field is the following argument. + The `valid' field is nonzero if any spec has looked at this switch; + if it remains zero at the end of the run, it must be meaningless. */ + +struct switchstr +{ + char *part1; + char *part2; + int valid; +}; + +struct switchstr *switches; + +int n_switches; + +/* Also a vector of input files specified. */ + +char **infiles; + +int n_infiles; + +/* And a vector of corresponding output files is made up later. */ + +char **outfiles; + +/* Create the vector `switches' and its contents. + Store its length in `n_switches'. */ + +void +process_command (argc, argv) + int argc; + char **argv; +{ + extern char *getenv (); + register int i; + n_switches = 0; + n_infiles = 0; + + env_exec_prefix = getenv ("GCC_EXEC_PREFIX"); + + /* 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). */ + + for (i = 1; i < argc; i++) + { + if (argv[i][0] == '-' && argv[i][1] != 'l') + { + register char *p = &argv[i][1]; + register int c = *p; + + switch (c) + { + case 'b': + machine_suffix = p + 1; + break; + + case 'B': + user_exec_prefix = p + 1; + break; + + case 'v': /* Print our subcommands and print versions. */ + vflag++; + n_switches++; + break; + + default: + n_switches++; + + if (SWITCH_TAKES_ARG (c) && p[1] == 0) + i++; + else if (WORD_SWITCH_TAKES_ARG (p)) + i++; + } + } + else + n_infiles++; + } + + /* Then create the space for the vectors and scan again. */ + + switches = ((struct switchstr *) + xmalloc ((n_switches + 1) * sizeof (struct switchstr))); + infiles = (char **) xmalloc ((n_infiles + 1) * sizeof (char *)); + n_switches = 0; + n_infiles = 0; + + /* This, time, copy the text of each switch and store a pointer + to the copy in the vector of switches. + Store all the infiles in their vector. */ + + for (i = 1; i < argc; i++) + { + if (argv[i][0] == '-' && argv[i][1] != 'l') + { + register char *p = &argv[i][1]; + register int c = *p; + + if (c == 'B' || c == 'b') + continue; + switches[n_switches].part1 = p; + if ((SWITCH_TAKES_ARG (c) && p[1] == 0) + || WORD_SWITCH_TAKES_ARG (p)) + switches[n_switches].part2 = argv[++i]; + else if (c == 'o') { + /* On some systems, ld cannot handle -o without space. + So split the -o and its argument. */ + switches[n_switches].part2 = (char *) xmalloc (strlen (p)); + strcpy (switches[n_switches].part2, &p[1]); + p[1] = 0; + } else + switches[n_switches].part2 = 0; + switches[n_switches].valid = 0; + n_switches++; + } + else + infiles[n_infiles++] = argv[i]; + } + + switches[n_switches].part1 = 0; + infiles[n_infiles] = 0; +} + +/* Process a spec string, accumulating and running commands. */ + +/* These variables describe the input file name. + input_file_number is the index on outfiles of this file, + so that the output file name can be stored for later use by %o. + input_basename is the start of the part of the input file + sans all directory names, and basename_length is the number + of characters starting there excluding the suffix .c or whatever. */ + +char *input_filename; +int input_file_number; +int input_filename_length; +int basename_length; +char *input_basename; + +/* These are variables used within do_spec and do_spec_1. */ + +/* Nonzero if an arg has been started and not yet terminated + (with space, tab or newline). */ +int arg_going; + +/* Nonzero means %d or %g has been seen; the next arg to be terminated + is a temporary file name. */ +int delete_this_arg; + +/* Nonzero means %w has been seen; the next arg to be terminated + is the output file name of this compilation. */ +int this_is_output_file; + +/* Nonzero means %s has been seen; the next arg to be terminated + is the name of a library file and we should try the standard + search dirs for it. */ +int this_is_library_file; + +/* Process the spec SPEC and run the commands specified therein. + Returns 0 if the spec is successfully processed; -1 if failed. */ + +int +do_spec (spec) + char *spec; +{ + int value; + + clear_args (); + arg_going = 0; + delete_this_arg = 0; + this_is_output_file = 0; + this_is_library_file = 0; + + value = do_spec_1 (spec, 0); + + /* Force out any unfinished command. + If -pipe, this forces out the last command if it ended in `|'. */ + if (value == 0) + { + if (argbuf_index > 0 && !strcmp (argbuf[argbuf_index - 1], "|")) + argbuf_index--; + + if (argbuf_index > 0) + value = execute (); + } + + return value; +} + +/* Process the sub-spec SPEC as a portion of a larger spec. + This is like processing a whole spec except that we do + not initialize at the beginning and we do not supply a + newline by default at the end. + INSWITCH nonzero means don't process %-sequences in SPEC; + in this case, % is treated as an ordinary character. + This is used while substituting switches. + INSWITCH nonzero also causes SPC not to terminate an argument. + + Value is zero unless a line was finished + and the command on that line reported an error. */ + +int +do_spec_1 (spec, inswitch) + char *spec; + int inswitch; +{ + register char *p = spec; + register int c; + char *string; + + while (c = *p++) + /* If substituting a switch, treat all chars like letters. + Otherwise, NL, SPC, TAB and % are special. */ + switch (inswitch ? 'a' : c) + { + case '\n': + /* End of line: finish any pending argument, + then run the pending command if one has been started. */ + if (arg_going) + { + obstack_1grow (&obstack, 0); + string = obstack_finish (&obstack); + if (this_is_library_file) + string = find_file (string); + store_arg (string, delete_this_arg, this_is_output_file); + if (this_is_output_file) + outfiles[input_file_number] = string; + } + arg_going = 0; + + if (argbuf_index > 0 && !strcmp (argbuf[argbuf_index - 1], "|")) + { + int i; + for (i = 0; i < n_switches; i++) + if (!strcmp (switches[i].part1, "pipe")) + break; + + /* A `|' before the newline means use a pipe here, + but only if -pipe was specified. + Otherwise, execute now and don't pass the `|' as an arg. */ + if (i < n_switches) + { + switches[i].valid = 1; + break; + } + else + argbuf_index--; + } + + if (argbuf_index > 0) + { + int value = execute (); + if (value) + return value; + } + /* Reinitialize for a new command, and for a new argument. */ + clear_args (); + arg_going = 0; + delete_this_arg = 0; + this_is_output_file = 0; + this_is_library_file = 0; + break; + + case '|': + /* End any pending argument. */ + if (arg_going) + { + obstack_1grow (&obstack, 0); + string = obstack_finish (&obstack); + if (this_is_library_file) + string = find_file (string); + store_arg (string, delete_this_arg, this_is_output_file); + if (this_is_output_file) + outfiles[input_file_number] = string; + } + + /* Use pipe */ + obstack_1grow (&obstack, c); + arg_going = 1; + break; + + case '\t': + case ' ': + /* Space or tab ends an argument if one is pending. */ + if (arg_going) + { + obstack_1grow (&obstack, 0); + string = obstack_finish (&obstack); + if (this_is_library_file) + string = find_file (string); + store_arg (string, delete_this_arg, this_is_output_file); + if (this_is_output_file) + outfiles[input_file_number] = string; + } + /* Reinitialize for a new argument. */ + arg_going = 0; + delete_this_arg = 0; + this_is_output_file = 0; + this_is_library_file = 0; + break; + + case '%': + switch (c = *p++) + { + case 0: + fatal ("Invalid specification! Bug in cc."); + + case 'b': + obstack_grow (&obstack, input_basename, basename_length); + arg_going = 1; + break; + + case 'd': + delete_this_arg = 2; + break; + + case 'e': + /* {...:%efoo} means report an error with `foo' as error message + and don't execute any more commands for this file. */ + { + char *q = p; + char *buf; + while (*p != 0 && *p != '\n') p++; + buf = (char *) alloca (p - q + 1); + strncpy (buf, q, p - q); + buf[p - q] = 0; + error ("%s", buf); + return -1; + } + break; + + case 'g': + obstack_grow (&obstack, temp_filename, temp_filename_length); + delete_this_arg = 1; + arg_going = 1; + break; + + case 'i': + obstack_grow (&obstack, input_filename, input_filename_length); + arg_going = 1; + break; + + case 'o': + { + register int f; + for (f = 0; f < n_infiles; f++) + store_arg (outfiles[f], 0, 0); + } + break; + + case 's': + this_is_library_file = 1; + break; + + case 'W': + { + int index = argbuf_index; + /* Handle the {...} following the %W. */ + if (*p != '{') + abort (); + p = handle_braces (p + 1); + if (p == 0) + return -1; + /* If any args were output, mark the last one for deletion + on failure. */ + if (argbuf_index != index) + record_temp_file (argbuf[argbuf_index - 1], 0, 1); + break; + } + + case 'w': + this_is_output_file = 1; + break; + + case '{': + p = handle_braces (p); + if (p == 0) + return -1; + break; + + case '%': + obstack_1grow (&obstack, '%'); + break; + +/*** The rest just process a certain constant string as a spec. */ + + case '1': + do_spec_1 (CC1_SPEC, 0); + break; + + case 'a': + do_spec_1 (ASM_SPEC, 0); + break; + + case 'c': + do_spec_1 (SIGNED_CHAR_SPEC, 0); + break; + + case 'C': + do_spec_1 (CPP_SPEC, 0); + break; + + case 'l': + do_spec_1 (LINK_SPEC, 0); + break; + + case 'L': + do_spec_1 (LIB_SPEC, 0); + break; + + case 'G': + do_spec_1 (LIBG_SPEC, 0); + break; + + case 'p': + do_spec_1 (CPP_PREDEFINES, 0); + break; + + case 'P': + { + char *x = (char *) alloca (strlen (CPP_PREDEFINES) * 2 + 1); + char *buf = x; + char *y = CPP_PREDEFINES; + + /* Copy all of CPP_PREDEFINES into BUF, + but put __ after every -D and at the end of each arg, */ + while (1) + { + if (! strncmp (y, "-D", 2)) + { + *x++ = '-'; + *x++ = 'D'; + *x++ = '_'; + *x++ = '_'; + y += 2; + } + else if (*y == ' ' || *y == 0) + { + *x++ = '_'; + *x++ = '_'; + if (*y == 0) + break; + else + *x++ = *y++; + } + else + *x++ = *y++; + } + *x = 0; + + do_spec_1 (buf, 0); + } + break; + + case 'S': + do_spec_1 (STARTFILE_SPEC, 0); + break; + + case 'E': + do_spec_1 (ENDFILE_SPEC, 0); + break; + + default: + abort (); + } + break; + + default: + /* Ordinary character: put it into the current argument. */ + obstack_1grow (&obstack, c); + arg_going = 1; + } + + return 0; /* End of string */ +} + +/* Return 0 if we call do_spec_1 and that returns -1. */ + +char * +handle_braces (p) + register char *p; +{ + register char *q; + char *filter; + int pipe = 0; + int negate = 0; + + 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; + + if (*p == '!') + /* A `!' after the open-brace negates the condition: + succeed if the specified switch is not present. */ + negate = 1, ++p; + + filter = p; + while (*p != ':' && *p != '}') p++; + if (*p != '}') + { + register int count = 1; + q = p + 1; + while (count > 0) + { + if (*q == '{') + count++; + else if (*q == '}') + count--; + else if (*q == 0) + abort (); + q++; + } + } + else + q = p + 1; + + if (p[-1] == '*' && p[0] == '}') + { + /* Substitute all matching switches as separate args. */ + register int i; + --p; + for (i = 0; i < n_switches; i++) + if (!strncmp (switches[i].part1, filter, p - filter)) + give_switch (i); + } + else + { + /* Test for presence of the specified switch. */ + register int i; + int present = 0; + + /* If name specified ends in *, as in {x*:...}, + check for presence of any switch name starting with x. */ + if (p[-1] == '*') + { + for (i = 0; i < n_switches; i++) + { + if (!strncmp (switches[i].part1, filter, p - filter - 1)) + { + switches[i].valid = 1; + present = 1; + } + } + } + /* Otherwise, check for presence of exact name specified. */ + else + { + for (i = 0; i < n_switches; i++) + { + if (!strncmp (switches[i].part1, filter, p - filter) + && switches[i].part1[p - filter] == 0) + { + switches[i].valid = 1; + present = 1; + break; + } + } + } + + /* 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); + } + else + { + if (do_spec_1 (save_string (p + 1, q - p - 2), 0) < 0) + return 0; + } + } + else if (pipe) + { + /* Here if a %{|...} conditional fails: output a minus sign, + which means "standard output" or "standard input". */ + do_spec_1 ("-", 0); + } + } + + return q; +} + +/* Pass a switch to the current accumulating command + in the same form that we received it. + SWITCHNUM identifies the switch; it is an index into + the vector of switches gcc received, which is `switches'. + This cannot fail since it never finishes a command line. */ + +give_switch (switchnum) + int switchnum; +{ + do_spec_1 ("-", 0); + do_spec_1 (switches[switchnum].part1, 1); + do_spec_1 (" ", 0); + if (switches[switchnum].part2 != 0) + { + do_spec_1 (switches[switchnum].part2, 1); + do_spec_1 (" ", 0); + } + switches[switchnum].valid = 1; +} + +/* Search for a file named NAME trying various prefixes including the + user's -B prefix and some standard ones. + Return the absolute pathname found. If nothing is found, return NAME. */ + +char * +find_file (name) + char *name; +{ + int size; + char *temp; + int win = 0; + + /* Compute maximum size of NAME plus any prefix we will try. */ + + size = strlen (standard_exec_prefix); + if (user_exec_prefix != 0 && strlen (user_exec_prefix) > size) + size = strlen (user_exec_prefix); + if (env_exec_prefix != 0 && strlen (env_exec_prefix) > size) + size = strlen (env_exec_prefix); + if (strlen (standard_exec_prefix) > size) + size = strlen (standard_exec_prefix); + if (strlen (standard_exec_prefix_1) > size) + size = strlen (standard_exec_prefix_1); + if (strlen (standard_startfile_prefix) > size) + size = strlen (standard_startfile_prefix); + if (strlen (standard_startfile_prefix_1) > size) + size = strlen (standard_startfile_prefix_1); + if (strlen (standard_startfile_prefix_2) > size) + size = strlen (standard_startfile_prefix_2); + if (machine_suffix) + size += strlen (machine_suffix) + 1; + size += strlen (name) + 1; + + temp = (char *) alloca (size); + + if (user_exec_prefix) + { + if (machine_suffix) + { + strcpy (temp, user_exec_prefix); + strcat (temp, machine_suffix); + strcat (temp, name); + win = (access (temp, R_OK) == 0); + } + if (!win) + { + strcpy (temp, user_exec_prefix); + strcat (temp, name); + win = (access (temp, R_OK) == 0); + } + } + + if (!win && env_exec_prefix) + { + if (machine_suffix) + { + strcpy (temp, env_exec_prefix); + strcat (temp, machine_suffix); + strcat (temp, name); + win = (access (temp, R_OK) == 0); + } + if (!win) + { + strcpy (temp, env_exec_prefix); + strcat (temp, name); + win = (access (temp, R_OK) == 0); + } + } + + if (!win) + { + if (machine_suffix) + { + strcpy (temp, standard_exec_prefix); + strcat (temp, machine_suffix); + strcat (temp, name); + win = (access (temp, R_OK) == 0); + } + if (!win) + { + strcpy (temp, standard_exec_prefix); + strcat (temp, name); + win = (access (temp, R_OK) == 0); + } + } + + if (!win) + { + if (machine_suffix) + { + strcpy (temp, standard_exec_prefix_1); + strcat (temp, machine_suffix); + strcat (temp, name); + win = (access (temp, R_OK) == 0); + } + if (!win) + { + strcpy (temp, standard_exec_prefix_1); + strcat (temp, name); + win = (access (temp, R_OK) == 0); + } + } + + if (!win) + { + if (machine_suffix) + { + strcpy (temp, standard_startfile_prefix); + strcat (temp, machine_suffix); + strcat (temp, name); + win = (access (temp, R_OK) == 0); + } + if (!win) + { + strcpy (temp, standard_startfile_prefix); + strcat (temp, name); + win = (access (temp, R_OK) == 0); + } + } + + if (!win) + { + if (machine_suffix) + { + strcpy (temp, standard_startfile_prefix_1); + strcat (temp, machine_suffix); + strcat (temp, name); + win = (access (temp, R_OK) == 0); + } + if (!win) + { + strcpy (temp, standard_startfile_prefix_1); + strcat (temp, name); + win = (access (temp, R_OK) == 0); + } + } + + if (!win) + { + if (machine_suffix) + { + strcpy (temp, standard_startfile_prefix_2); + strcat (temp, machine_suffix); + strcat (temp, name); + win = (access (temp, R_OK) == 0); + } + if (!win) + { + strcpy (temp, standard_startfile_prefix_2); + strcat (temp, name); + win = (access (temp, R_OK) == 0); + } + } + + if (!win) + { + if (machine_suffix) + { + strcpy (temp, "./"); + strcat (temp, machine_suffix); + strcat (temp, name); + win = (access (temp, R_OK) == 0); + } + if (!win) + { + strcpy (temp, "./"); + strcat (temp, name); + win = (access (temp, R_OK) == 0); + } + } + + if (win) + return save_string (temp, strlen (temp)); + return name; +} + +/* On fatal signals, delete all the temporary files. */ + +void +fatal_error (signum) + int signum; +{ + signal (signum, SIG_DFL); + delete_failure_queue (); + delete_temp_files (); + /* Get the same signal again, this time not handled, + so its normal effect occurs. */ + kill (getpid (), signum); +} + +int +main (argc, argv) + int argc; + char **argv; +{ + register int i; + int value; + int error_count = 0; + int linker_was_run = 0; + char *explicit_link_files; + + programname = argv[0]; + + if (signal (SIGINT, SIG_IGN) != SIG_IGN) + signal (SIGINT, fatal_error); + if (signal (SIGHUP, SIG_IGN) != SIG_IGN) + signal (SIGHUP, fatal_error); + if (signal (SIGTERM, SIG_IGN) != SIG_IGN) + signal (SIGTERM, fatal_error); + if (signal (SIGPIPE, SIG_IGN) != SIG_IGN) + signal (SIGPIPE, fatal_error); + + argbuf_length = 10; + argbuf = (char **) xmalloc (argbuf_length * sizeof (char *)); + + obstack_init (&obstack); + + choose_temp_base (); + + /* Make a table of what switches there are (switches, n_switches). + Make a table of specified input files (infiles, n_infiles). */ + + process_command (argc, argv); + + if (vflag) + { + extern char *version_string; + fprintf (stderr, "gcc version %s\n", version_string); + if (n_infiles == 0) + exit (0); + } + + if (n_infiles == 0) + fatal ("No input files specified."); + + /* Make a place to record the compiler output file names + that correspond to the input files. */ + + outfiles = (char **) xmalloc (n_infiles * sizeof (char *)); + bzero (outfiles, n_infiles * sizeof (char *)); + + /* Record which files were specified explicitly as link input. */ + + explicit_link_files = (char *) xmalloc (n_infiles); + bzero (explicit_link_files, n_infiles); + + for (i = 0; i < n_infiles; i++) + { + register struct compiler *cp; + int this_file_error = 0; + + /* Tell do_spec what to substitute for %i. */ + + input_filename = infiles[i]; + input_filename_length = strlen (input_filename); + input_file_number = i; + + /* Use the same thing in %o, unless cp->spec says otherwise. */ + + outfiles[i] = input_filename; + + /* Figure out which compiler from the file's suffix. */ + + for (cp = compilers; cp->spec; cp++) + { + if (strlen (cp->suffix) < input_filename_length + && !strcmp (cp->suffix, + infiles[i] + input_filename_length + - strlen (cp->suffix))) + { + /* Ok, we found an applicable compiler. Run its spec. */ + /* First say how much of input_filename to substitute for %b */ + register char *p; + + input_basename = input_filename; + for (p = input_filename; *p; p++) + if (*p == '/') + input_basename = p + 1; + basename_length = (input_filename_length - strlen (cp->suffix) + - (input_basename - input_filename)); + value = do_spec (cp->spec); + if (value < 0) + this_file_error = 1; + break; + } + } + + /* If this file's name does not contain a recognized suffix, + record it as explicit linker input. */ + + if (! cp->spec) + explicit_link_files[i] = 1; + + /* Clear the delete-on-failure queue, deleting the files in it + if this compilation failed. */ + + if (this_file_error) + { + delete_failure_queue (); + error_count++; + } + /* If this compilation succeeded, don't delete those files later. */ + clear_failure_queue (); + } + + /* Run ld to link all the compiler output files. */ + + if (error_count == 0) + { + int tmp = execution_count; + value = do_spec (link_spec); + if (value < 0) + error_count = 1; + linker_was_run = (tmp != execution_count); + } + + /* If options said don't run linker, + complain about input files to be given to the linker. */ + + if (! linker_was_run && error_count == 0) + for (i = 0; i < n_infiles; i++) + if (explicit_link_files[i]) + error ("%s: linker input file unused since linking not done", + outfiles[i]); + + /* Set the `valid' bits for switches that match anything in any spec. */ + + validate_all_switches (); + + /* Warn about any switches that no pass was interested in. */ + + for (i = 0; i < n_switches; i++) + if (! switches[i].valid) + error ("unrecognized option `-%s'", switches[i].part1); + + /* Delete some or all of the temporary files we made. */ + + if (error_count) + delete_failure_queue (); + delete_temp_files (); + + exit (error_count); +} + +xmalloc (size) + int size; +{ + register int value = malloc (size); + if (value == 0) + fatal ("virtual memory exhausted"); + return value; +} + +xrealloc (ptr, size) + int ptr, size; +{ + register int value = realloc (ptr, size); + if (value == 0) + fatal ("virtual memory exhausted"); + return value; +} + +/* Return a newly-allocated string whose contents concatenate those of s1, s2, s3. */ + +char * +concat (s1, s2, s3) + char *s1, *s2, *s3; +{ + int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3); + char *result = (char *) xmalloc (len1 + len2 + len3 + 1); + + strcpy (result, s1); + strcpy (result + len1, s2); + strcpy (result + len1 + len2, s3); + *(result + len1 + len2 + len3) = 0; + + return result; +} + +char * +save_string (s, len) + char *s; + int len; +{ + register char *result = (char *) xmalloc (len + 1); + + bcopy (s, result, len); + result[len] = 0; + return result; +} + +pfatal_with_name (name) + char *name; +{ + extern int errno, sys_nerr; + extern char *sys_errlist[]; + char *s; + + if (errno < sys_nerr) + s = concat ("%s: ", sys_errlist[errno], ""); + else + s = "cannot open %s"; + fatal (s, name); +} + +perror_with_name (name) + char *name; +{ + extern int errno, sys_nerr; + extern char *sys_errlist[]; + char *s; + + if (errno < sys_nerr) + s = concat ("%s: ", sys_errlist[errno], ""); + else + s = "cannot open %s"; + error (s, name); +} + +perror_exec (name) + char *name; +{ + extern int errno, sys_nerr; + extern char *sys_errlist[]; + char *s; + + if (errno < sys_nerr) + s = concat ("installation problem, cannot exec %s: ", + sys_errlist[errno], ""); + else + s = "installation problem, cannot exec %s"; + error (s, name); +} + +/* 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."); +} + +#ifdef HAVE_VPRINTF + +/* Output an error message and exit */ + +int +fatal (va_alist) + va_dcl +{ + va_list ap; + char *format; + + va_start(ap); + format = va_arg (ap, char *); + vfprintf (stderr, format, ap); + va_end (ap); + fprintf (stderr, "\n"); + delete_temp_files (); + exit (1); +} + +error (va_alist) + va_dcl +{ + va_list ap; + char *format; + + va_start(ap); + format = va_arg (ap, char *); + fprintf (stderr, "%s: ", programname); + vfprintf (stderr, format, ap); + va_end (ap); + + fprintf (stderr, "\n"); +} + +#else /* not HAVE_VPRINTF */ + +fatal (msg, arg1, arg2) + char *msg, *arg1, *arg2; +{ + error (msg, arg1, arg2); + delete_temp_files (0); + exit (1); +} + +error (msg, arg1, arg2) + char *msg, *arg1, *arg2; +{ + fprintf (stderr, "%s: ", programname); + fprintf (stderr, msg, arg1, arg2); + fprintf (stderr, "\n"); +} + +#endif /* not HAVE_VPRINTF */ + + +void +validate_all_switches () +{ + struct compiler *comp; + register char *p; + register char c; + + for (comp = compilers; comp->spec; comp++) + { + p = comp->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); + + /* Now notice switches mentioned in the machine-specific specs. */ + +#ifdef ASM_SPEC + p = ASM_SPEC; + while (c = *p++) + if (c == '%' && *p == '{') + /* We have a switch spec. */ + validate_switches (p + 1); +#endif + +#ifdef CPP_SPEC + p = CPP_SPEC; + while (c = *p++) + if (c == '%' && *p == '{') + /* We have a switch spec. */ + validate_switches (p + 1); +#endif + +#ifdef SIGNED_CHAR_SPEC + p = SIGNED_CHAR_SPEC; + while (c = *p++) + if (c == '%' && *p == '{') + /* We have a switch spec. */ + validate_switches (p + 1); +#endif + +#ifdef CC1_SPEC + p = CC1_SPEC; + while (c = *p++) + if (c == '%' && *p == '{') + /* We have a switch spec. */ + validate_switches (p + 1); +#endif + +#ifdef LINK_SPEC + p = LINK_SPEC; + while (c = *p++) + if (c == '%' && *p == '{') + /* We have a switch spec. */ + validate_switches (p + 1); +#endif + +#ifdef LIB_SPEC + p = LIB_SPEC; + while (c = *p++) + if (c == '%' && *p == '{') + /* We have a switch spec. */ + validate_switches (p + 1); +#endif + +#ifdef STARTFILE_SPEC + p = STARTFILE_SPEC; + while (c = *p++) + if (c == '%' && *p == '{') + /* We have a switch spec. */ + validate_switches (p + 1); +#endif +} + +/* Look at the switch-name that comes after START + and mark as valid all supplied switches that match it. */ + +void +validate_switches (start) + char *start; +{ + register char *p = start; + char *filter; + register int i; + + if (*p == '|') + ++p; + + if (*p == '!') + ++p; + + filter = p; + while (*p != ':' && *p != '}') p++; + + if (p[-1] == '*') + { + /* Mark all matching switches as valid. */ + --p; + for (i = 0; i < n_switches; i++) + if (!strncmp (switches[i].part1, filter, p - filter)) + switches[i].valid = 1; + } + else + { + /* Mark an exact matching switch as valid. */ + for (i = 0; i < n_switches; i++) + { + if (!strncmp (switches[i].part1, filter, p - filter) + && switches[i].part1[p - filter] == 0) + switches[i].valid = 1; + } + } +} diff --git a/gcc-1.40/gcc.dvi b/gcc-1.40/gcc.dvi new file mode 100644 index 0000000..fc42fad Binary files /dev/null and b/gcc-1.40/gcc.dvi differ diff --git a/gcc-1.40/gcc.hlp b/gcc-1.40/gcc.hlp new file mode 100644 index 0000000..27c5658 --- /dev/null +++ b/gcc-1.40/gcc.hlp @@ -0,0 +1,153 @@ +1 GCC + The GCC command invokes the GNU C compiler. + + GCC file-spec + +2 Parameters + + file-spec + + A C source file. If no input file extension is specified, GNU C + assumes .C as the default extension. + +2 Qualifiers + + GNU C command qualifiers modify the way the compiler handles the + compiliation. + + The following is the list of available qualifiers for GNU C: + + + /CC1_OPTIONS=(option [,option...]]) + + /DEBUG + + /DEFINE=(identifier[=definition][,...]) + + /INCLUDE_DIRECTORY=(path [,path...]]) + + /MACHINE_CODE + + /OPTIMIZE + + /UNDEFINE=(identifier[,identifier,...]) + + /VERBOSE + + +2 Linking + + When linking programs compiled with GNU C, you should include the GNU + C library before the VAX C library. For example, + + LINK object-file,GNU_CC:[000000]GCCLIB/LIB,SYS$LIBRARY:VAXCRTL/LIB + + You can also link your program with the shared VAX C library. This + can reduce the size of the .EXE file, as well as make it smaller + when it's running. For example, + + $ LINK object-file, GNU_CC:[000000]GCCLIB/LIB,SYS$INPUT:/OPTIONS + SYS$SHARE:VAXCRTL/SHARE + + (If you use the second example and type it in by hand, be sure to type + ^Z after the last carriage return) + +2 /DEBUG + + /DEBUG includes additional information in the object file output so + that the program can be debugged with the VAX Symbolic Debugger. + This qualifier includes very little information, so using the + debugger is somewhat difficult. + +2 /DEFINE=(identifier[=definition][,...]) + + /DEFINE defines a string or macro ('definition') to be substituted + for every occurrence of a given string ('identifier') in a program. + It is equivalent to the #define preprocessor directive. + + All definitions and identifiers are converted to uppercase unless they + are in quotation marks. + + The simple form of the /DEFINE qualifier, + + /DEFINE=vms + + results in a definition equivalent to the preprocessor directive + + #define VMS 1 + + You must enclose macro definitions in quotation marks, as in this + example: + + /DEFINE="C(x)=((x) & 0xff)" + + This definition is the same as the preprocessor definition + + #define C(x) ((x) & 0xff) + + If more than one /DEFINE is present on the GCC command line, only + the last /DEFINE is used. + + If both /DEFINE and /UNDEFINE are present on a command line, /DEFINE + is evaluated before /UNDEFINE + +2 /INCLUDE_DIRECTORY=(path [,path...]) + + The /INCLUDE_DIRECTORY qualifier provides additional directories to + search for user-defined include files. 'path' can be either a + logical name or a directory specification. + + There are two forms for specifying include files - #include "file-spec" + and #include . For the #include "file-spec" form, the search + order is: + + 1. The directory containing the source file. + + 2. The directories in the /INCLUDE qualifier (if any). + + 3. The directory (or directories) specified in the logical name + GNU_CC_INCLUDE. + + 4. The directory (or directories) specified in the logical name + SYS$LIBRARY. + + For the #include form, the search order is: + + 1. The directories specified in the /INCLUDE qualifier (if any). + + 2. The directory (or directories) specified in the logical name + GNU_CC_INCLUDE. + + 3. The directory (or directories) specified in the logical name + SYS$LIBRARY. + +2 /MACHINE_CODE + + Tells GNU C to output the machine code generated by the compiler. Note + that no object file is produced when /MACHINE_CODE is specified. The + machine code is output to a file with the same name as the input file, + with the extension .S. + +2 /OPTIMIZE + /NOOPTIMIZE + + Controls whether optimization is performed by the compiler. By default, + optimization is on. /NOOPTIMIZE turns optimization off. + +2 /UNDEFINE + + /UNDEFINE cancels a macro definition. Thus, it is the same as the + #undef preprocessor directive. + + If more than one /UNDEFINE is present on the GCC command line, only + the last /UNDEFINE is used. + + If both /DEFINE and /UNDEFINE are present on a command line, /DEFINE + is evaluated before /UNDEFINE + +2 /VERBOSE + + Controls whether the user sees the invocation command strings for the + preprocessor, compiler, and assembler. The compiler also outputs + some statistics on time spent in its various phases. + diff --git a/gcc-1.40/gcc.info b/gcc-1.40/gcc.info new file mode 100644 index 0000000..ba495da --- /dev/null +++ b/gcc-1.40/gcc.info @@ -0,0 +1,137 @@ +Info file gcc.info, produced by Makeinfo, -*- Text -*- from input +file gcc.texinfo. + + This file documents the use and the internals of the GNU compiler. + + Copyright (C) 1988, 1989, 1990 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. + + 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" and "Protect +Your Freedom--Fight `Look And Feel'" 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" and "Protect Your Freedom--Fight `Look And Feel'" and this +permission notice may be included in translations approved by the +Free Software Foundation instead of in the original English. + +Indirect: +gcc.info-1: 1201 +gcc.info-2: 23370 +gcc.info-3: 59004 +gcc.info-4: 108328 +gcc.info-5: 148022 +gcc.info-6: 197139 +gcc.info-7: 245248 +gcc.info-8: 287049 +gcc.info-9: 334140 +gcc.info-10: 383069 +gcc.info-11: 432736 + +Tag Table: +(Indirect) +Node: Top1203 +Node: Copying2579 +Node: Contributors15946 +Node: Boycott18145 +Node: Options23372 +Node: Installation59006 +Node: Other Dir78072 +Node: Sun Install79316 +Node: 3b1 Install81176 +Node: SCO Install82519 +Node: VMS Install83280 +Node: HPUX Install90886 +Node: Tower Install91842 +Node: Trouble92394 +Node: Service95393 +Node: Incompatibilities95971 +Node: Extensions104866 +Node: Statement Exprs106873 +Node: Naming Types108330 +Node: Typeof109419 +Node: Lvalues111287 +Node: Conditionals113201 +Node: Zero-Length114128 +Node: Variable-Length114806 +Node: Subscripting116589 +Node: Pointer Arith117072 +Node: Initializers117651 +Node: Constructors118095 +Node: Function Attributes119596 +Node: Dollar Signs121312 +Node: Alignment121813 +Node: Inline123151 +Node: Extended Asm126108 +Node: Asm Labels134884 +Node: Explicit Reg Vars136202 +Node: Global Reg Vars137217 +Node: Local Reg Vars141451 +Node: Alternate Keywords143044 +Node: Bugs144209 +Node: Bug Criteria145201 +Node: Bug Reporting148024 +Node: Portability158743 +Node: Interface160507 +Node: Passes164911 +Node: RTL177793 +Node: RTL Objects179628 +Node: Accessors182561 +Node: Flags185866 +Node: Machine Modes190479 +Node: Constants197141 +Node: Regs and Memory199893 +Node: Arithmetic207258 +Node: Comparisons212492 +Node: Bit Fields215304 +Node: Conversions216388 +Node: RTL Declarations219062 +Node: Side Effects219833 +Node: Incdec229116 +Node: Assembler231489 +Node: Insns233011 +Node: Calls243128 +Node: Sharing245250 +Node: Machine Desc248064 +Node: Patterns249708 +Node: Example253019 +Node: RTL Template254147 +Node: Output Template262171 +Node: Output Statement265190 +Node: Constraints267327 +Node: Simple Constraints268255 +Node: Multi-Alternative278669 +Node: Class Preferences281678 +Node: Modifiers282558 +Node: No Constraints285940 +Node: Standard Names287051 +Node: Pattern Ordering301654 +Node: Dependent Patterns302880 +Node: Jump Patterns307633 +Node: Peephole Definitions310012 +Node: Expander Definitions316964 +Node: Machine Macros323916 +Node: Run-time Target325153 +Node: Storage Layout328997 +Node: Registers334142 +Node: Register Classes348305 +Node: Stack Layout358344 +Node: Library Calls380662 +Node: Addressing Modes383071 +Node: Delayed Branch389500 +Node: Condition Code392584 +Node: Cross-compilation395295 +Node: Misc399753 +Node: Assembler Format407089 +Node: Config432738 + +End Tag Table diff --git a/gcc-1.40/gcc.info-1 b/gcc-1.40/gcc.info-1 new file mode 100644 index 0000000..5452276 --- /dev/null +++ b/gcc-1.40/gcc.info-1 @@ -0,0 +1,518 @@ +Info file gcc.info, produced by Makeinfo, -*- Text -*- from input +file gcc.texinfo. + + This file documents the use and the internals of the GNU compiler. + + Copyright (C) 1988, 1989, 1990 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. + + 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" and "Protect +Your Freedom--Fight `Look And Feel'" 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" and "Protect Your Freedom--Fight `Look And Feel'" and this +permission notice may be included in translations approved by the +Free Software Foundation instead of in the original English. + + +File: gcc.info, Node: Top, Next: Copying, Up: (DIR) + +Introduction +************ + + This manual documents how to run, install and port the GNU C +compiler, as well as its new features and incompatibilities, and how +to report bugs. + +* Menu: + +* Copying:: GNU General Public License says + how you can copy and share GNU CC. +* Contributors:: People who have contributed to GNU CC. +* Boycott:: Protect your freedom--fight "look and feel". +* Options:: Command options supported by `gcc'. +* Installation:: How to configure, compile and install GNU CC. +* Trouble:: If you have trouble installing GNU CC. +* Service:: How to find suppliers of services for GNU CC users. +* Incompatibilities:: Incompatibilities of GNU CC. +* Extensions:: GNU extensions to the C language. +* Bugs:: How to report bugs (if you want to get them fixed). +* Portability:: Goals of GNU CC's portability features. +* Interface:: Function-call interface of GNU CC output. +* Passes:: Order of passes, what they do, and what each file is for. +* RTL:: The intermediate representation that most passes work on. +* Machine Desc:: How to write machine description instruction patterns. +* Machine Macros:: How to write the machine description C macros. +* Config:: Writing the `xm-MACHINE.h' file. + + +File: gcc.info, Node: Copying, Next: Contributors, Prev: Top, Up: Top + +GNU GENERAL PUBLIC LICENSE +************************** + + Version 1, February 1989 + + Copyright (C) 1989 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +Preamble +======== + + The license agreements of most software companies try to keep +users at the mercy of those companies. By contrast, our 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. The General Public License applies to the Free Software +Foundation's software and to any other program whose authors commit +to using it. You can use it for your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Specifically, the General Public License is designed to make +sure that you have the freedom to give away or sell copies of free +software, 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 a 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 tell them 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. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 1. This License Agreement 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 work containing the Program or a portion of it, either + verbatim or with modifications. Each licensee is addressed as + "you". + + 2. You may copy and distribute verbatim copies of the Program's + source code as you receive it, in any medium, provided that you + conspicuously and appropriately publish on each copy an + appropriate copyright notice and disclaimer of warranty; keep + intact all the notices that refer to this General Public License + and to the absence of any warranty; and give any other + recipients of the Program a copy of this General Public License + along with the Program. You may charge a fee for the physical + act of transferring a copy. + + 3. You may modify your copy or copies of the Program or any portion + of it, and copy and distribute such modifications under the + terms of Paragraph 1 above, provided that you also do the + following: + + * cause the modified files to carry prominent notices stating + that you changed the files and the date of any change; and + + * cause the whole of any work that you distribute or publish, + that in whole or in part contains the Program or any part + thereof, either with or without modifications, to be + licensed at no charge to all third parties under the terms + of this General Public License (except that you may choose + to grant warranty protection to some or all third parties, + at your option). + + * If the modified program normally reads commands + interactively when run, you must cause it, when started + running for such interactive use in the simplest and most + usual 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 + General Public License. + + * 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. + + Mere aggregation of another independent work with the Program + (or its derivative) on a volume of a storage or distribution + medium does not bring the other work under the scope of these + terms. + + 4. You may copy and distribute the Program (or a portion or + derivative of it, under Paragraph 2) in object code or + executable form under the terms of Paragraphs 1 and 2 above + provided that you also do one of the following: + + * accompany it with the complete corresponding + machine-readable source code, which must be distributed + under the terms of Paragraphs 1 and 2 above; or, + + * accompany it with a written offer, valid for at least three + years, to give any third party free (except for a nominal + charge for the cost of distribution) a complete + machine-readable copy of the corresponding source code, to + be distributed under the terms of Paragraphs 1 and 2 above; + or, + + * accompany it with the information you received as to where + the corresponding source code may be obtained. (This + alternative is allowed only for noncommercial distribution + and only if you received the program in object code or + executable form alone.) + + Source code for a work means the preferred form of the work + for making modifications to it. For an executable file, + complete source code means all the source code for all modules + it contains; but, as a special exception, it need not include + source code for modules which are standard libraries that + accompany the operating system on which the executable file + runs, or for standard header files or definitions files that + accompany that operating system. + + 5. You may not copy, modify, sublicense, distribute or transfer the + Program except as expressly provided under this General Public + License. Any attempt otherwise to copy, modify, sublicense, + distribute or transfer the Program is void, and will + automatically terminate your rights to use the Program under + this License. However, parties who have received copies, or + rights to use copies, from you under this General Public License + will not have their licenses terminated so long as such parties + remain in full compliance. + + 6. By copying, distributing or modifying 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. + + 7. Each time you redistribute the Program (or any work based on the + Program), the recipient automatically receives a license from + the original licensor to copy, distribute or modify the Program + subject to these terms and conditions. You may not impose any + further restrictions on the recipients' exercise of the rights + granted herein. + + 8. 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 the 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 the license, + you may choose any version ever published by the Free Software + Foundation. + + 9. 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. + + NO WARRANTY + + 10. 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. + + 11. 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 OF TERMS AND CONDITIONS + +Appendix: 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 humanity, the best way to achieve this is to +make it free software which everyone can redistribute and change +under these terms. + + To do so, attach the following notices to the program. It is +safest to attach them to the start of each source file to most +effectively convey the exclusion of warranty; and each file should +have at least the "copyright" line and a pointer to where the full +notice is found. + + ONE LINE TO GIVE THE PROGRAM'S NAME AND A BRIEF IDEA OF WHAT IT DOES. + Copyright (C) 19YY 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 1, 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. + + Also add information on how to contact you by electronic and paper +mail. + + If the program is interactive, make it output a short notice like +this when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19YY NAME OF AUTHOR + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + + The hypothetical commands `show w' and `show c' should show the +appropriate parts of the General Public License. Of course, the +commands you use may be called something other than `show w' and +`show c'; they could even be mouse-clicks or menu items--whatever +suits your program. + + You should also get your employer (if you work as a programmer) or +your school, if any, to sign a "copyright disclaimer" for the +program, if necessary. Here a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + program `Gnomovision' (a program to direct compilers to make passes + at assemblers) written by James Hacker. + + SIGNATURE OF TY COON, 1 April 1989 + Ty Coon, President of Vice + + That's all there is to it! + + +File: gcc.info, Node: Contributors, Next: Boycott, Prev: Copying, Up: Top + +Contributors to GNU CC +********************** + + In addition to Richard Stallman, several people have written parts +of GNU CC. + + * The idea of using RTL and some of the optimization ideas came + from the U. of Arizona Portable Optimizer, written by Jack + Davidson and Christopher Fraser. See "Register Allocation and + Exhaustive Peephole Optimization", Software Practice and + Experience 14 (9), Sept. 1984, 857-866. + + * Paul Rubin wrote most of the preprocessor. + + * Leonard Tower wrote parts of the parser, RTL generator, and RTL + definitions, and of the Vax machine description. + + * Ted Lemon wrote parts of the RTL reader and printer. + + * Jim Wilson implemented loop strength reduction and some other + loop optimizations. + + * Nobuyuki Hikichi of Software Research Associates, Tokyo, + contributed the support for the Sony NEWS machine. + + * Charles LaBrec contributed the support for the Integrated + Solutions 68020 system. + + * Michael Tiemann of MCC wrote most of the description of the + National Semiconductor 32000 series cpu. He also wrote the code + for inline function integration and for the SPARC cpu and + Motorola 88000 cpu and part of the Sun FPA support. + + * Jan Stein of the Chalmers Computer Society provided support for + Genix, as well as part of the 32000 machine description. + + * Randy Smith finished the Sun FPA support. + + * Robert Brown implemented the support for Encore 32000 systems. + + * David Kashtan of SRI adapted GNU CC to the Vomit-Making System. + + * Alex Crain provided changes for the 3b1. + + * Greg Satz and Chris Hanson assisted in making GNU CC work on + HP-UX for the 9000 series 300. + + * William Schelter did most of the work on the Intel 80386 support. + + * Christopher Smith did the port for Convex machines. + + * Paul Petersen wrote the machine description for the Alliant FX/8. + + * Alain Lichnewsky ported GNU CC to the Mips cpu. + + * Devon Bowen, Dale Wiles and Kevin Zachmann ported GNU CC to the + Tahoe. + + * Jonathan Stone wrote the machine description for the Pyramid + computer. + + +File: gcc.info, Node: Boycott, Next: Options, Prev: Contributors, Up: Top + +Protect Your Freedom--Fight "Look And Feel" +******************************************* + + This section is a political message from the League for + Programming Freedom to the users of GNU CC. It is included here + as an expression of support for the League on the part of the + Free Software Foundation and Richard Stallman. + + Ashton-Tate, Apple, Lotus and Xerox are trying to create a new +form of legal monopoly: a copyright on a class of user interfaces. +These monopolies would cause serious problems for users and +developers of computer software and systems. + + Until a few years ago, the law seemed clear: no one could restrict +others from using a user interface; programmers were free to +implement any interface they chose. Imitating interfaces, sometimes +with changes, was standard practice in the computer field. The +interfaces we know evolved gradually in this way; for example, the +Macintosh user interface drew ideas from the Xerox interface, which +in turn drew on work done at Stanford and SRI. 1-2-3 imitated +VisiCalc, and dBase imitated a database program from JPL. + + Most computer companies, and nearly all computer users, were happy +with this state of affairs. The companies that are suing say it does +not offer "enough incentive" to develop their products, but they must +have considered it "enough" when they made their decision to do so. +It seems they are not satisfied with the opportunity to continue to +compete in the marketplace--not even with a head start. + + If Xerox, Lotus, Apple and Ashton-Tate are permitted to make law +through the courts, the precedent will hobble the software industry: + + * Gratuitous incompatibilities will burden users. Imagine if each + car manufacturer had to arrange the pedals in a different order. + + * Software will become and remain more expensive. Users will be + "locked in" to proprietary interfaces, for which there is no + real competition. + + * Large companies have an unfair advantage wherever lawsuits + become commonplace. Since they can easily afford to sue, they + can intimidate small companies with threats even when they don't + really have a case. + + * User interface improvements will come slower, since incremental + evolution through creative imitation will no longer be permitted. + + * Even Apple, etc., will find it harder to make improvements if + they can no longer adapt the good ideas that others introduce, + for fear of weakening their own legal positions. Some users + suggest that this stagnation may already have started. + + * If you use GNU software, you might find it of some concern that + user interface copyright will make it hard for the Free Software + Foundation to develop programs compatible with the interfaces + that you already know. + + To protect our freedom from lawsuits like these, a group of +programmers and users have formed a new grass-roots political +organization, the League for Programming Freedom. + + The purpose of the League is to oppose new monopolistic practices +such as user-interface copyright and software patents; it calls for a +return to the legal policies of the recent past, in which these +practices were not allowed. The League is not concerned with free +software as an issue, and not affiliated with the Free Software +Foundation. + + The League's membership rolls include John McCarthy, inventor of +Lisp, Marvin Minsky, founder of the 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. + + The League needs both activist members and members who only pay +their dues. + + To join, or for more information, phone (617) 492-0023 or write to: + + League for Programming Freedom + 1 Kendall Square #143 + P.O. Box 9171 + Cambridge, MA 02139 league@prep.ai.mit.edu + + Here are some suggestions from the League for how you can protect +your freedom to write programs: + + * Don't buy from Xerox, Lotus, Apple or Ashton-Tate. Buy from + their competitors or from the defendants they are suing. + + * Don't develop software to work with the systems made by these + companies. + + * Port your existing software to competing systems, so that you + encourage users to switch. + + * Write letters to company presidents to let them know their + conduct is unacceptable. + + * Tell your friends and colleagues about this issue and how it + threatens to ruin the computer industry. + + * Above all, don't work for the look-and-feel plaintiffs, and + don't accept contracts from them. + + * Write to Congress to explain the importance of this issue. + + House Subcommittee on Intellectual Property + 2137 Rayburn Bldg + Washington, DC 20515 + + Senate Subcommittee on Patents, Trademarks and Copyrights + United States Senate + Washington, DC 20510 + + Express your opinion! You can make a difference. + + \ No newline at end of file diff --git a/gcc-1.40/gcc.info-10 b/gcc-1.40/gcc.info-10 new file mode 100644 index 0000000..7a22672 --- /dev/null +++ b/gcc-1.40/gcc.info-10 @@ -0,0 +1,1161 @@ +Info file gcc.info, produced by Makeinfo, -*- Text -*- from input +file gcc.texinfo. + + This file documents the use and the internals of the GNU compiler. + + Copyright (C) 1988, 1989, 1990 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. + + 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" and "Protect +Your Freedom--Fight `Look And Feel'" 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" and "Protect Your Freedom--Fight `Look And Feel'" and this +permission notice may be included in translations approved by the +Free Software Foundation instead of in the original English. + + +File: gcc.info, Node: Addressing Modes, Next: Delayed Branch, Prev: Library Calls, Up: Machine Macros + +Addressing Modes +================ + +`HAVE_POST_INCREMENT' + Define this macro if the machine supports post-increment + addressing. + +`HAVE_PRE_INCREMENT' +`HAVE_POST_DECREMENT' +`HAVE_PRE_DECREMENT' + Similar for other kinds of addressing. + +`CONSTANT_ADDRESS_P (X)' + A C expression that is 1 if the RTX X is a constant whose value + is an integer. This includes integers whose values are not + explicitly known, such as `symbol_ref' and `label_ref' + expressions and `const' arithmetic expressions. + + On most machines, this can be defined as `CONSTANT_P (X)', but a + few machines are more restrictive in which constant addresses + are supported. + +`MAX_REGS_PER_ADDRESS' + A number, the maximum number of registers that can appear in a + valid memory address. Note that it is up to you to specify a + value equal to the maximum number that + `go_if_legitimate_address' would ever accept. + +`GO_IF_LEGITIMATE_ADDRESS (MODE, X, LABEL)' + A C compound statement with a conditional `goto LABEL;' executed + if X (an RTX) is a legitimate memory address on the target + machine for a memory operand of mode MODE. + + It usually pays to define several simpler macros to serve as + subroutines for this one. Otherwise it may be too complicated + to understand. + + This macro must exist in two variants: a strict variant and a + non-strict one. The strict variant is used in the reload pass. + It must be defined so that any pseudo-register that has not been + allocated a hard register is considered a memory reference. In + contexts where some kind of register is required, a + pseudo-register with no hard register must be rejected. + + The non-strict variant is used in other passes. It must be + defined to accept all pseudo-registers in every context where + some kind of register is required. + + Compiler source files that want to use the strict variant of + this macro define the macro `REG_OK_STRICT'. You should use an + `#ifdef REG_OK_STRICT' conditional to define the strict variant + in that case and the non-strict variant otherwise. + + Typically among the subroutines used to define + `GO_IF_LEGITIMATE_ADDRESS' are subroutines to check for + acceptable registers for various purposes (one for base + registers, one for index registers, and so on). Then only these + subroutine macros need have two variants; the higher levels of + macros may be the same whether strict or not. + + Normally, constant addresses which are the sum of a `symbol_ref' + and an integer are stored inside a `const' RTX to mark them as + constant. Therefore, there is no need to recognize such sums as + legitimate addresses. + + Usually `PRINT_OPERAND_ADDRESS' is not prepared to handle + constant sums that are not marked with `const'. It assumes + that a naked `plus' indicates indexing. If so, then you *must* + reject such naked constant sums as illegitimate addresses, so + that none of them will be given to `PRINT_OPERAND_ADDRESS'. + +`REG_OK_FOR_BASE_P (X)' + A C expression that is nonzero if X (assumed to be a `reg' RTX) + is valid for use as a base register. For hard registers, it + should always accept those which the hardware permits and reject + the others. Whether the macro accepts or rejects pseudo + registers must be controlled by `REG_OK_STRICT' as described + above. This usually requires two variant definitions, of which + `REG_OK_STRICT' controls the one actually used. + +`REG_OK_FOR_INDEX_P (X)' + A C expression that is nonzero if X (assumed to be a `reg' RTX) + is valid for use as an index register. + + The difference between an index register and a base register is + that the index register may be scaled. If an address involves + the sum of two registers, neither one of them scaled, then + either one may be labeled the "base" and the other the "index"; + but whichever labeling is used must fit the machine's + constraints of which registers may serve in each capacity. The + compiler will try both labelings, looking for one that is valid, + and will reload one or both registers only if neither labeling + works. + +`LEGITIMIZE_ADDRESS (X, OLDX, MODE, WIN)' + A C compound statement that attempts to replace X with a valid + memory address for an operand of mode MODE. WIN will be a C + statement label elsewhere in the code; the macro definition may + use + + GO_IF_LEGITIMATE_ADDRESS (MODE, X, WIN); + + to avoid further processing if the address has become legitimate. + + X will always be the result of a call to + `break_out_memory_refs', and OLDX will be the operand that was + given to that function to produce X. + + The code generated by this macro should not alter the + substructure of X. If it transforms X into a more legitimate + form, it should assign X (which will always be a C variable) a + new value. + + It is not necessary for this macro to come up with a legitimate + 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. + +`GO_IF_MODE_DEPENDENT_ADDRESS (ADDR, LABEL)' + A C statement or compound statement with a conditional `goto + LABEL;' executed if memory address X (an RTX) can have different + meanings depending on the machine mode of the memory reference + it is used for. + + Autoincrement and autodecrement addresses typically have + mode-dependent effects because the amount of the increment or + decrement is the size of the operand being addressed. Some + machines have other mode-dependent addresses. Many RISC + machines have no mode-dependent addresses. + + You may assume that ADDR is a valid address for the machine. + +`LEGITIMATE_CONSTANT_P (X)' + A C expression that is nonzero if X is a legitimate constant for + an immediate operand on the target machine. You can assume that + either X is a `const_double' or it satisfies `CONSTANT_P', so + you need not check these things. In fact, `1' is a suitable + definition for this macro on machines where any `const_double' + is valid and anything `CONSTANT_P' is valid. + + +File: gcc.info, Node: Delayed Branch, Next: Condition Code, Prev: Addressing Modes, Up: Machine Macros + +Parameters for Delayed Branch Optimization +========================================== + +`HAVE_DELAYED_BRANCH' + Define this macro if the target machine has delayed branches, + that is, a branch does not take effect immediately, and the + actual branch instruction may be followed by one or more + instructions that will be issued before the PC is actually + changed. + + If defined, this allows a special scheduling pass to be run + after the second jump optimization to attempt to reorder + instructions to exploit this. Defining this macro also requires + the definition of certain other macros described below. + +`DBR_SLOTS_AFTER (INSN)' + This macro must be defined if `HAVE_DELAYED_BRANCH' is defined. + Its definition should be a C expression returning the number of + available delay slots following the instruction(s) output by the + pattern for INSN. The definition of "slot" is + machine-dependent, and may denote instructions, bytes, or + whatever. + +`DBR_INSN_SLOTS (INSN)' + This macro must be defined if `HAVE_DELAYED_BRANCH' is defined. + It should be a C expression returning the number of slots + (typically the number of machine instructions) consumed by INSN. + + You may assume that INSN is truly an insn, not a note, label, + barrier, dispatch table, `use', or `clobber'. + +`DBR_INSN_ELIGIBLE_P (INSN, DINSN)' + A C expression whose value is non-zero if it is legitimate to + put INSN in the delay slot following DINSN. + + You do not need to take account of data flow considerations in + the definition of this macro, because the delayed branch + optimizer always does that. This macro is needed only when + certain insns may not be placed in certain delay slots for + reasons not evident from the RTL expressions themselves. If + there are no such problems, you don't need to define this macro. + + You may assume that INSN is truly an insn, not a note, label, + barrier, dispatch table, `use', or `clobber'. You may assume + that DINSN is a jump insn with a delay slot. + +`DBR_OUTPUT_SEQEND(FILE)' + A C statement, to be executed after all slot-filler instructions + have been output. If necessary, call `dbr_sequence_length' to + determine the number of slots filled in a sequence (zero if not + currently outputting a sequence), to decide how many no-ops to + output, or whatever. + + Don't define this macro if it has nothing to do, but it is + helpful in reading assembly output if the extent of the delay + sequence is made explicit (e.g. with white space). + + Note that output routines for instructions with delay slots must + be prepared to deal with not being output as part of a sequence + (i.e. when the scheduling pass is not run, or when no slot + fillers could be found.) The variable `final_sequence' is null + when not processing a sequence, otherwise it contains the + `sequence' rtx being output. + + +File: gcc.info, Node: Condition Code, Next: Cross-compilation, Prev: Delayed Branch, Up: Machine Macros + +Condition Code Information +========================== + + The file `conditions.h' defines a variable `cc_status' to describe +how the condition code was computed (in case the interpretation of +the condition code depends on the instruction that it was set by). +This variable contains the RTL expressions on which the condition +code is currently based, and several standard flags. + + Sometimes additional machine-specific flags must be defined in the +machine description header file. It can also add additional +machine-specific information by defining `CC_STATUS_MDEP'. + +`CC_STATUS_MDEP' + C code for a data type which is used for declaring the `mdep' + component of `cc_status'. It defaults to `int'. + +`CC_STATUS_MDEP_INIT' + A C expression to initialize the `mdep' field to "empty". The + default definition does nothing, since most machines don't use + the field anyway. If you want to use the field, you should + probably define this macro to initialize it. + +`NOTICE_UPDATE_CC (EXP, INSN)' + A C compound statement to set the components of `cc_status' + appropriately for an insn INSN whose body is EXP. It is this + macro's responsibility to recognize insns that set the condition + code as a byproduct of other activity as well as those that + explicitly set `(cc0)'. + + If there are insn that do not set the condition code but do + alter other machine registers, this macro must check to see + whether they invalidate the expressions that the condition code + is recorded as reflecting. For example, on the 68000, insns + that store in address registers do not set the condition code, + which means that usually `NOTICE_UPDATE_CC' can leave + `cc_status' unaltered for such insns. But suppose that the + previous insn set the condition code based on location + `a4@(102)' and the current insn stores a new value in `a4'. + Although the condition code is not changed by this, it will no + longer be true that it reflects the contents of `a4@(102)'. + Therefore, `NOTICE_UPDATE_CC' must alter `cc_status' in this + case to say that nothing is known about the condition code value. + + The definition of `NOTICE_UPDATE_CC' must be prepared to deal + with the results of peephole optimization: insns whose patterns + are `parallel' RTXs containing various `reg', `mem' or constants + which are just the operands. The RTL structure of these insns + is not sufficient to indicate what the insns actually do. What + `NOTICE_UPDATE_CC' should do when it sees one is just to run + `CC_STATUS_INIT'. + + +File: gcc.info, Node: Cross-compilation, Next: Misc, Prev: Condition Code, Up: Machine Macros + +Cross Compilation and Floating-Point Format +=========================================== + + While all modern machines use 2's complement representation for +integers, there are a variety of representations for floating point +numbers. This means that in a cross-compiler the representation of +floating point numbers in the compiled program may be different from +that used in the machine doing the compilation. + + Because different representation systems may offer different +amounts of range and precision, the cross compiler cannot safely use +the host machine's floating point arithmetic. Therefore, floating +point constants must be represented in the target machine's format. +This means that the cross compiler cannot use `atof' to parse a +floating point constant; it must have its own special routine to use +instead. Also, constant folding must emulate the target machine's +arithmetic (or must not be done at all). + + The macros in the following table should be defined only if you +are cross compiling between different floating point formats. + + Otherwise, don't define them. Then default definitions will be set +up which use `double' as the data type, `==' to test for equality, etc. + + You don't need to worry about how many times you use an operand of +any of these macros. The compiler never uses operands which have +side effects. + +`REAL_VALUE_TYPE' + A macro for the C data type to be used to hold a floating point + value in the target machine's format. Typically this would be a + `struct' containing an array of `int'. + +`REAL_VALUES_EQUAL (X, Y)' + A macro for a C expression which compares for equality the two + values, X and Y, both of type `REAL_VALUE_TYPE'. + +`REAL_VALUES_LESS (X, Y)' + A macro for a C expression which tests whether X is less than Y, + both values being of type `REAL_VALUE_TYPE' and interpreted as + floating point numbers in the target machine's representation. + +`REAL_VALUE_LDEXP (X, SCALE)' + A macro for a C expression which performs the standard library + function `ldexp', but using the target machine's floating point + representation. Both X and the value of the expression have + type `REAL_VALUE_TYPE'. The second argument, SCALE, is an + integer. + +`REAL_VALUE_ATOF (STRING)' + A macro for a C expression which converts STRING, an expression + of type `char *', into a floating point number in the target + machine's representation. The value has type `REAL_VALUE_TYPE'. + + Define the following additional macros if you want to make +floating point constant folding work while cross compiling. If you +don't define them, cross compilation is still possible, but constant +folding will not happen for floating point values. + +`REAL_ARITHMETIC (OUTPUT, CODE, X, Y)' + A macro for a C statement which calculates an arithmetic + operation of the two floating point values X and Y, both of type + `REAL_VALUE_TYPE' in the target machine's representation, to + produce a result of the same type and representation which is + stored in OUTPUT (which will be a variable). + + The operation to be performed is specified by CODE, a tree code + which will always be one of the following: `PLUS_EXPR', + `MINUS_EXPR', `MULT_EXPR', `RDIV_EXPR', `MAX_EXPR', `MIN_EXPR'. + + The expansion of this macro is responsible for checking for + overflow. If overflow happens, the macro expansion should + execute the statement `return 0;', which indicates the inability + to perform the arithmetic operation requested. + +`REAL_VALUE_NEGATE (X)' + A macro for a C expression which returns the negative of the + floating point value X. Both X and the value of the expression + have type `REAL_VALUE_TYPE' and are in the target machine's + floating point representation. + + There is no way for this macro to report overflow, since + overflow can't happen in the negation operation. + +`REAL_VALUE_TO_INT (LOW, HIGH, X)' + A macro for a C expression which converts a floating point value + X into a double-precision integer which is then stored into LOW + and HIGH, two variables of type INT. + +`REAL_VALUE_FROM_INT (X, LOW, HIGH)' + A macro for a C expression which converts a double-precision + integer found in LOW and HIGH, two variables of type INT, into a + floating point value which is then stored into X. + + +File: gcc.info, Node: Misc, Next: Assembler Format, Prev: Cross-compilation, Up: Machine Macros + +Miscellaneous Parameters +======================== + +`CASE_VECTOR_MODE' + An alias for a machine mode name. This is the machine mode that + elements of a jump-table should have. + +`CASE_VECTOR_PC_RELATIVE' + Define this macro if jump-tables should contain relative + addresses. + +`CASE_DROPS_THROUGH' + Define this if control falls through a `case' insn when the + index value is out of range. This means the specified + default-label is actually ignored by the `case' insn proper. + +`IMPLICIT_FIX_EXPR' + An alias for a tree code that should be used by default for + conversion of floating point values to fixed point. Normally, + `FIX_ROUND_EXPR' is used. + +`FIXUNS_TRUNC_LIKE_FIX_TRUNC' + Define this macro if the same instructions that convert a + floating point number to a signed fixed point number also + convert validly to an unsigned one. + +`EASY_DIV_EXPR' + An alias for a tree code that is the easiest kind of division to + compile code for in the general case. It may be + `TRUNC_DIV_EXPR', `FLOOR_DIV_EXPR', `CEIL_DIV_EXPR' or + `ROUND_DIV_EXPR'. These four division operators differ in how + they round the result to an integer. `EASY_DIV_EXPR' is used + when it is permissible to use any of those kinds of division and + the choice should be made on the basis of efficiency. + +`DEFAULT_SIGNED_CHAR' + An expression whose value is 1 or 0, according to whether the + type `char' should be signed or unsigned by default. The user + can always override this default with the options + `-fsigned-char' and `-funsigned-char'. + +`SCCS_DIRECTIVE' + Define this if the preprocessor should ignore `#sccs' directives + and print no error message. + +`HAVE_VPRINTF' + Define this if the library function `vprintf' is available on + your system. + +`MOVE_MAX' + The maximum number of bytes that a single instruction can move + quickly from memory to memory. + +`INT_TYPE_SIZE' + A C expression for the size in bits of the type `int' on the + target machine. If you don't define this, the default is one + word. + +`SHORT_TYPE_SIZE' + A C expression for the size in bits of the type `short' on the + target machine. If you don't define this, the default is half a + word. (If this would be less than one storage unit, it is + rounded up to one unit.) + +`LONG_TYPE_SIZE' + A C expression for the size in bits of the type `long' on the + target machine. If you don't define this, the default is one + word. + +`LONG_LONG_TYPE_SIZE' + A C expression for the size in bits of the type `long long' on + the target machine. If you don't define this, the default is + two words. + +`CHAR_TYPE_SIZE' + A C expression for the size in bits of the type `char' on the + target machine. If you don't define this, the default is one + quarter of a word. (If this would be less than one storage + unit, it is rounded up to one unit.) + +`FLOAT_TYPE_SIZE' + A C expression for the size in bits of the type `float' on the + target machine. If you don't define this, the default is one + word. + +`DOUBLE_TYPE_SIZE' + A C expression for the size in bits of the type `double' on the + target machine. If you don't define this, the default is two + words. + +`LONG_DOUBLE_TYPE_SIZE' + A C expression for the size in bits of the type `long double' on + the target machine. If you don't define this, the default is + two words. + +`SLOW_BYTE_ACCESS' + 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 slow (requires more than one instruction). + +`SLOW_ZERO_EXTEND' + 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'. + +`SHIFT_COUNT_TRUNCATED' + Define this macro if shift instructions ignore all but the + lowest few bits of the shift count. It implies that a + sign-extend or zero-extend instruction for the shift count can + be omitted. + +`TRULY_NOOP_TRUNCATION (OUTPREC, INPREC)' + A C expression which is nonzero if on this machine it is safe to + "convert" an integer of INPREC bits to one of OUTPREC bits + (where OUTPREC is smaller than INPREC) by merely operating on it + as if it had only OUTPREC bits. + + On many machines, this expression can be 1. + +`NO_FUNCTION_CSE' + 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. + +`PROMOTE_PROTOTYPES' + Define this macro if an argument declared as `char' or `short' + in a prototype should actually be passed as an `int'. In + addition to avoiding errors in certain cases of mismatch, it + also makes for better code on certain machines. + +`STORE_FLAG_VALUE' + A C expression for the value stored by a store-flag instruction + (`sCOND') when the condition is true. This is usually 1 or -1; + it is required to be an odd number or a negative number. + + Do not define `STORE_FLAG_VALUE' if the machine has no + store-flag instructions. + +`Pmode' + An alias for the machine mode for pointers. Normally the + definition can be + + #define Pmode SImode + +`FUNCTION_MODE' + An alias for the machine mode used for memory references to + functions being called, in `call' RTL expressions. On most + machines this should be `QImode'. + +`INSN_MACHINE_INFO' + This macro should expand into a C structure type to use for the + machine-dependent info field specified with the optional last + argument in `define_insn' and `define_peephole' patterns. For + example, it might expand into `struct machine_info'; then it + would be up to you to define this structure in the `tm.h' file. + + You do not need to define this macro if you do not write the + optional last argument in any of the patterns in the machine + description. + +`DEFAULT_MACHINE_INFO' + This macro should expand into a C initializer to use to + initialize the machine-dependent info for one insn pattern. It + is used for patterns that do not specify the machine-dependent + info. + + If you do not define this macro, zero is used. + +`CONST_COSTS (X, CODE)' + 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. + + CODE is the expression code--redundant, since it can be obtained + with `GET_CODE (X)'. + +`DOLLARS_IN_IDENTIFIERS' + Define this to be nonzero if the character `$' should be allowed + by default in identifier names. + + +File: gcc.info, Node: Assembler Format, Prev: Misc, Up: Machine Macros + +Output of Assembler Code +======================== + +`ASM_SPEC' + A C string constant that tells the GNU CC driver program options + to pass to the assembler. It can also specify how to translate + options you give to GNU CC into options for GNU CC to pass to + the assembler. See the file `tm-sun3.h' for an example of this. + + Do not define this macro if it does not need to do anything. + +`LINK_SPEC' + A C string constant that tells the GNU CC driver program options + to pass to the linker. It can also specify how to translate + options you give to GNU CC into options for GNU CC to pass to + the linker. + + Do not define this macro if it does not need to do anything. + +`LIB_SPEC' + Another C string constant used much like `LINK_SPEC'. The + difference between the two is that `LIBS_SPEC' is used at the + end of the command given to the linker. + + If this macro is not defined, a default is provided that loads + the standard C library from the usual place. See `gcc.c'. + +`LIBG_SPEC' + Another C string constant used much like `LINK_SPEC'. This + controls whether to link `libg.a' when debugging. Some systems + expect this; others do not have any `libg.a'. + + If this macro is not defined, a default is provided that loads + the `libg.a' provided `-g' is specified. See `gcc.c'. + +`STARTFILE_SPEC' + Another C string constant used much like `LINK_SPEC'. The + difference between the two is that `STARTFILE_SPEC' is used at + the very beginning of the command given to the linker. + + If this macro is not defined, a default is provided that loads + the standard C startup file from the usual place. See `gcc.c'. + +`STANDARD_EXEC_PREFIX' + Define this macro as a C string constant if you wish to override + the standard choice of `/usr/local/lib/gcc-' as the default + prefix to try when searching for the executable files of the + compiler. + + The prefix specified by the `-B' option, if any, is tried before + the default prefix. After the default prefix, if the executable + is not found that way, `/usr/lib/gcc-' is tried next; then the + directories in your search path for shell commands are searched. + +`STANDARD_STARTFILE_PREFIX' + Define this macro as a C string constant if you wish to override + the standard choice of `/usr/local/lib/' as the default prefix + to try when searching for startup files such as `crt0.o'. + + In this search, all the prefixes tried for executable files are + tried first. Then comes the default startfile prefix specified + by this macro, followed by the prefixes `/lib/' and `/usr/lib/' + as last resorts. + +`ASM_FILE_START (STREAM)' + A C expression which outputs to the stdio stream STREAM some + appropriate text to go at the start of an assembler file. + + Normally this macro is defined to output a line containing + `#NO_APP', which is a comment that has no effect on most + assemblers but tells the GNU assembler that it can save time by + not checking for certain assembler constructs. + + On systems that use SDB, it is necessary to output certain + commands; see `tm-attasm.h'. + +`ASM_FILE_END (STREAM)' + A C expression which outputs to the stdio stream STREAM some + appropriate text to go at the end of an assembler file. + + If this macro is not defined, the default is to output nothing + special at the end of the file. Most systems don't require any + definition. + + On systems that use SDB, it is necessary to output certain + commands; see `tm-attasm.h'. + +`ASM_IDENTIFY_GCC (FILE)' + A C statement to output assembler commands which will identify + the object file as having been compiled with GNU CC (or another + GNU compiler). + + If you don't define this macro, the string `gcc_compiled.:' is + output. This string is calculated to define a symbol which, on + BSD systems, will never be defined for any other reason. GDB + checks for the presence of this symbol when reading the symbol + table of an executable. + + On non-BSD systems, you must arrange communication with GDB in + some other fashion. If GDB is not used on your system, you can + define this macro with an empty body. + +`ASM_APP_ON' + A C string constant for text to be output before each `asm' + statement or group of consecutive ones. Normally this is + `"#APP"', which is a comment that has no effect on most + assemblers but tells the GNU assembler that it must check the + lines that follow for all valid assembler constructs. + +`ASM_APP_OFF' + A C string constant for text to be output after each `asm' + statement or group of consecutive ones. Normally this is + `"#NO_APP"', which tells the GNU assembler to resume making the + time-saving assumptions that are valid for ordinary compiler + output. + +`TEXT_SECTION_ASM_OP' + A C string constant for the assembler operation that should + precede instructions and read-only data. Normally `".text"' is + right. + +`DATA_SECTION_ASM_OP' + A C string constant for the assembler operation to identify the + following data as writable initialized data. Normally `".data"' + is right. + +`EXTRA_SECTIONS' + A list of names for sections other than the standard two, which + are `in_text' and `in_data'. You need not define this macro on + a system with no other sections (that GCC needs to use). + +`EXTRA_SECTION_FUNCTIONS' + One or more functions to be defined in `varasm.c'. These + functions should do jobs analogous to those of `text_section' + and `data_section', for your additional sections. Do not define + this macro if you do not define `EXTRA_SECTIONS'. + +`SELECT_SECTION (EXP)' + A C statement or statements to switch to the appropriate section + for output of EXP. You can assume that EXP is either a + `VAR_DECL' node or a constant of some sort. Select the section + by calling `text_section' or one of the alternatives for other + sections. + + Do not define this macro if you use only the standard two + sections and put all read-only variables and constants in the + text section. + +`SELECT_RTX_SECTION (MODE, RTX)' + A C statement or statements to switch to the appropriate section + for output of RTX in mode MODE. You can assume that RTX is some + kind of constant in RTL. The argument MODE is redundant except + in the case of a `const_int' rtx. Select the section by calling + `text_section' or one of the alternatives for other sections. + + Do not define this macro if you use only the standard two + sections and put all constants in the text section. + +`REGISTER_NAMES' + A C initializer containing the assembler's names for the machine + registers, each one as a C string constant. This is what + translates register numbers in the compiler into assembler + language. + +`DBX_REGISTER_NUMBER (REGNO)' + A C expression that returns the DBX register number for the + compiler register number REGNO. In simple cases, the value of + this expression may be REGNO itself. But sometimes there are + some registers that the compiler knows about and DBX does not, + or vice versa. In such cases, some register may need to have + one number in the compiler and another for DBX. + +`DBX_DEBUGGING_INFO' + Define this macro if GNU CC should produce debugging output for + DBX in response to the `-g' option. + +`SDB_DEBUGGING_INFO' + Define this macro if GNU CC should produce debugging output for + SDB in response to the `-g' option. + +`PUT_SDB_OP' + Define these macros to override the assembler syntax for the + special SDB assembler directives. See `sdbout.c' for a list of + these macros and their arguments. If the standard syntax is + used, you need not define them yourself. + +`SDB_GENERATE_FAKE' + Define this macro to override the usual method of constructing a + dummy name for anonymous structure and union types. See + `sdbout.c' for more information. + +`DBX_NO_XREFS' + Define this macro if DBX on your system does not support the + construct `xsTAGNAME'. On some systems, this construct is used + to describe a forward reference to a structure named TAGNAME. + On other systems, this construct is not supported at all. + +`DBX_CONTIN_LENGTH' + A symbol name in DBX-format debugging information is normally + continued (split into two separate `.stabs' directives) when it + exceeds a certain length (by default, 80 characters). On some + operating systems, DBX requires this splitting; on others, + splitting must not be done. You can inhibit splitting by + defining this macro with the value zero. You can override the + default splitting-length by defining this macro as an expression + for the length you desire. + +`DBX_CONTIN_CHAR' + Normally continuation is indicated by adding a `\' character to + the end of a `.stabs' string when a continuation follows. To + use a different character instead, define this macro as a + character constant for the character you want to use. Do not + define this macro if backslash is correct for your system. + +`DBX_STATIC_STAB_DATA_SECTION' + Define this macro if it is necessary to go to the data section + before outputting the `.stabs' pseudo-op for a non-global static + variable. + +`ASM_OUTPUT_LABEL (STREAM, NAME)' + A C statement (sans semicolon) to output to the stdio stream + STREAM the assembler definition of a label named NAME. Use the + expression `assemble_name (STREAM, NAME)' to output the name + itself; before and after that, output the additional assembler + syntax for defining the name, and a newline. + +`ASM_DECLARE_FUNCTION_NAME (STREAM, NAME, DECL)' + A C statement (sans semicolon) to output to the stdio stream + STREAM any text necessary for declaring the name NAME of a + function which is being defined. This macro is responsible for + outputting the label definition (perhaps using + `ASM_OUTPUT_LABEL'). The argument DECL is the `FUNCTION_DECL' + tree node representing the function. + + If this macro is not defined, then the function name is defined + in the usual manner as a label (by means of `ASM_OUTPUT_LABEL'). + +`ASM_GLOBALIZE_LABEL (STREAM, NAME)' + A C statement (sans semicolon) to output to the stdio stream + STREAM some commands that will make the label NAME global; that + is, available for reference from other files. Use the + expression `assemble_name (STREAM, NAME)' to output the name + itself; before and after that, output the additional assembler + syntax for making that name global, and a newline. + +`ASM_OUTPUT_EXTERNAL (STREAM, DECL, NAME)' + A C statement (sans semicolon) to output to the stdio stream + STREAM any text necessary for declaring the name of an external + symbol named NAME which is referenced in this compilation but + not defined. The value of DECL is the tree node for the + declaration. + + This macro need not be defined if it does not need to output + anything. The GNU assembler and most Unix assemblers don't + require anything. + +`ASM_OUTPUT_LABELREF (STREAM, NAME)' + A C statement to output to the stdio stream STREAM a reference + in assembler syntax to a label named NAME. The character `_' + should be added to the front of the name, if that is customary + on your operating system, as it is in most Berkeley Unix + systems. This macro is used in `assemble_name'. + +`ASM_GENERATE_INTERNAL_LABEL (STRING, PREFIX, NUM)' + A C statement to store into the string STRING a label whose name + is made from the string PREFIX and the number NUM. + + This string, when output subsequently by `ASM_OUTPUT_LABELREF', + should produce the same output that `ASM_OUTPUT_INTERNAL_LABEL' + would produce with the same PREFIX and NUM. + +`ASM_OUTPUT_INTERNAL_LABEL (STREAM, PREFIX, NUM)' + A C statement to output to the stdio stream STREAM a label whose + name is made from the string PREFIX and the number NUM. These + labels are used for internal purposes, and there is no reason + for them to appear in the symbol table of the object file. On + many systems, the letter `L' at the beginning of a label has + this effect. The usual definition of this macro is as follows: + + fprintf (STREAM, "L%s%d:\n", PREFIX, NUM) + +`ASM_OUTPUT_CASE_LABEL (STREAM, PREFIX, NUM, TABLE)' + Define this if the label before a jump-table needs to be output + specially. The first three arguments are the same as for + `ASM_OUTPUT_INTERNAL_LABEL'; the fourth argument is the + jump-table which follows (a `jump_insn' containing an `addr_vec' + or `addr_diff_vec'). + + This feature is used on system V to output a `swbeg' statement + for the table. + + If this macro is not defined, these labels are output with + `ASM_OUTPUT_INTERNAL_LABEL'. + +`ASM_OUTPUT_CASE_END (STREAM, NUM, TABLE)' + Define this if something special must be output at the end of a + jump-table. The definition should be a C statement to be + executed after the assembler code for the table is written. It + should write the appropriate code to stdio stream STREAM. The + argument TABLE is the jump-table insn, and NUM is the + label-number of the preceding label. + + If this macro is not defined, nothing special is output at the + end of the jump-table. + +`ASM_OUTPUT_ALIGN_CODE (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. + + 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. + +`ASM_FORMAT_PRIVATE_NAME (OUTVAR, NAME, NUMBER)' + A C expression to assign to OUTVAR (which is a variable of type + `char *') a newly allocated string made from the string NAME and + the number NUMBER, with some suitable punctuation added. Use + `alloca' to get space for the string. + + This string will be used as the argument to + `ASM_OUTPUT_LABELREF' to produce an assembler label for an + internal static variable whose name is NAME. Therefore, the + string must be such as to result in valid assembler code. The + argument NUMBER is different each time this macro is executed; + it prevents conflicts between similarly-named internal static + variables in different scopes. + + Ideally this string should not be a valid C identifier, to + prevent any conflict with the user's own symbols. Most + assemblers allow periods or percent signs in assembler symbols; + putting at least one of these between the name and the number + will suffice. + +`ASM_OUTPUT_REG_PUSH (STREAM, REGNO)' + A C expression to output to STREAM some assembler code which + will push hard register number REGNO onto the stack. The code + need not be optimal, since this macro is used only when profiling. + +`ASM_OUTPUT_REG_POP (STREAM, REGNO)' + A C expression to output to STREAM some assembler code which + will pop hard register number REGNO off of the stack. The code + need not be optimal, since this macro is used only when profiling. + +`ASM_OUTPUT_ADDR_DIFF_ELT (STREAM, VALUE, 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 STREAM an assembler pseudo-instruction to generate a + difference between two labels. VALUE and REL are the numbers of + two internal labels. The definitions of these labels are output + using `ASM_OUTPUT_INTERNAL_LABEL', and they must be printed in + the same way here. For example, + + fprintf (STREAM, "\t.word L%d-L%d\n", + VALUE, REL) + +`ASM_OUTPUT_ADDR_VEC_ELT (STREAM, VALUE)' + This macro should be provided on machines where the addresses in + a dispatch table are absolute. + + The definition should be a C statement to output to the stdio + stream STREAM an assembler pseudo-instruction to generate a + reference to a label. VALUE is the number of an internal label + whose definition is output using `ASM_OUTPUT_INTERNAL_LABEL'. + For example, + + fprintf (STREAM, "\t.word L%d\n", VALUE) + +`ASM_OUTPUT_DOUBLE (STREAM, VALUE)' + A C statement to output to the stdio stream STREAM an assembler + instruction to assemble a `double' constant whose value is + VALUE. VALUE will be a C expression of type `double'. + +`ASM_OUTPUT_FLOAT (STREAM, VALUE)' + A C statement to output to the stdio stream STREAM an assembler + instruction to assemble a `float' constant whose value is VALUE. + vALUE will be a C expression of type `float'. + +`ASM_OUTPUT_INT (STREAM, EXP)' +`ASM_OUTPUT_SHORT (STREAM, EXP)' +`ASM_OUTPUT_CHAR (STREAM, EXP)' + A C statement to output to the stdio stream STREAM an assembler + instruction to assemble a `int', `short' or `char' constant + whose value is VALUE. The argument EXP will be an RTL + expression which represents a constant value. Use + `output_addr_const (STREAM, EXP)' to output this value as an + assembler expression. + +`ASM_OUTPUT_DOUBLE_INT (STREAM, EXP)' + A C statement to output to the stdio stream STREAM an assembler + instruction to assemble a `long long' constant whose value is + EXP. The argument EXP will be an RTL expression which + represents a constant value. It may be a `const_double' RTX, or + it may be an ordinary single-precision constant. In the latter + case, you should zero-extend it. + +`ASM_OUTPUT_BYTE (STREAM, VALUE)' + A C statement to output to the stdio stream STREAM an assembler + instruction to assemble a single byte containing the number VALUE. + +`ASM_OUTPUT_ASCII (STREAM, PTR, LEN)' + A C statement to output to the stdio stream STREAM an assembler + instruction to assemble a string constant containing the LEN + bytes at PTR. PTR will be a C expression of type `char *' and + LEN a C expression of type `int'. + + If the assembler has a `.ascii' pseudo-op as found in the + Berkeley Unix assembler, do not define the macro + `ASM_OUTPUT_ASCII'. + +`ASM_OUTPUT_SKIP (STREAM, NBYTES)' + A C statement to output to the stdio stream STREAM an assembler + instruction to advance the location counter by NBYTES bytes. + NBYTES will be a C expression of type `int'. + +`ASM_OUTPUT_ALIGN (STREAM, POWER)' + A C statement to output to the stdio stream STREAM an assembler + instruction to advance the location counter to a multiple of 2 + to the POWER bytes. POWER will be a C expression of type `int'. + +`ASM_OUTPUT_COMMON (STREAM, NAME, SIZE, ROUNDED)' + A C statement (sans semicolon) to output to the stdio stream + STREAM the assembler definition of a common-label named NAME + whose size is SIZE bytes. The variable ROUNDED is the size + rounded up to whatever alignment the caller wants. + + Use the expression `assemble_name (STREAM, 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. + +`ASM_OUTPUT_LOCAL (STREAM, NAME, SIZE, ROUNDED)' + A C statement (sans semicolon) to output to the stdio stream + STREAM the assembler definition of a local-common-label named + NAME whose size is SIZE bytes. The variable ROUNDED is the size + rounded up to whatever alignment the caller wants. + + Use the expression `assemble_name (STREAM, 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 static variables are output. + +`ASM_OUTPUT_SOURCE_FILENAME (STREAM, NAME)' + A C statment to output DBX or SDB debugging information which + indicates that filename NAME is the current source file to the + stdio stream STREAM. + + This macro need not be defined if the standard form of debugging + information for the debugger in use is appropriate. + +`ASM_OUTPUT_SOURCE_LINE (STREAM, LINE)' + A C statment to output DBX or SDB debugging information before + code for line number LINE of the current source file to the + stdio stream STREAM. + + This macro need not be defined if the standard form of debugging + information for the debugger in use is appropriate. + +`ASM_OUTPUT_IDENT (STREAM, STRING)' + A C statement to output something to the assembler file to + handle a `#ident' directive containing the text STRING. If this + macro is not defined, nothing is output for a `#ident' directive. + +`TARGET_BELL' + A C constant expression for the integer value for escape + sequence `\a'. + +`TARGET_BS' +`TARGET_TAB' +`TARGET_NEWLINE' + C constant expressions for the integer values for escape + sequences `\b', `\t' and `\n'. + +`TARGET_VT' +`TARGET_FF' +`TARGET_CR' + C constant expressions for the integer values for escape + sequences `\v', `\f' and `\r'. + +`ASM_OUTPUT_OPCODE (STREAM, PTR)' + Define this macro if you are using an unusual assembler that + requires different names for the machine instructions. + + The definition is a C statement or statements which output an + assembler instruction opcode to the stdio stream STREAM. The + macro-operand PTR is a variable of type `char *' which points to + the opcode name in its "internal" form--the form that is written + in the machine description. The definition should output the + opcode name to STREAM, performing any translation you desire, + and increment the variable PTR to point at the end of the opcode + so that it will not be output twice. + + In fact, your macro definition may process less than the entire + opcode name, or more than the opcode name; but if you want to + process text that includes `%'-sequences to substitute operands, + you must take care of the substitution yourself. Just be sure + to increment PTR over whatever text should not be output normally. + + If you need to look at the operand values, they can be found as + the elements of `recog_operand'. + + If the macro definition does nothing, the instruction is output + in the usual way. + +`FINAL_PRESCAN_INSN (INSN, OPVEC, NOPERANDS)' + If defined, a C statement to be executed just prior to the + output of assembler code for INSN, to modify the extracted + operands so they will be output differently. + + Here the argument OPVEC is the vector containing the operands + extracted from INSN, and NOPERANDS is the number of elements of + the vector which contain meaningful data for this insn. The + contents of this vector are what will be used to convert the + insn template into assembler code, so you can change the + assembler output by changing the contents of the vector. + + This macro is useful when various assembler syntaxes share a + single file of instruction patterns; by defining this macro + differently, you can cause a large class of instructions to be + output differently (such as with rearranged operands). + Naturally, variations in assembler syntax affecting individual + insn patterns ought to be handled by writing conditional output + routines in those patterns. + + If this macro is not defined, it is equivalent to a null + statement. + +`PRINT_OPERAND (STREAM, X, CODE)' + A C compound statement to output to stdio stream STREAM the + assembler syntax for an instruction operand X. X is an RTL + expression. + + CODE is a value that can be used to specify one of several ways + of printing the operand. It is used when identical operands + must be printed differently depending on the context. CODE + comes from the `%' specification that was used to request + printing of the operand. If the specification was just `%DIGIT' + then CODE is 0; if the specification was `%LTR DIGIT' then CODE + is the ASCII code for LTR. + + If X is a register, this macro should print the register's name. + The names can be found in an array `reg_names' whose type is + `char *[]'. `reg_names' is initialized from `REGISTER_NAMES'. + + When the machine description has a specification `%PUNCT' (a `%' + followed by a punctuation character), this macro is called with + a null pointer for X and the punctuation character for CODE. + +`PRINT_OPERAND_PUNCT_VALID_P (CODE)' + A C expression which evaluates to true if CODE is a valid + punctuation character for use in the `PRINT_OPERAND' macro. If + `PRINT_OPERAND_PUNCT_VALID_P' is not defined, it means that no + punctuation characters (except for the standard one, `%') are + used in this way. + +`PRINT_OPERAND_ADDRESS (STREAM, X)' + A C compound statement to output to stdio stream STREAM the + assembler syntax for an instruction operand that is a memory + reference whose address is X. X is an RTL expression. + +`ASM_OPEN_PAREN' +`ASM_CLOSE_PAREN' + These macros are defined as C string constant, describing the + syntax in the assembler for grouping arithmetic expressions. + The following definitions are correct for most assemblers: + + #define ASM_OPEN_PAREN "(" + #define ASM_CLOSE_PAREN ")" + + \ No newline at end of file diff --git a/gcc-1.40/gcc.info-11 b/gcc-1.40/gcc.info-11 new file mode 100644 index 0000000..1e418de --- /dev/null +++ b/gcc-1.40/gcc.info-11 @@ -0,0 +1,74 @@ +Info file gcc.info, produced by Makeinfo, -*- Text -*- from input +file gcc.texinfo. + + This file documents the use and the internals of the GNU compiler. + + Copyright (C) 1988, 1989, 1990 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. + + 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" and "Protect +Your Freedom--Fight `Look And Feel'" 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" and "Protect Your Freedom--Fight `Look And Feel'" and this +permission notice may be included in translations approved by the +Free Software Foundation instead of in the original English. + + +File: gcc.info, Node: Config, Prev: Machine Macros, Up: Top + +The Configuration File +********************** + + The configuration file `xm-MACHINE.h' contains macro definitions +that describe the machine and system on which the compiler is running. +Most of the values in it are actually the same on all machines that +GNU CC runs on, so large parts of all configuration files are +identical. But there are some macros that vary: + +`FAILURE_EXIT_CODE' + A C expression for the status code to be returned when the + compiler exits after serious errors. + +`SUCCESS_EXIT_CODE' + A C expression for the status code to be returned when the + compiler exits without serious errors. + +`USE_C_ALLOCA' + Define this macro to indicate that the compiler is running with + the `alloca' implemented in C. This version of `alloca' can be + found in the file `alloca.c'; to use it, you must also alter the + `Makefile' variable `ALLOCA'. + + This macro, unlike most, describes the machine that the compiler + is running on, rather than the one the compiler is compiling for. + Therefore, it should be set in the `xm-MACHINE.h' file rather + than in the `tm-MACHINE.h' file. + + If you do define this macro, you should probably do it as follows: + + #ifndef __GNUC__ + #define USE_C_ALLOCA + #else + #define alloca __builtin_alloca + #endif + + so that when the compiler is compiled with GNU CC it uses the + more efficient built-in `alloca' function. + + In addition, configuration files for system V define `bcopy', +`bzero' and `bcmp' as aliases. Some files define `alloca' as a macro +when compiled with GNU CC, in order to take advantage of the benefit +of GNU CC's built-in `alloca'. + + diff --git a/gcc-1.40/gcc.info-2 b/gcc-1.40/gcc.info-2 new file mode 100644 index 0000000..6ca6971 --- /dev/null +++ b/gcc-1.40/gcc.info-2 @@ -0,0 +1,913 @@ +Info file gcc.info, produced by Makeinfo, -*- Text -*- from input +file gcc.texinfo. + + This file documents the use and the internals of the GNU compiler. + + Copyright (C) 1988, 1989, 1990 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. + + 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" and "Protect +Your Freedom--Fight `Look And Feel'" 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" and "Protect Your Freedom--Fight `Look And Feel'" and this +permission notice may be included in translations approved by the +Free Software Foundation instead of in the original English. + + +File: gcc.info, Node: Options, Next: Installation, Prev: Boycott, Up: Top + +GNU CC Command Options +********************** + + The GNU C compiler uses a command syntax much like the Unix C +compiler. The `gcc' program accepts options and file names as +operands. Multiple single-letter options may *not* be grouped: `-dr' +is very different from `-d -r'. + + When you invoke GNU CC, it normally does preprocessing, +compilation, assembly and linking. File names which end in `.c' are +taken as C source to be preprocessed and compiled; file names ending +in `.i' are taken as preprocessor output to be compiled; compiler +output files plus any input files with names ending in `.s' are +assembled; then the resulting object files, plus any other input +files, are linked together to produce an executable. + + Command options allow you to stop this process at an intermediate +stage. For example, the `-c' option says not to run the linker. +Then the output consists of object files output by the assembler. + + Other command options are passed on to one stage of processing. +Some options control the preprocessor and others the compiler itself. +Yet other options control the assembler and linker; these are not +documented here, but you rarely need to use any of them. + + Here are the options to control the overall compilation process, +including those that say whether to link, whether to assemble, and so +on. + +`-o FILE' + Place output in file FILE. This applies regardless to whatever + sort of output is being produced, whether it be an executable + file, an object file, an assembler file or preprocessed C code. + + If `-o' is not specified, the default is to put an executable + file in `a.out', the object file `SOURCE.c' in `SOURCE.o', an + assembler file in `SOURCE.s', and preprocessed C on standard + output. + +`-c' + Compile or assemble the source files, but do not link. Produce + object files with names made by replacing `.c' or `.s' with `.o' + at the end of the input file names. Do nothing at all for + object files specified as input. + +`-S' + Compile into assembler code but do not assemble. The assembler + output file name is made by replacing `.c' with `.s' at the end + of the input file name. Do nothing at all for assembler source + files or object files specified as input. + +`-E' + Run only the C preprocessor. Preprocess all the C source files + specified and output the results to standard output. + +`-v' + Compiler driver program prints the commands it executes as it + runs the preprocessor, compiler proper, assembler and linker. + Some of these are directed to print their own version numbers. + +`-pipe' + Use pipes rather than temporary files for communication between + the various stages of compilation. This fails to work on some + systems where the assembler is unable to read from a pipe; but + the GNU assembler has no trouble. + +`-BPREFIX' + Compiler driver program tries PREFIX as a prefix for each + program it tries to run. These programs are `cpp', `cc1', `as' + and `ld'. + + For each subprogram to be run, the compiler driver first tries + the `-B' prefix, if any. If that name is not found, or if `-B' + was not specified, the driver tries two standard prefixes, which + are `/usr/lib/gcc-' and `/usr/local/lib/gcc-'. If neither of + those results in a file name that is found, the unmodified + program name is searched for using the directories specified in + your `PATH' environment variable. + + The run-time support file `gnulib' is also searched for using + the `-B' prefix, if needed. If it is not found there, the two + standard prefixes above are tried, and that is all. The file is + left out of the link if it is not found by those means. Most of + the time, on most machines, you can do without it. + + You can get a similar result from the environment variable; + `GCC_EXEC_PREFIX' if it is defined, its value is used as a + prefix in the same way. If both the `-B' option and the + `GCC_EXEC_PREFIX' variable are present, the `-B' option is used + first and the environment variable value second. + +`-bPREFIX' + The argument PREFIX is used as a second prefix for the compiler + executables and libraries. This prefix is optional: the + compiler tries each file first with it, then without it. This + prefix follows the prefix specified with `-B' or the default + prefixes. + + Thus, `-bvax- -Bcc/' in the presence of environment variable + `GCC_EXEC_PREFIX' with definition `/u/foo/' causes GNU CC to try + the following file names for the preprocessor executable: + + cc/vax-cpp + cc/cpp + /u/foo/vax-cpp + /u/foo/cpp + /usr/local/lib/gcc-vax-cpp + /usr/local/lib/gcc-cpp + /usr/lib/gcc-vax-cpp + /usr/lib/gcc-cpp + + These options control the details of C compilation itself. + +`-ansi' + Support all ANSI standard C programs. + + This turns off certain features of GNU C that are incompatible + with ANSI C, such as the `asm', `inline' and `typeof' keywords, + and predefined macros such as `unix' and `vax' that identify the + type of system you are using. It also enables the undesirable + and rarely used ANSI trigraph feature. + + The alternate keywords `__asm__', `__inline__' and `__typeof__' + continue to work despite `-ansi'. You would not want to use + them in an ANSI C program, of course, but it useful to put them + in header files that might be included in compilations done with + `-ansi'. Alternate predefined macros such as `__unix__' and + `__vax__' are also available, with or without `-ansi'. + + The `-ansi' option does not cause non-ANSI programs to be + rejected gratuitously. For that, `-pedantic' is required in + addition to `-ansi'. + + The macro `__STRICT_ANSI__' is predefined when the `-ansi' + option is used. Some header files may notice this macro and + refrain from declaring certain functions or defining certain + macros that the ANSI standard doesn't call for; this is to avoid + interfering with any programs that might use these names for + other things. + +`-traditional' + Attempt to support some aspects of traditional C compilers. + Specifically: + + * All `extern' declarations take effect globally even if they + are written inside of a function definition. This includes + implicit declarations of functions. + + * The keywords `typeof', `inline', `signed', `const' and + `volatile' are not recognized. (You can still use the + alternative keywords such as `__typeof__', `__inline__', + and so on.) + + * Comparisons between pointers and integers are always allowed. + + * Integer types `unsigned short' and `unsigned char' promote + to `unsigned int'. + + * Out-of-range floating point literals are not an error. + + * String "constants" are not necessarily constant; they are + stored in writable space, and identical looking constants + are allocated separately. + + * All automatic variables not declared `register' are + preserved by `longjmp'. Ordinarily, GNU C follows ANSI C: + automatic variables not declared `volatile' may be clobbered. + + * In the preprocessor, comments convert to nothing at all, + rather than to a space. This allows traditional token + concatenation. + + * 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. + + * The predefined macro `__STDC__' is not defined when you use + `-traditional', but `__GNUC__' is (since the GNU extensions + which `__GNUC__' indicates are not affected by + `-traditional'). If you need to write header files that + work differently depending on whether `-traditional' 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. + +`-O' + Optimize. Optimizing compilation takes somewhat more time, and + a lot more memory for a large function. + + Without `-O', the compiler's goal is to reduce the cost of + compilation and to make debugging produce the expected results. + Statements are independent: if you stop the program with a + breakpoint between statements, you can then assign a new value + to any variable or change the program counter to any other + statement in the function and get exactly the results you would + expect from the source code. + + Without `-O', only variables declared `register' are allocated + in registers. The resulting compiled code is a little worse + than produced by PCC without `-O'. + + With `-O', the compiler tries to reduce code size and execution + time. + + Some of the `-f' options described below turn specific kinds of + optimization on or off. + +`-g' + Produce debugging information in the operating system's native + format (for DBX or SDB). GDB also can work with this debugging + information. + + Unlike most other C compilers, GNU CC allows you to use `-g' + with `-O'. 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. + +`-gg' + Produce debugging information in the old GDB format. This is + obsolete. + +`-w' + Inhibit all warning messages. + +`-W' + Print extra warning messages for these events: + + * 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 `-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 that is declared `volatile', or whose address is + taken, or whose size is other than 1, 2, 4 or 8 bytes. + Also, they do not occur for structures, unions or arrays, + even when they are in registers. + + Note that there may be no warning about a variable that is + used only to compute a value that itself is never used, + because such computations may be deleted by data flow + analysis before the warnings are printed. + + These warnings are made optional because GNU CC 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: + + { + int x; + switch (y) + { + case 1: x = 1; + break; + case 2: x = 4; + break; + case 3: x = 5; + } + foo (x); + } + + If the value of `y' is always 1, 2 or 3, then `x' is always + initialized, but GNU CC doesn't know this. Here is another + common case: + + { + int save_y; + if (change_y) save_y = y, y = new_y; + ... + if (change_y) y = save_y; + } + + This has no bug because `save_y' is used only if it is set. + + Some spurious warnings can be avoided if you declare as + `volatile' all the functions you use that never return. + *Note Function Attributes::. + + * A nonvolatile automatic variable might be changed by a call + to `longjmp'. These warnings as well are possible only in + optimizing compilation. + + The compiler sees only the calls to `setjmp'. It cannot + know where `longjmp' will be called; in fact, a signal + handler could call it at any point in the code. As a + result, you may get a warning even when there is in fact no + problem because `longjmp' cannot in fact be called at the + place which would cause a problem. + + * A function can return either with or without a value. + (Falling off the end of the function body is considered + returning without a value.) For example, this function + would evoke such a warning: + + foo (a) + { + if (a > 0) + return a; + } + + Spurious warnings can occur because GNU CC does not realize + that certain functions (including `abort' and `longjmp') + will never return. + + * An expression-statement contains no side effects. + + In the future, other useful warnings may also be enabled by this + option. + +`-Wimplicit' + Warn whenever a function is implicitly declared. + +`-Wreturn-type' + Warn whenever a function is defined with a return-type that + defaults to `int'. Also warn about any `return' statement with + no return-value in a function whose return-type is not `void'. + +`-Wunused' + Warn whenever a local variable is unused aside from its + declaration, whenever a function is declared static but never + defined, and whenever a statement computes a result that is + explicitly not used. + +`-Wswitch' + Warn whenever a `switch' statement has an index of enumeral type + and lacks a `case' for one or more of the named codes of that + enumeration. (The presence of a `default' label prevents this + warning.) `case' labels outside the enumeration range also + provoke warnings when this option is used. + +`-Wcomment' + Warn whenever a comment-start sequence `/*' appears in a comment. + +`-Wtrigraphs' + Warn if any trigraphs are encountered (assuming they are enabled). + +`-Wall' + All of the above `-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. + + The other `-W...' options below are not implied by `-Wall' + because certain kinds of useful macros are almost impossible to + write without causing those warnings. + +`-Wshadow' + Warn whenever a local variable shadows another local variable. + +`-Wid-clash-LEN' + Warn whenever two distinct identifiers match in the first LEN + characters. This may help you prepare a program that will + compile with certain obsolete, brain-damaged compilers. + +`-Wpointer-arith' + Warn about anything that depends on the "size of" a function + type or of `void'. GNU C assigns these types a size of 1, for + convenience in calculations with `void *' pointers and pointers + to functions. + +`-Wcast-qual' + Warn whenever a pointer is cast so as to remove a type qualifier + from the target type. For example, warn if a `const char *' is + cast to an ordinary `char *'. + +`-Wwrite-strings' + Give string constants the type `const char[LENGTH]' so that + copying the address of one into a non-`const' `char *' pointer + will get a warning. These warnings will help you find at + compile time code that can try to write into a string constant, + but only if you have been very careful about using `const' in + declarations and prototypes. Otherwise, it will just be a + nuisance; this is why we did not make `-Wall' request these + warnings. + +`-p' + Generate extra code to write profile information suitable for + the analysis program `prof'. + +`-pg' + Generate extra code to write profile information suitable for + the analysis program `gprof'. + +`-a' + Generate extra code to write profile information for basic + blocks, which will record the number of times each basic block + is executed. This data could be analyzed by a program like + `tcov'. Note, however, that the format of the data is not what + `tcov' expects. Eventually GNU `gprof' should be extended to + process this data. + +`-lLIBRARY' + Search a standard list of directories for a library named + LIBRARY, which is actually a file named `libLIBRARY.a'. The + linker uses this file as if it had been specified precisely by + name. + + The directories searched include several standard system + directories plus any that you specify with `-L'. + + Normally the files found this way are library files--archive + files whose members are object files. The linker handles an + archive file by scanning through it for members which define + symbols that have so far been referenced but not defined. But + if the file that is found is an ordinary object file, it is + linked in the usual fashion. The only difference between using + an `-l' option and specifying a file name is that `-l' searches + several directories. + +`-LDIR' + Add directory DIR to the list of directories to be searched for + `-l'. + +`-nostdlib' + Don't use the standard system libraries and startup files when + linking. Only the files you specify will be passed to the linker. + +`-mMACHINESPEC' + Machine-dependent option specifying something about the type of + target machine. These options are defined by the macro + `TARGET_SWITCHES' in the machine description. The default for + the options is also defined by that macro, which enables you to + change the defaults. + + These are the `-m' options defined in the 68000 machine + description: + + `-m68020' + `-mc68020' + Generate output for a 68020 (rather than a 68000). This is + the default if you use the unmodified sources. + + `-m68000' + `-mc68000' + Generate output for a 68000 (rather than a 68020). + + `-m68881' + Generate output containing 68881 instructions for floating + point. This is the default if you use the unmodified + sources. + + `-mfpa' + Generate output containing Sun FPA instructions for + floating point. + + `-msoft-float' + Generate output containing library calls for floating point. + + `-mshort' + Consider type `int' to be 16 bits wide, like `short int'. + + `-mnobitfield' + Do not use the bit-field instructions. `-m68000' implies + `-mnobitfield'. + + `-mbitfield' + Do use the bit-field instructions. `-m68020' implies + `-mbitfield'. This is the default if you use the + unmodified sources. + + `-mrtd' + Use a different function-calling convention, in which + functions that take a fixed number of arguments return with + the `rtd' instruction, which pops their arguments while + returning. This saves one instruction in the caller since + there is no need to pop the arguments there. + + This calling convention is incompatible with the one + normally used on Unix, so you cannot use it if you need to + call libraries compiled with the Unix compiler. + + Also, you must provide function prototypes for all + functions that take variable numbers of arguments + (including `printf'); otherwise incorrect code will be + generated for calls to those functions. + + In addition, seriously incorrect code will result if you + call a function with too many arguments. (Normally, extra + arguments are harmlessly ignored.) + + The `rtd' instruction is supported by the 68010 and 68020 + processors, but not by the 68000. + + These `-m' options are defined in the Vax machine description: + + `-munix' + Do not output certain jump instructions (`aobleq' and so + on) that the Unix assembler for the Vax cannot handle + across long ranges. + + `-mgnu' + Do output those jump instructions, on the assumption that + you will assemble with the GNU assembler. + + `-mg' + Output code for g-format floating point numbers instead of + d-format. + + These `-m' switches are supported on the Sparc: + + `-mfpu' + Generate output containing floating point instructions. + This is the default if you use the unmodified sources. + + `-mno-epilogue' + Generate separate return instructions for `return' + statements. This has both advantages and disadvantages; I + don't recall what they are. + + These `-m' options are defined in the Convex machine description: + + `-mc1' + Generate output for a C1. This is the default when the + compiler is configured for a C1. + + `-mc2' + Generate output for a C2. This is the default when the + compiler is configured for a C2. + + `-margcount' + Generate code which puts an argument count in the word + preceding each argument list. Some nonportable Convex and + Vax programs need this word. (Debuggers don't; this info + is in the symbol table.) + + `-mnoargcount' + Omit the argument count word. This is the default if you + use the unmodified sources. + +`-fFLAG' + Specify machine-independent flags. Most flags have both + positive and negative forms; the negative form of `-ffoo' would + be `-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 `no-' or adding it. + + `-fpcc-struct-return' + Use the same convention for returning `struct' and `union' + values that is used by the usual C compiler on your system. + This convention is less efficient for small structures, and + on many machines it fails to be reentrant; but it has the + advantage of allowing intercallability between GCC-compiled + code and PCC-compiled code. + + `-ffloat-store' + Do not store floating-point variables in registers. This + prevents undesirable excess precision on machines such as + the 68000 where the floating registers (of the 68881) keep + more precision than a `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 `-ffloat-store' for such programs. + + `-fno-asm' + Do not recognize `asm', `inline' or `typeof' as a keyword. + These words may then be used as identifiers. You can use + `__asm__', `__inline__' and `__typeof__' instead. + + `-fno-defer-pop' + Always pop the arguments to each function call as soon as + that function returns. Normally the compiler (when + optimizing) lets arguments accumulate on the stack for + several function calls and pops them all at once. + + `-fstrength-reduce' + Perform the optimizations of loop strength reduction and + elimination of iteration variables. + + `-fcombine-regs' + Allow the combine pass to combine an instruction that + copies one register into another. This might or might not + produce better code when used in addition to `-O'. I am + interested in hearing about the difference this makes. + + `-fforce-mem' + Force memory operands to be copied into registers before + doing arithmetic on them. This may produce better code by + making all memory references potential common + subexpressions. When they are not common subexpressions, + instruction combination should eliminate the separate + register-load. I am interested in hearing about the + difference this makes. + + `-fforce-addr' + Force memory address constants to be copied into registers + before doing arithmetic on them. This may produce better + code just as `-fforce-mem' may. I am interested in hearing + about the difference this makes. + + `-fomit-frame-pointer' + Don't keep the frame pointer in a register for functions + that don't need one. This avoids the instructions to save, + set up and restore frame pointers; it also makes an extra + register available in many functions. *It also makes + debugging impossible.* + + On some machines, such as the Vax, this flag has no effect, + because the standard calling sequence automatically handles + the frame pointer and nothing is saved by pretending it + doesn't exist. The machine-description macro + `FRAME_POINTER_REQUIRED' controls whether a target machine + supports this flag. *Note Registers::. + + `-finline-functions' + Integrate all simple functions into their callers. The + compiler heuristically decides which functions are simple + enough to be worth integrating in this way. + + If all calls to a given function are integrated, and the + function is declared `static', then the function is + normally not output as assembler code in its own right. + + `-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 registers around such calls. Such + allocation is done only when it seems to result in better + code than would otherwise be produced. + + This option is enabled by default on certain machines, + usually those which have no call-preserved registers to use + instead. + + `-fkeep-inline-functions' + Even if all calls to a given function are integrated, and + the function is declared `static', nevertheless output a + separate run-time callable version of the function. + + `-fwritable-strings' + Store string constants in the writable data segment and + don't uniquize them. This is for compatibility with old + programs which assume they can write into string constants. + `-traditional' also has this effect. + + Writing into string constants is a very bad idea; + "constants" should be constant. + + `-fcond-mismatch' + Allow conditional expressions with mismatched types in the + second and third arguments. The value of such an + expression is void. + + `-fno-function-cse' + Do not put function addresses in registers; make each + instruction that calls a constant function contain the + function's address explicitly. + + This option results in less efficient code, but some + strange hacks that alter the assembler output may be + confused by the optimizations performed when this option is + not used. + + `-fvolatile' + Consider all memory references through pointers to be + volatile. + + `-fshared-data' + Requests that the data and non-`const' variables of this + compilation be shared data rather than private data. The + distinction makes sense only on certain operating systems, + where shared data is shared between processes running the + same program, while private data exists in one copy per + process. + + `-funsigned-char' + Let the type `char' be the unsigned, like `unsigned char'. + + Each kind of machine has a default for what `char' should + be. It is either like `unsigned char' by default or like + `signed char' by default. (Actually, at present, the + default is always signed.) + + The type `char' is always a distinct type from either + `signed char' or `unsigned char', even though its behavior + is always just like one of those two. + + Note that this is equivalent to `-fno-signed-char', which + is the negative form of `-fsigned-char'. + + `-fsigned-char' + Let the type `char' be signed, like `signed char'. + + Note that this is equivalent to `-fno-unsigned-char', which + is the negative form of `-funsigned-char'. + + `-fdelayed-branch' + If supported for the target machine, attempt to reorder + instructions to exploit instruction slots available after + delayed branch instructions. + + `-ffixed-REG' + Treat the register named REG as a fixed register; generated + code should never refer to it (except perhaps as a stack + pointer, frame pointer or in some other fixed role). + + REG must be the name of a register. The register names + accepted are machine-specific and are defined in the + `REGISTER_NAMES' macro in the machine description macro file. + + This flag does not have a negative form, because it + specifies a three-way choice. + + `-fcall-used-REG' + Treat the register named REG as an allocatable 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 REG. + + Use of this flag for a register that has a fixed pervasive + role in the machine's execution model, such as the stack + pointer or frame pointer, will produce disastrous results. + + This flag does not have a negative form, because it + specifies a three-way choice. + + `-fcall-saved-REG' + Treat the register named REG as an allocatable 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 REG if they use it. + + Use of this flag for a register that has a fixed pervasive + role in the machine's execution model, such as the stack + pointer or frame pointer, will produce disastrous results. + + A different sort of disaster will result from the use of + this flag for a register in which function values may be + returned. + + This flag does not have a negative form, because it + specifies a three-way choice. + +`-dLETTERS' + Says to make debugging dumps at times specified by LETTERS. + Here are the possible letters: + + `r' + Dump after RTL generation. + + `j' + Dump after first jump optimization. + + `s' + Dump after CSE (including the jump optimization that + sometimes follows CSE). + + `L' + Dump after loop optimization. + + `f' + Dump after flow analysis. + + `c' + Dump after instruction combination. + + `l' + Dump after local register allocation. + + `g' + Dump after global register allocation. + + `d' + Dump after delayed branch scheduling. + + `J' + Dump after last jump optimization. + + `m' + Print statistics on memory usage, at the end of the run. + +`-pedantic' + Issue all the warnings demanded by strict ANSI standard C; + reject all programs that use forbidden extensions. + + Valid ANSI standard C programs should compile properly with or + without this option (though a rare few will require `-ansi'). + However, without this option, certain GNU extensions and + traditional C features are supported as well. With this option, + they are rejected. There is no reason to use this option; it + exists only to satisfy pedants. + + `-pedantic' does not cause warning messages for use of the + alternate keywords whose names begin and end with `__'. *Note + Alternate Keywords::. + +`-static' + On Suns running version 4, this prevents linking with the shared + libraries. (`-g' has the same effect.) + + These options control the C preprocessor, which is run on each C +source file before actual compilation. If you use the `-E' option, +nothing is done except C preprocessing. Some of these options make +sense only together with `-E' because they request preprocessor +output that is not suitable for actual compilation. + +`-C' + Tell the preprocessor not to discard comments. Used with the + `-E' option. + +`-IDIR' + Search directory DIR for include files. + +`-I-' + Any directories specified with `-I' options before the `-I-' + option are searched only for the case of `#include "FILE"'; they + are not searched for `#include '. + + If additional directories are specified with `-I' options after + the `-I-', these directories are searched for all `#include' + directives. (Ordinarily *all* `-I' directories are used this + way.) + + In addition, the `-I-' option inhibits the use of the current + directory (where the current input file came from) as the first + search directory for `#include "FILE"'. There is no way to + override this effect of `-I-'. With `-I.' you can specify + searching the directory which was current when the compiler was + invoked. That is not exactly the same as what the preprocessor + does by default, but it is often satisfactory. + + `-I-' does not inhibit the use of the standard system + directories for header files. Thus, `-I-' and `-nostdinc' are + independent. + +`-i FILE' + Process FILE as input, discarding the resulting output, before + processing the regular input file. Because the output generated + from FILE is discarded, the only effect of `-i FILE' is to make + the macros defined in FILE available for use in the main input. + +`-nostdinc' + Do not search the standard system directories for header files. + Only the directories you have specified with `-I' options (and + the current directory, if appropriate) are searched. + + Between `-nostdinc' and `-I-', you can eliminate all directories + from the search path except those you specify. + +`-M' + Tell the preprocessor to output a rule suitable for `make' + describing the dependencies of each object file. For each + source file, the preprocessor outputs one `make'-rule whose + target is the object file name for that source file and whose + dependencies are all the files `#include'd in it. This rule may + be a single line or may be continued with `\'-newline if it is + long. + + `-M' implies `-E'. + +`-MM' + Like `-M' but the output mentions only the user-header files + included with `#include "FILE"'. System header files included + with `#include ' are omitted. + + `-MM' implies `-E'. + +`-DMACRO' + Define macro MACRO with the string `1' as its definition. + +`-DMACRO=DEFN' + Define macro MACRO as DEFN. + +`-UMACRO' + Undefine macro MACRO. + +`-trigraphs' + Support ANSI C trigraphs. You don't want to know about this + brain-damage. The `-ansi' option also has this effect. + + \ No newline at end of file diff --git a/gcc-1.40/gcc.info-3 b/gcc-1.40/gcc.info-3 new file mode 100644 index 0000000..02c242f --- /dev/null +++ b/gcc-1.40/gcc.info-3 @@ -0,0 +1,1258 @@ +Info file gcc.info, produced by Makeinfo, -*- Text -*- from input +file gcc.texinfo. + + This file documents the use and the internals of the GNU compiler. + + Copyright (C) 1988, 1989, 1990 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. + + 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" and "Protect +Your Freedom--Fight `Look And Feel'" 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" and "Protect Your Freedom--Fight `Look And Feel'" and this +permission notice may be included in translations approved by the +Free Software Foundation instead of in the original English. + + +File: gcc.info, Node: Installation, Next: Trouble, Prev: Options, Up: Top + +Installing GNU CC +***************** + + Here is the procedure for installing GNU CC on a Unix system. + +* Menu: + +* Other Dir:: Compiling in a separate directory (not where the source is). +* Sun Install:: See below for installation on the Sun. +* 3B1 Install:: See below for installation on the 3B1. +* SCO Install:: See below for installation on SCO System V 3.2. (Or ESIX.) +* VMS Install:: See below for installation on VMS. +* HPUX Install:: See below for installation on HPUX. +* Tower Install:: See below for installation on an NCR Tower. + + 1. Edit `Makefile'. If you are using HPUX, or any form of system + V, you must make a few changes described in comments at the + beginning of the file. Genix requires changes also, and so does + the Pyramid. + + 2. On a Sequent system, go to the Berkeley universe. + + 3. Choose configuration files. The easy way to do this is to run + the command file `config.gcc' with a single argument, which + specifies the type of machine (and in some cases which operating + system). + + Here is a list of the possible arguments: + + `vax' + Vaxes running BSD. + + `vms' + Vaxes running VMS. + + `vax-sysv' + Vaxes running system V. + + `i386-sysv' + Intel 386 PCs running system V. + + `i386-sysv-gas' + Intel 386 PCs running system V, using the GNU assembler and + GNU linker. + + `sequent-i386' + Sequent with Intel 386 processors. + + `i386-aix' + Intel 386 PCs or PS/2s running AIX. + + `sun2' + Sun 2 running system version 2 or 3. + + `sun3' + Sun 3 running system version 4, with 68881. Note there we + do not provide a configuration file to use an FPA by + default, because programs that establish signal handlers + for floating point traps inherently cannot work with the FPA. + + `sun3-nfp' + Sun 3 running system version 4, without 68881. + + `sun4' + Sun 4 running system version 4. *Note Incompatibilities::, + for calling convention incompatibilities on the Sun 4 + (sparc). + + `sun2-os4' + Sun 2 running system version 4. + + `sun3-os3' + Sun 3 running system version 2 or 3, with 68881. + + `sun3-nfp-os3' + Sun 3 running system version 2 or 3, without 68881. + + `sun4-os3' + Sun 4 running system version 2 or 3. *Note + Incompatibilities::, for calling convention + incompatibilities on the Sun 4 (sparc). + + `sun386' + Sun 386 ("roadrunner"). + + `alliant' + Alliant FX/8 computer. Note that the standard installed C + compiler in Concentrix 5.0 has a bug which prevent it from + compiling GNU CC correctly. You can patch the compiler bug + as follows: + + cp /bin/pcc ./pcc + adb -w ./pcc - << EOF + 15f6?w 6610 + EOF + + Then you must use the `-ip12' option when compiling GNU CC + with the patched compiler, as shown here: + + make CC="./pcc -ip12" CFLAGS=-w + + Note also that Alliant's version of DBX does not manage to + work with the output from GNU CC. + + `tahoe' + The tahoe computer (running BSD, and using DBX). + + `decstation' + The DEC 3100 Mips machine ("pmax"). Note that GNU CC + cannot generate debugging information in the unusual format + used on the Mips. + + `mips-sysv' + The Mips computer, RS series, with the System V environment + as default. Note that GNU CC cannot generate debugging + information in the unusual format used on the Mips. + + `mips-bsd43' + The Mips computer, RS series, with the BSD 4.3 environment + as default. Note that GNU CC cannot generate debugging + information in the unusual format used on the Mips. + + `mips' + The Mips computer, M series. Note that GNU CC cannot + generate debugging information in the unusual format used + on the Mips. + + `iris' + Another variant of the Mips computer, the Silicon Graphics + Iris 4D. Note that GNU CC cannot generate debugging + information in the unusual format used on the Mips. + + `convex-c1' + Convex C1 computer. With operating system version 9, use + `cc -pcc' as the compilation command when building stage 1 + of GNU CC. + + `convex-c2' + Convex C2 computer. With operating system version 9, use + `cc -pcc' as the compilation command when building stage 1 + of GNU CC. + + `pyramid' + Pyramid computer. + + `hp9k320' + HP 9000 series 300 using HPUX assembler. Note there is no + support in GNU CC for HP's debugger; thus, `-g' is not + available in this configuration. + + `hp9k320-gas' + HP 9000 series 300 using GNU assembler, linker and debugger. + This requires the HP-adapt package, which is available + along with the GNU linker as part of the "binutils" + distribution. This is on the GNU CC distribution tape. + + `hp9k320-old' + HP 9000 series 300 using HPUX assembler, in operating + system versions older than 6.5. Note there is no support + in GNU CC for HP's debugger; thus, `-g' is not available in + this configuration. + + `hp9k320-bsd' + HP 9000 series 300 running BSD. + + `hp9k200-bsd' + HP 9000 series 200 running BSD. Note that the C compiler + that comes with this system cannot compile GNU CC; contact + `law@super.org' to get binaries of GNU CC for + bootstrapping. Additionally, a minor patch is necessary if + you wish to build kernels with GNU CC; contact + `law@super.org' to get a copy of the patch. + + `isi68' + ISI 68000 or 68020 system with a 68881. + + `isi68-nfp' + ISI 68000 or 68020 system without a 68881. + + `news800' + Sony NEWS 68020 system. + + `next' + NeXT system. + + `tower' + NCR Tower 32 system. + + `altos' + Altos 3068. Note that you must use the GNU assembler, + linker and debugger, with COFF-encapsulation. Also, you + must fix a kernel bug. Details in the file `ALTOS-README'. + + `3b1' + AT&T 3b1, a.k.a. 7300 PC. Note that special procedures are + needed to compile GNU CC with this machine's standard C + compiler, due to bugs in that compiler. *Note 3b1 + Install::. You can bootstrap it more easily with previous + versions of GNU CC if you have them. + + `3b1-gas' + AT&T 3b1 using the GNU assembler. + + `sequent-ns32k' + Sequent containing ns32000 processors. + + `encore' + Encore ns32000 system. + + `genix' + National Semiconductor ns32000 system. + + `88000' + Motorola 88000 processor. This port is not finished. + + Here we spell out what files need to be set up: + + * Make a symbolic link named `config.h' to the top-level + config file for the machine you are using (*note + Config::.). This file is responsible for defining + information about the host machine. It includes `tm.h'. + + The file is located in the subdirectory `config'. Its name + should be `xm-MACHINE.h', with these exceptions: + + `xm-vms.h' + for vaxen running VMS. + + `xm-vaxv.h' + for vaxen running system V. + + `xm-i386v.h' + for Intel 80386's running system V. + + `xm-sun386i.h' + for Sun roadrunner running any version of the + operating system. + + `xm-hp9k320.h' + for the HP 9000 series 300. + + `xm-genix.h' + for the ns32000 running Genix + + If your system does not support symbolic links, you might + want to set up `config.h' to contain a `#include' command + which refers to the appropriate file. + + * Make a symbolic link named `tm.h' to the + machine-description macro file for your machine. It should + be in the subdirectory `config' and its name should be + `tm-MACHINE.h'. + + If your system is a 68000, don't use the file `tm-m68k.h' + directly. Instead, use one of these files: + + `tm-sun3.h' + for Sun 3 machines with 68881. + + `tm-sun3-nfp.h' + for Sun 3 machines with no hardware floating point. + + `tm-sun3os3.h' + for Sun 3 machines with 68881, running Sunos version 3. + + `tm-sun3os3nf.h' + for Sun 3 machines with no hardware floating point, + running Sunos version 3. + + `tm-sun2.h' + for Sun 2 machines. + + `tm-3b1.h' + for AT&T 3b1 (aka 7300 Unix PC). + + `tm-isi68.h' + for Integrated Solutions systems. This file assumes + you use the GNU assembler. + + `tm-isi68-nfp.h' + for Integrated Solutions systems without a 68881. + This file assumes you use the GNU assembler. + + `tm-news800.h' + for Sony NEWS systems. + + `tm-hp9k320.h' + for HPUX systems, if you are using GNU CC with the + system's assembler and linker. + + `tm-hp9k320g.h' + for HPUX systems, if you are using the GNU assembler, + linker and other utilities. Not all of the pieces of + GNU software needed for this mode of operation are as + yet in distribution; full instructions will appear + here in the future. + + `tm-tower-as.h' + for NCR Tower 32 systems, using the standard system + assembler. + + For the vax, use `tm-vax.h' on BSD Unix, `tm-vaxv.h' on + system V, or `tm-vms.h' on VMS. + + For the Motorola 88000, use `tm-m88k.h'. The support for + the 88000 does not currently work; it requires extensive + changes which we hope to reconcile in version 2. + + For the 80386, don't use `tm-i386.h' directly. Use + `tm-i386v.h' if the target machine is running system V, + `tm-i386gas.h' if it is running system V but you are using + the GNU assembler and linker, `tm-seq386.h' for a Sequent + 386 system, or `tm-compaq.h' for a Compaq, or + `tm-sun386i.h' for a Sun 386 system. + + For the Mips computer, there are five choices: `tm-mips.h' + for the M series, `tm-mips-bsd.h' for the RS series with + BSD, `tm-mips-sysv.h' for the RS series with System V, + `tm-iris.h' for the Iris version of the machine, and + `tm-decstatn.h' for the Decstation. + + For the 32000, use `tm-sequent.h' if you are using a + Sequent machine, or `tm-encore.h' for an Encore machine, or + `tm-genix.h' if you are using Genix version 3; otherwise, + perhaps `tm-ns32k.h' will work for you. + + Note that Genix has bugs in `alloca' and `malloc'; you must + get the compiled versions of these from GNU Emacs and edit + GNU CC's `Makefile' to use them. + + Note that Encore systems are supported only under BSD. + + For Sparc (Sun 4) machines, use `tm-sparc.h' with operating + system version 4, and `tm-sun4os3.h' with system version 3. + + For Convex systems before version 8.1, use `tm-conv1os7.h' + or `tm-conv2os7.h'. For versions 8.1 and greater, use + `tm-convex1.h' or `tm-convex2.h'. You should also + bootstrap GCC with `pcc' rather than `cc'; one way to do + this is with the following commands. + + ln -s /bin/pcc ./cc + set path = (. $path) + + * Make a symbolic link named `md' to the machine description + pattern file. It should be in the `config' subdirectory + and its name should be `MACHINE.md'; but MACHINE is often + not the same as the name used in the `tm.h' file because + the `md' files are more general. + + * Make a symbolic link named `aux-output.c' to the output + subroutine file for your machine. It should be in the + `config' subdirectory and its name should be `out-MACHINE.c'. + + 4. Make sure the Bison parser generator is installed. (This is + unnecessary if the Bison output files `c-parse.tab.c' and + `cexp.c' are more recent than `c-parse.y' and `cexp.y' and you + do not plan to change the `.y' files.) + + Bison versions older than Sept 8, 1988 will produce incorrect + output for `c-parse.tab.c'. + + 5. If you have a previous version of GCC installed, then chances + are you can compile the new version with that. Do the following: + + make CC="gcc -O" + + Since this produces an optimized executable right away, there is + no need to bootstrap the result with itself except to test it. + Therefore, you can skip directly to the `make install' step below. + + 6. Build the compiler. Just type `make' in the compiler directory. + + Ignore any warnings you may see about "statement not reached" + in the `insn-emit.c'; they are normal. Any other compilation + errors may represent bugs in the port to your machine or + operating system, and should be investigated and reported (*note + Bugs::.). + + Some commercial compilers fail to compile GNU CC because they + have bugs or limitations. For example, the Microsoft compiler + is said to run out of macro space. Some Ultrix compilers run + out of expression space; then you need to break up the statement + where the problem happens. + + 7. If you are using COFF-encapsulation, you must convert `gnulib' + to a GNU-format library at this point. See the file + `README-ENCAP' in the directory containing the GNU binary file + utilities, for directions. + + 8. Move the first-stage object files and executables into a + subdirectory with this command: + + make stage1 + + The files are moved into a subdirectory named `stage1'. Once + installation is complete, you may wish to delete these files + with `rm -r stage1'. + + 9. Recompile the compiler with itself, with this command: + + make CC=stage1/gcc CFLAGS="-g -O -Bstage1/" + + This is called making the stage 2 compiler. + + On a 68000 or 68020 system lacking floating point hardware, + unless you have selected a `tm.h' file that expects by default + that there is no such hardware, do this instead: + + make CC=stage1/gcc CFLAGS="-g -O -Bstage1/ -msoft-float" + + 10. If you wish to test the compiler by compiling it with itself one + more time, do this (in C shell): + + make stage2 + make CC=stage2/gcc CFLAGS="-g -O -Bstage2/" + foreach file (*.o) + cmp $file stage2/$file + end + + This is called making the stage 3 compiler. Aside from the `-B' + option, the options should be the same as when you made the + stage 2 compiler. + + The `foreach' command (written in C shell) will notify you if + any of these stage 3 object files differs from those of stage 2. + On BSD systems, any difference, no matter how innocuous, + indicates that the stage 2 compiler has compiled GNU CC + incorrectly, and is therefore a potentially serious bug which + you should investigate and report (*note Bugs::.). + + On systems that use COFF object files, bytes 5 to 8 will + always be different, since it is a timestamp. On these systems, + you can do the comparison as follows (in Bourne shell): + + for file in *.o; do + echo $file + tail +10c $file > foo1 + tail +10c stage2/$file > foo2 + cmp foo1 foo2 + done + + On MIPS machines, you should use the shell script `ecoff-cmp' + to compare two object files. + + 11. Install the compiler driver, the compiler's passes and run-time + support. You can use the following command: + + make install + + This copies the files `cc1', `cpp' and `gnulib' to files + `gcc-cc1', `gcc-cpp' and `gcc-gnulib' in directory + `/usr/local/lib', which is where the compiler driver program + looks for them. It also copies the driver program `gcc' into + the directory `/usr/local/bin', so that it appears in typical + execution search paths. + + *Warning: there is a bug in `alloca' in the Sun library. To + avoid this bug, install the binaries of GNU CC that were + compiled by GNU CC. They use `alloca' as a built-in function + and never the one in the library.* + + *Warning: the GNU CPP may not work for `ioctl.h', + `ttychars.h' and other system header files unless the + `-traditional' option is used.* The bug is in the header files: + at least on some machines, they rely on behavior that is + incompatible with ANSI C. This behavior consists of + substituting for macro argument names when they appear inside of + character constants. The `-traditional' option tells GNU CC to + behave the way these headers expect. + + Because of this problem, you might prefer to configure GNU CC + to use the system's own C preprocessor. To do so, make the file + `/usr/local/lib/gcc-cpp' a link to `/lib/cpp'. + + Alternatively, on Sun systems and 4.3BSD at least, you can + correct the include files by running the shell script + `fixincludes'. This installs modified, corrected copies of the + files `ioctl.h', `ttychars.h' and many others, in a special + directory where only GNU CC will normally look for them. This + script will work on various systems because it chooses the files + by searching all the system headers for the problem cases that + we know about. + + Use the following command to do this: + + make includes + + If you selected a different directory for GNU CC installation + when you installed it, by specifying the Make variable `prefix' + or `libdir', specify it the same way in this command. + + Note that some systems are starting to come with ANSI C + system header files. On these systems, don't run `fixincludes'; + it may not work, and is certainly not necessary. + + *Warning:* `fixincludes' does not work on many MIPS systems, + because those systems come with circular symbolic links which + cause `ls -lR' to go into an infinite loop. + + If you cannot install the compiler's passes and run-time support +in `/usr/local/lib', you can alternatively use the `-B' option to +specify a prefix by which they may be found. The compiler +concatenates the prefix with the names `cpp', `cc1' and `gnulib'. +Thus, you can put the files in a directory `/usr/foo/gcc' and specify +`-B/usr/foo/gcc/' when you run GNU CC. + + Also, you can specify an alternative default directory for these +files by setting the Make variable `libdir' when you make GNU CC. + + +File: gcc.info, Node: Other Dir, Next: Sun Install, Prev: Installation, Up: Installation + +Compilation in a Separate Directory +=================================== + + If you wish to build the object files and executables in a +directory other than the one containing the source files, here is +what you must do differently: + + 1. Go to that directory before running `config.gcc': + + mkdir gcc-sun3 + cd gcc-sun3 + + On systems that do not support symbolic links, this directory + must be on the same file system as the source code directory. + + 2. Specify where to find `config.gcc' when you run it: + + ../gcc-1.36/config.gcc ... + + 3. Specify where to find the sources, as an argument to `config.gcc': + + ../gcc-1.36/config.gcc -srcdir=../gcc-1.36 sun3 + + The `-srcdir=DIR' option is not needed when the source + directory is the parent of the current directory, because + `config.gcc' detects that case automatically. + + Now, you can run `make' in that directory. You need not repeat +the configuration steps shown above, when ordinary source files +change. You must, however, run `config.gcc' again when the +configuration files change, if your system does not support symbolic +links. + + +File: gcc.info, Node: Sun Install, Next: 3b1 Install, Prev: Other Dir, Up: Installation + +Installing GNU CC on the Sun +============================ + + Make sure the environment variable `FLOAT_OPTION' is not set when +you compile `gnulib'. If this option were set to `f68881' when +`gnulib' is compiled, the resulting code would demand to be linked +with a special startup file and would not link properly without +special pains. + + There is a bug in `alloca' in certain versions of the Sun library. +To avoid this bug, install the binaries of GNU CC that were compiled +by GNU CC. They use `alloca' as a built-in function and never the +one in the library. + + Some versions of the Sun compiler crash when compiling GNU CC, +with a segmentation fault in cpp. This can sometimes be due to the +bulk of data in the environment variables. You may be able to avoid +it by using the following command to compile GNU CC with Sun CC: + + make CC="TERMCAP=x OBJS=x LIBFUNCS=x STAGESTUFF=x cc" + + Another problem that often happens on Suns is that you get a crash +when building stage 2, when `genflags' is run. + + One reason for such as crash is if you configured GNU CC for the +wrong version of SunOS. Starting with version 1.38, configurations +`sun3' and `sun4' are for SunOS 4, so this problem should no longer +happen. + + Another cause of the same symptom is having installed the GNU +linker with an earlier version of SunOS. The version that worked +before stopped working due to a change in the format of executables +in SunOS 4.1. Many sites have installed the GNU linker as +`/usr/local/lib/gcc-ld', often as part of installing GNU C++. So if +you get such crashes and you have used the proper configuration, try +deleting `/usr/local/lib/gcc-ld'. + + The current version of the GNU linker, found in the current +binutils release, does work with SunOS 4.1. + + +File: gcc.info, Node: 3b1 Install, Next: SCO Install, Prev: Sun Install, Up: Installation + +Installing GNU CC on the 3b1 +============================ + + Installing GNU CC on the 3b1 is difficult if you do not already +have GNU CC running, due to bugs in the installed C compiler. +However, the following procedure might work. We are unable to test it. + + 1. Comment out the `#include "config.h"' line on line 37 of + `cccp.c' and do `make cpp'. This makes a preliminary version of + GNU cpp. + + 2. Save the old `/lib/cpp' and copy the preliminary GNU cpp to that + file name. + + 3. Undo your change in `cccp.c', or reinstall the original version, + and do `make cpp' again. + + 4. Copy this final version of GNU cpp into `/lib/cpp'. + + 5. Replace every occurrence of `obstack_free' in `tree.c' with + `_obstack_free'. + + 6. Run `make' to get the first-stage GNU CC. + + 7. Reinstall the original version of `/lib/cpp'. + + 8. Now you can compile GNU CC with itself and install it in the + normal fashion. + + If you have installed an earlier version of GCC, you can compile +the newer version with that. However, you will run into trouble +compiling `gnulib', since that is normally compiled with CC. To +solve the problem, uncomment this line in `Makefile': + + CCLIBFLAGS = -B/usr/local/lib/gcc- -tp -Wp,-traditional + + +File: gcc.info, Node: SCO Install, Next: VMS Install, Prev: 3B1 Install, Up: Installation + +Installing GNU CC on SCO System V 3.2 +===================================== + + The compiler that comes with this system does not work properly +with `-O'. Therefore, you should redefine the Make variable +`CCLIBFLAGS' not to use `-O'. + + You should also edit `Makefile' to enable the lines that set +`CLIB' to `-lPW', and the ones specifically labeled as being for SCO, +that set `RANLIB', and that set `CC' and `OLDCC' to `rcc'. + + Also, edit the definition of `USER_H' to remove the file `limits.h'. + + Then you can run `config.gcc i386-sco' and finish building GNU CC +normally. + + The same recipe should work on ESIX, but use `config.gcc +i386-esix' instead. + + +File: gcc.info, Node: VMS Install, Next: HPUX Install, Prev: SCO Install, Up: Installation + +Installing GNU CC on VMS +======================== + + The VMS version of GNU CC is distributed in a backup saveset +containing both source code and precompiled binaries. + + To install the `gcc' command so you can use the compiler easily, +in the same manner as you use the VMS C compiler, you must install +the VMS CLD file for GNU CC as follows: + + 1. Define the VMS logical names `GNU_CC' and `GNU_CC_INCLUDE' to + point to the directories where the GNU CC executables + (`gcc-cpp', `gcc-cc1', etc.) and the C include files are kept. + This should be done with the commands: + + $ assign /super /system disk:[gcc.] gnu_cc + $ assign /super /system disk:[gcc.include.] gnu_cc_include + + with the appropriate disk and directory names. These commands + can be placed in your system startup file so they will be + executed whenever the machine is rebooted. You may, if you + choose, do this via the `GCC_INSTALL.COM' script in the `[GCC]' + directory. + + 2. Install the `GCC' command with the command line: + + $ set command /table=sys$library:dcltables gnu_cc:[000000]gcc + + 3. To install the help file, do the following: + + $ lib/help sys$library:helplib.hlb gcc.hlp + + Now you can invoke the compiler with a command like `gcc + /verbose file.c', which is equivalent to the command `gcc -v -c + file.c' in Unix. + + We try to put corresponding binaries and sources on the VMS +distribution tape. But sometimes the binaries will be from an older +version that the sources, because we don't always have time to update +them. (Use the `/verbose' option to determine the version number of +the binaries and compare it with the source file `version.c' to tell +whether this is so.) In this case, you should use the binaries you +get to recompile the sources. If you must recompile, here is how: + + 1. Copy the file `tm-vms.h' to `tm.h', `xm-vms.h' to `config.h', + `vax.md' to `md.' and `out-vax.c' to `aux-output.c'. The files + to be copied are found in the subdirectory named `config'; they + should be copied to the main directory of GNU CC. + + 2. Setup the logical names and command tables as defined above. In + addition, define the vms logical name `GNU_BISON' to point at + the to the directories where the Bison executable is kept. This + should be done with the command: + + $ assign /super /system disk:[bison.] gnu_bison + + You may, if you choose, use the `INSTALL_BISON.COM' script in + the `[BISON]' directory. + + 3. Install the `BISON' command with the command line: + + $ set command /table=sys$library:dcltables gnu_bison:[000000]bison + + 4. Type `@make' to do recompile everything. + + If you are compiling with a version of GNU CC older than + 1.33, specify `/DEFINE=("inline=")' as an option in all the + compilations. This requires editing all the `gcc' commands in + `make-cc1.com'. (The older versions had problems supporting + `inline'.) Once you have a working 1.33 or newer GNU CC, you + can change this file back. + + Due to the differences between the filesystems of Unix and VMS, +the preprocessor attempts to translate the names of include files +into something that VMS will understand. The basic strategy is to +prepend a prefix to the specification of the include file, convert +the whole filename to a VMS filename, and then try to open the file. +The preprocessor tries various prefixes until one of them succeeds. + + The first prefix is the `GNU_CC_INCLUDE:' logical name: this is +where GNU_C header files are traditionally stored. If a header file +is not found there, `SYS$SYSROOT:[SYSLIB.]' is tried next. If the +preprocessor is still unable to locate the file, it then assumes that +the include file specification is a valid VMS filename all by itself, +and it uses this filename to attempt to open the include file. If +none of these strategies succeeds, the preprocessor reports an error. + + If you wish to store header files in non-standard locations, then +you can assign the logical `GNU_CC_INCLUDE' to be a search list, +where each element of the list is suitable for use with a rooted +logical. + + With this version of GNU CC, `const' global variables now work +properly. Unless, however, the `const' modifier is also specified in +every external declaration of the variable in all of the source files +that use that variable, the linker will issue warnings about +conflicting attributes for the variable, since the linker does not +know if the variable should be read-only. The program will still +work, but the variable will be placed in writable storage. + + Due to an assembler bug, offsets to static constants are sometimes +incorrectly evaluated. This bug is present in GAS 1.38.1, and should +be fixed in the next version. + + Under previous versions of GNU CC, the generated code would +occasionally give strange results when linked to the sharable +`VAXCRTL' library. Now this should work. + + Even with this version, however, GNU CC itself should not be +linked to the sharable `VAXCRTL'. The `qsort' routine supplied with +`VAXCRTL' has a bug which can cause a compiler crash. + + Similarly, the preprocessor should not be linked to the sharable +`VAXCRTL'. The `strncat' routine supplied with `VAXCRTL' has a bug +which can cause the preprocessor to go into an infinite loop. + + It should be pointed out that if you attempt to link to the +sharable `VAXCRTL', the VMS linker will strongly resist any effort to +force it to use the `qsort' and `strncat' routines from `gcclib'. +Until the bugs in `VAXCRTL' have been fixed, linking any of the +compiler components to the sharable VAXCRTL is not recommended. +(These routines can be bypassed by placing duplicate copies of +`qsort' and `strncat' in `gcclib' under different names, and patching +the compiler sources to use these routines). Both of the bugs in +`VAXCRTL' are still present in VMS version 5.4-1, which is the most +recent version as of this writing. + + The executables that are generated by `make-cc1.com' and +`make-cccp.com' use the non-shared version of `VAXCRTL' (and thus use +the `qsort' and `strncat' routines from `gcclib.olb'). + + Note that GNU CC on VMS now generates debugging information to +describe the programs symbols to the VMS debugger. However, you need +version 1.37 or later of GAS in order to output them properly in the +object file. + + The VMS linker does not distinguish between upper and lower case +letters in function and variable names. However, usual practice in C +is to distinguish case. Normally GNU C (by means of the assembler +GAS) implements usual C behavior by augmenting each name that is not +all lower-case. A name is augmented by truncating it to at most 23 +characters and then adding more characters at the end which encode +the case pattern the rest. + + Name augmentation yields bad results for programs that use +precompiled libraries (such as Xlib) which were generated by another +compiler. Use the compiler option `/NOCASE_HACK' to inhibits +augmentation; it makes external C functions and variables +case-independent as is usual on VMS. Alternatively, you could write +all references to the functions and variables in such libraries using +lower case; this will work on VMS, but is not portable to other +systems. In cases where you need to selectively inhibit +augmentation, you can define a macro for each mixed case symbol for +which you wish to inhibit augmentation, where the macro expands into +the lower case equivalent of the name. + + +File: gcc.info, Node: HPUX Install, Next: Tower Install, Prev: VMS Install, Up: Installation + +Installing GNU CC on HPUX +========================= + + To install GNU CC on HPUX, you must start by editing the file +`Makefile'. Search for the string `HPUX' to find comments saying +what to change. You need to change some variable definitions and (if +you are using GAS) some lines in the rule for the target `gnulib'. + + To avoid errors when linking programs with `-g', create an empty +library named `libg.a'. An easy way to do this is: + + ar rc /usr/local/lib/libg.a + + To compile with the HPUX C compiler, you must specify get the file +`alloca.c' from GNU Emacs. Then, when you run `make', use this +argument: + + make ALLOCA=alloca.o + + When recompiling GNU CC with itself, do not define `ALLOCA'. +Instead, an `-I' option needs to be added to `CFLAGS' as follows: + + make CC=stage1/gcc CFLAGS="-g -O -Bstage1/ -I../binutils/hp-include" + + +File: gcc.info, Node: Tower Install, Prev: HPUX Install, Up: Installation + +Installing GNU CC on an NCR Tower +================================= + + On an NCR Tower model 4x0 or 6x0, you may have trouble because the +default maximum virtual address size of a process is just 1 Mb. Most +often you will find this problem while compiling GNU CC with itself. + + The only way to solve the problem is to reconfigure the kernel. +Add a line such as this to the configuration file: + + MAXUMEM = 4096 + +and then relink the kernel and reboot the machine. + + +File: gcc.info, Node: Trouble, Next: Service, Prev: Installation, Up: Top + +Known Causes of Trouble with GNU CC +*********************************** + + Here are some of the things that have caused trouble for people +installing or using GNU CC. + + * On certain systems, defining certain environment variables such + as `CC' can interfere with the functioning of `make'. + + * Cross compilation can run into trouble for certain machines + because some target machines' assemblers require floating point + numbers to be written as *integer* constants in certain contexts. + + The compiler writes these integer constants by examining the + floating point value as an integer and printing that integer, + because this is simple to write and independent of the details + of the floating point representation. But this does not work if + the compiler is running on a different machine with an + incompatible floating point format, or even a different + byte-ordering. + + In addition, correct constant folding of floating point values + requires representing them in the target machine's format. (The + C standard does not quite require this, but in practice it is + the only way to win.) + + It is now possible to overcome these problems by defining macros + such as `REAL_VALUE_TYPE'. But doing so is a substantial amount + of work for each target machine. *Note Cross-compilation::. + + * Users often think it is a bug when GNU CC reports an error for + code like this: + + int foo (short); + + int foo (x) + short x; + {...} + + The error message is correct: this code really is erroneous, + because the old-style non-prototype definition passes subword + integers in their promoted types. In other words, the argument + is really an `int', not a `short'. The correct prototype is this: + + int foo (int); + + * Users often think it is a bug when GNU CC reports an error for + code like this: + + int foo (struct mumble *); + + struct mumble { ... }; + + int foo (struct mumble *x) + { ... } + + This code really is erroneous, because the scope of `struct + mumble' the prototype is limited to the argument list containing + it. It does not refer to the `struct mumble' defined with file + scope immediately below--they are two unrelated types with + similar names in different scopes. + + But in the definition of `foo', the file-scope type is used + because that is available to be inherited. Thus, the definition + and the prototype do not match, and you get an error. + + This behavior may seem silly, but it's what the ANSI standard + specifies. It is easy enough for you to make your code work by + moving the definition of `struct mumble' above the prototype. I + don't think it's worth being incompatible for. + + Additional problems are described in *Note Incompatibilities::. + + +File: gcc.info, Node: Service, Next: Incompatibilities, Prev: Trouble, Up: Top + +How To Get Help with GNU CC +*************************** + + If you need help installing, using or changing GNU CC, there are +two ways to find it: + + * Send a message to a suitable network mailing list. First try + `bug-gcc@prep.ai.mit.edu', and if that brings no response, try + `help-gcc@prep.ai.mit.edu'. + + * Look in the service directory for someone who might help you for + a fee. The service directory is found in the file named + `SERVICE' in the GNU CC distribution. + + +File: gcc.info, Node: Incompatibilities, Next: Extensions, Prev: Service, Up: Top + +Incompatibilities of GNU CC +*************************** + + There are several noteworthy incompatibilities between GNU C and +most existing (non-ANSI) versions of C. The `-traditional' option +eliminates most of these incompatibilities, *but not all*, by telling +GNU C to behave like older C compilers. + + * GNU CC normally makes string constants read-only. If several + identical-looking string constants are used, GNU CC stores only + one copy of the string. + + One consequence is that you cannot call `mktemp' with a string + constant argument. The function `mktemp' always alters the + string its argument points to. + + Another consequence is that `sscanf' does not work on some + systems when passed a string constant as its format control + string. This is because `sscanf' incorrectly tries to write + into the string constant. Likewise `fscanf' and `scanf'. + + The best solution to these problems is to change the program to + use `char'-array variables with initialization strings for these + purposes instead of string constants. But if this is not + possible, you can use the `-fwritable-strings' flag, which + directs GNU CC to handle string constants the same way most C + compilers do. `-traditional' also has this effect, among others. + + * GNU CC does not substitute macro arguments when they appear + inside of string constants. For example, the following macro in + GNU CC + + #define foo(a) "a" + + will produce output `"a"' regardless of what the argument A is. + + The `-traditional' option directs GNU CC to handle such cases + (among others) in the old-fashioned (non-ANSI) fashion. + + * When you use `setjmp' and `longjmp', the only automatic + variables guaranteed to remain valid are those declared + `volatile'. This is a consequence of automatic register + allocation. Consider this function: + + jmp_buf j; + + foo () + { + int a, b; + + a = fun1 (); + if (setjmp (j)) + return a; + + a = fun2 (); + /* `longjmp (j)' may be occur in `fun3'. */ + return a + fun3 (); + } + + Here `a' may or may not be restored to its first value when the + `longjmp' occurs. If `a' is allocated in a register, then its + first value is restored; otherwise, it keeps the last value + stored in it. + + If you use the `-W' option with the `-O' option, you will get a + warning when GNU CC thinks such a problem might be possible. + + The `-traditional' option directs GNU C to put variables in the + stack by default, rather than in registers, in functions that + call `setjmp'. This results in the behavior found in + traditional C compilers. + + * Declarations of external variables and functions within a block + apply only to the block containing the declaration. In other + words, they have the same scope as any other declaration in the + same place. + + In some other C compilers, a `extern' declaration affects all + the rest of the file even if it happens within a block. + + The `-traditional' option directs GNU C to treat all `extern' + declarations as global, like traditional compilers. + + * In traditional C, you can combine `long', etc., with a typedef + name, as shown here: + + typedef int foo; + typedef long foo bar; + + In ANSI C, this is not allowed: `long' and other type modifiers + require an explicit `int'. Because this criterion is expressed + by Bison grammar rules rather than C code, the `-traditional' + flag cannot alter it. + + * PCC allows typedef names to be used as function parameters. The + difficulty described immediately above applies here too. + + * PCC allows whitespace in the middle of compound assignment + operators such as `+='. GNU CC, following the ANSI standard, + does not allow this. The difficulty described immediately above + applies here too. + + * GNU CC will flag unterminated character constants inside of + preprocessor conditionals that fail. Some programs have English + comments enclosed in conditionals that are guaranteed to fail; + if these comments contain apostrophes, GNU CC will probably + report an error. For example, this code would produce an error: + + #if 0 + You can't expect this to work. + #endif + + The best solution to such a problem is to put the text into an + actual C comment delimited by `/*...*/'. However, + `-traditional' suppresses these error messages. + + * When compiling functions that return `float', PCC converts it to + a double. GNU CC actually returns a `float'. If you are + concerned with PCC compatibility, you should declare your + functions to return `double'; you might as well say what you mean. + + * When compiling functions that return structures or unions, GNU + CC output code normally uses a method different from that used + on most versions of Unix. As a result, code compiled with GNU + CC cannot call a structure-returning function compiled with PCC, + and vice versa. + + The method used by GNU CC is as follows: a structure or union + which is 1, 2, 4 or 8 bytes long is returned like a scalar. A + structure or union with any other size is stored into an address + supplied by the caller in a special, fixed register. + + PCC usually handles all sizes of structures and unions by + returning the address of a block of static storage containing + the value. This method is not used in GNU CC because it is + slower and nonreentrant. + + You can tell GNU CC to use the PCC convention with the option + `-fpcc-struct-return'. + + There are also system-specific incompatibilities. + + * On the Sparc, GNU CC uses an incompatible calling convention for + structures. It passes them by including their contents in the + argument list, whereas the standard compiler passes them + effectively by reference. + + This really ought to be fixed, but such calling conventions are + not yet supported in GNU CC, so it isn't straightforward to fix + it. GNU CC version 2 will use a compatible calling convention. + + The convention for structure returning is also incompatible, and + `-fpcc-struct-return' does not help. + + * The Sparc version of `setjmp' interacts badly with unexpected + stack adjustments. With rare exceptions, you cannot use + `setjmp' in a function which moves the stack pointer. + + In the current version of GNU CC, there are three ways that the + stack pointer can change value: (1) calls to `alloca', (2) use + of variable-sized objects, and (3) calls to functions with + parameters that do not all fit in the argument-passing registers + (e.g., more than 6 parameters). You should avoid all three in + functions that call `setjmp'. + + The cause of the problem is the way that Sun implemented + register windows. The 64 bytes at addresses `%sp' through + `%sp+63' correspond to the register window save area. When a + register window must be spilled, its stack pointer is located, + and the registers are dumped starting at that address. + Similarly, when a register window must be restored, its stack + pointer is located, and the registers are restored from that + address. + + When `setjmp' is called, the current register window's registers + are saved into the register save area, and when `longjmp' is + called, they are restored (actually, *all* register windows are + restored from all valid register windows at the time `longjmp' + is called). If there is a change in the value of the stack + pointer bewteen the `setjmp' and `longjmp' calls, when the + registers are restored, they are restored with random values. + + * On Ultrix, the Fortran compiler expects registers 2 through 5 to + be saved by function calls. We have not been able to tell + whether the C compiler agrees with the Fortran compiler. + Currently, GNU CC treats these registers as temporaries on the + Vax, which is compatible with BSD Unix. + + If we learn for certain that Ultrix has departed from the + traditional BSD calling convention, we will change GNU CC for + Ultrix to fit. In the mean time, you can use these options to + produce code compatible with the Fortran compiler: + + -fcall-saved-r2 -fcall-saved-r3 -fcall-saved-r4 -fcall-saved-r5 + + * DBX rejects some files produced by GNU CC, though it accepts + similar constructs in output from PCC. Until someone can supply + a coherent description of what is valid DBX input and what is + not, there is nothing I can do about these problems. You are on + your own. + + +File: gcc.info, Node: Extensions, Next: Bugs, Prev: Incompatibilities, Up: Top + +GNU Extensions to the C Language +******************************** + + GNU C provides several language features not found in ANSI +standard C. (The `-pedantic' option directs GNU CC to print a +warning message if any of these features is used.) To test for the +availability of these features in conditional compilation, check for +a predefined macro `__GNUC__', which is always defined under GNU CC. + +* Menu: + +* Statement Exprs:: Putting statements and declarations inside expressions. +* Naming Types:: Giving a name to the type of some expression. +* Typeof:: `typeof': referring to the type of an expression. +* Lvalues:: Using `?:', `,' and casts in lvalues. +* Conditionals:: Omitting the middle operand of a `?:' expression. +* Zero-Length:: Zero-length arrays. +* Variable-Length:: Arrays whose length is computed at run time. +* Subscripting:: Any array can be subscripted, even if not an lvalue. +* Pointer Arith:: Arithmetic on `void'-pointers and function pointers. +* Initializers:: Non-constant initializers. +* Constructors:: Constructor expressions give structures, unions + or arrays as values. +* Function Attributes:: Declaring that functions have no side effects, + or that they can never return. +* Dollar Signs:: Dollar sign is allowed in identifiers. +* Alignment:: Inquiring about the alignment of a type or variable. +* Inline:: Defining inline functions (as fast as macros). +* Extended Asm:: Assembler instructions with C expressions as operands. + (With them you can define "built-in" functions.) +* Asm Labels:: Specifying the assembler name to use for a C symbol. +* Explicit Reg Vars:: Defining variables residing in specified registers. +* Alternate Keywords:: `__const__', `__asm__', etc., for header files. + + +File: gcc.info, Node: Statement Exprs, Next: Naming Types, Prev: Extensions, Up: Extensions + +Statements and Declarations inside of Expressions +================================================= + + A compound statement in parentheses may appear inside an +expression in GNU C. This allows you to declare variables within an +expression. For example: + + ({ int y = foo (); int z; + if (y > 0) z = y; + else z = - y; + z; }) + +is a valid (though slightly more complex than necessary) expression +for the absolute value of `foo ()'. + + This feature is especially useful in making macro definitions +"safe" (so that they evaluate each operand exactly once). For +example, the "maximum" function is commonly defined as a macro in +standard C as follows: + + #define max(a,b) ((a) > (b) ? (a) : (b)) + +But this definition computes either A or B twice, with bad results if +the operand has side effects. In GNU C, if you know the type of the +operands (here let's assume `int'), you can define the macro safely +as follows: + + #define maxint(a,b) \ + ({int _a = (a), _b = (b); _a > _b ? _a : _b; }) + + Embedded statements are not allowed in constant expressions, such +as the value of an enumeration constant, the width of a bit field, or +the initial value of a static variable. + + If you don't know the type of the operand, you can still do this, +but you must use `typeof' (*note Typeof::.) or type naming (*note +Naming Types::.). + + \ No newline at end of file diff --git a/gcc-1.40/gcc.info-4 b/gcc-1.40/gcc.info-4 new file mode 100644 index 0000000..0e44e41 --- /dev/null +++ b/gcc-1.40/gcc.info-4 @@ -0,0 +1,1022 @@ +Info file gcc.info, produced by Makeinfo, -*- Text -*- from input +file gcc.texinfo. + + This file documents the use and the internals of the GNU compiler. + + Copyright (C) 1988, 1989, 1990 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. + + 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" and "Protect +Your Freedom--Fight `Look And Feel'" 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" and "Protect Your Freedom--Fight `Look And Feel'" and this +permission notice may be included in translations approved by the +Free Software Foundation instead of in the original English. + + +File: gcc.info, Node: Naming Types, Next: Typeof, Prev: Statement Exprs, Up: Extensions + +Naming an Expression's Type +=========================== + + You can give a name to the type of an expression using a `typedef' +declaration with an initializer. Here is how to define NAME as a +type name for the type of EXP: + + typedef NAME = EXP; + + This is useful in conjunction with the +statements-within-expressions feature. Here is how the two together +can be used to define a safe "maximum" macro that operates on any +arithmetic type: + + #define max(a,b) \ + ({typedef _ta = (a), _tb = (b); \ + _ta _a = (a); _tb _b = (b); \ + _a > _b ? _a : _b; }) + + The reason for using names that start with underscores for the +local variables is to avoid conflicts with variable names that occur +within the expressions that are substituted for `a' and `b'. +Eventually we hope to design a new form of declaration syntax that +allows you to declare variables whose scopes start only after their +initializers; this will be a more reliable way to prevent such +conflicts. + + +File: gcc.info, Node: Typeof, Next: Lvalues, Prev: Naming Types, Up: Extensions + +Referring to a Type with `typeof' +================================= + + Another way to refer to the type of an expression is with `typeof'. +The syntax of using of this keyword looks like `sizeof', but the +construct acts semantically like a type name defined with `typedef'. + + There are two ways of writing the argument to `typeof': with an +expression or with a type. Here is an example with an expression: + + typeof (x[0](1)) + +This assumes that `x' is an array of functions; the type described is +that of the values of the functions. + + Here is an example with a typename as the argument: + + typeof (int *) + +Here the type described is that of pointers to `int'. + + If you are writing a header file that must work when included in +ANSI C programs, write `__typeof__' instead of `typeof'. *Note +Alternate Keywords::. + + A `typeof'-construct can be used anywhere a typedef name could be +used. For example, you can use it in a declaration, in a cast, or +inside of `sizeof' or `typeof'. + + * This declares `y' with the type of what `x' points to. + + typeof (*x) y; + + * This declares `y' as an array of such values. + + typeof (*x) y[4]; + + * This declares `y' as an array of pointers to characters: + + typeof (typeof (char *)[4]) y; + + It is equivalent to the following traditional C declaration: + + char *y[4]; + + To see the meaning of the declaration using `typeof', and why it + might be a useful way to write, let's rewrite it with these + macros: + + #define pointer(T) typeof(T *) + #define array(T, N) typeof(T [N]) + + Now the declaration can be rewritten this way: + + array (pointer (char), 4) y; + + Thus, `array (pointer (char), 4)' is the type of arrays of 4 + pointers to `char'. + + +File: gcc.info, Node: Lvalues, Next: Conditionals, Prev: Typeof, Up: Extensions + +Generalized Lvalues +=================== + + Compound expressions, conditional expressions and casts are +allowed as lvalues provided their operands are lvalues. This means +that you can take their addresses or store values into them. + + For example, a compound expression can be assigned, provided the +last expression in the sequence is an lvalue. These two expressions +are equivalent: + + (a, b) += 5 + a, (b += 5) + + Similarly, the address of the compound expression can be taken. +These two expressions are equivalent: + + &(a, b) + a, &b + + A conditional expression is a valid lvalue if its type is not void +and the true and false branches are both valid lvalues. For example, +these two expressions are equivalent: + + (a ? b : c) = 5 + (a ? b = 5 : (c = 5)) + + A cast is a valid lvalue if its operand is valid. Taking the +address of the cast is the same as taking the address without a cast, +except for the type of the result. For example, these two +expressions are equivalent (but the second may be valid when the type +of `a' does not permit a cast to `int *'). + + &(int *)a + (int **)&a + + A simple assignment whose left-hand side is a cast works by +converting the right-hand side first to the specified type, then to +the type of the inner left-hand side expression. After this is +stored, the value is converter back to the specified type to become +the value of the assignment. Thus, if `a' has type `char *', the +following two expressions are equivalent: + + (int)a = 5 + (int)(a = (char *)5) + + An assignment-with-arithmetic operation such as `+=' applied to a +cast performs the arithmetic using the type resulting from the cast, +and then continues as in the previous case. Therefore, these two +expressions are equivalent: + + (int)a += 5 + (int)(a = (char *) ((int)a + 5)) + + +File: gcc.info, Node: Conditionals, Next: Zero-Length, Prev: Lvalues, Up: Extensions + +Conditional Expressions with Omitted Middle-Operands +==================================================== + + The middle operand in a conditional expression may be omitted. +Then if the first operand is nonzero, its value is the value of the +conditional expression. + + Therefore, the expression + + x ? : y + +has the value of `x' if that is nonzero; otherwise, the value of `y'. + + This example is perfectly equivalent to + + x ? x : y + +In this simple case, the ability to omit the middle operand is not +especially useful. When it becomes useful is when the first operand +does, or may (if it is a macro argument), contain a side effect. +Then repeating the operand in the middle would perform the side +effect twice. Omitting the middle operand uses the value already +computed without the undesirable effects of recomputing it. + + +File: gcc.info, Node: Zero-Length, Next: Variable-Length, Prev: Conditionals, Up: Extensions + +Arrays of Length Zero +===================== + + Zero-length arrays are allowed in GNU C. They are very useful as +the last element of a structure which is really a header for a +variable-length object: + + struct line { + int length; + char contents[0]; + }; + + { + struct line *thisline + = (struct line *) malloc (sizeof (struct line) + this_length); + thisline->length = this_length; + } + + In standard C, you would have to give `contents' a length of 1, +which means either you waste space or complicate the argument to +`malloc'. + + +File: gcc.info, Node: Variable-Length, Next: Subscripting, Prev: Zero-Length, Up: Extensions + +Arrays of Variable Length +========================= + + Variable-length automatic arrays are allowed in GNU C. These +arrays are declared like any other automatic arrays, but with a +length that is not a constant expression. The storage is allocated +at that time and deallocated when the brace-level is exited. For +example: + + FILE *concat_fopen (char *s1, char *s2, char *mode) + { + char str[strlen (s1) + strlen (s2) + 1]; + strcpy (str, s1); + strcat (str, s2); + return fopen (str, mode); + } + + You can also use variable-length arrays as arguments to functions: + + struct entry + tester (int len, char data[len]) + { + ... + } + + The length of an array is computed on entry to the brace-level +where the array is declared and is remembered for the scope of the +array in case you access it with `sizeof'. + + Jumping or breaking out of the scope of the array name will also +deallocate the storage. Jumping into the scope is not allowed; you +will get an error message for it. + + You can use the function `alloca' to get an effect much like +variable-length arrays. The function `alloca' is available in many +other C implementations (but not in all). On the other hand, +variable-length arrays are more elegant. + + There are other differences between these two methods. Space +allocated with `alloca' exists until the containing *function* returns. +The space for a variable-length array is deallocated as soon as the +array name's scope ends. (If you use both variable-length arrays and +`alloca' in the same function, deallocation of a variable-length +array will also deallocate anything more recently allocated with +`alloca'.) + + +File: gcc.info, Node: Subscripting, Next: Pointer Arith, Prev: Variable-Length, Up: Extensions + +Non-Lvalue Arrays May Have Subscripts +===================================== + + Subscripting is allowed on arrays that are not lvalues, even +though the unary `&' operator is not. For example, this is valid in +GNU C though not valid in other C dialects: + + struct foo {int a[4];}; + + struct foo f(); + + bar (int index) + { + return f().a[index]; + } + + +File: gcc.info, Node: Pointer Arith, Next: Initializers, Prev: Subscripting, Up: Extensions + +Arithmetic on `void'-Pointers and Function Pointers +=================================================== + + In GNU C, addition and subtraction operations are supported on +pointers to `void' and on pointers to functions. This is done by +treating the size of a `void' or of a function as 1. + + A consequence of this is that `sizeof' is also allowed on `void' +and on function types, and returns 1. + + The option `-Wpointer-arith' requests a warning if these +extensions are used. + + +File: gcc.info, Node: Initializers, Next: Constructors, Prev: Pointer Arith, Up: Extensions + +Non-Constant Initializers +========================= + + The elements of an aggregate initializer for an automatic variable +are not required to be constant expressions in GNU C. Here is an +example of an initializer with run-time varying elements: + + foo (float f, float g) + { + float beat_freqs[2] = { f-g, f+g }; + ... + } + + +File: gcc.info, Node: Constructors, Next: Function Attributes, Prev: Initializers, Up: Extensions + +Constructor Expressions +======================= + + GNU C supports constructor expressions. A constructor looks like +a cast containing an initializer. Its value is an object of the type +specified in the cast, containing the elements specified in the +initializer. The type must be a structure, union or array type. + + Assume that `struct foo' and `structure' are declared as shown: + + struct foo {int a; char b[2];} structure; + +Here is an example of constructing a `struct foo' with a constructor: + + structure = ((struct foo) {x + y, 'a', 0}); + +This is equivalent to writing the following: + + { + struct foo temp = {x + y, 'a', 0}; + structure = temp; + } + + You can also construct an array. If all the elements of the +constructor are (made up of) simple constant expressions, suitable +for use in initializers, then the constructor is an lvalue and can be +coerced to a pointer to its first element, as shown here: + + char **foo = (char *[]) { "x", "y", "z" }; + + Array constructors whose elements are not simple constants are not +very useful, because the constructor is not an lvalue. There are +only two valid ways to use it: to subscript it, or initialize an +array variable with it. The former is probably slower than a +`switch' statement, while the latter does the same thing an ordinary +C initializer would do. + + output = ((int[]) { 2, x, 28 }) [input]; + + +File: gcc.info, Node: Function Attributes, Next: Dollar Signs, Prev: Constructors, Up: Extensions + +Declaring Attributes of Functions +================================= + + In GNU C, you declare certain things about functions called in +your program which help the compiler optimize function calls. + + A few functions, such as `abort' and `exit', cannot return. These +functions should be declared `volatile'. For example, + + extern volatile void abort (); + +tells the compiler that it can assume that `abort' will not return. +This makes slightly better code, but more importantly it helps avoid +spurious warnings of uninitialized variables. + + Many functions do not examine any values except their arguments, +and have no effects except the return value. Such a function can be +subject to common subexpression elimination and loop optimization +just as an arithmetic operator would be. These functions should be +declared `const'. For example, + + extern const void square (); + +says that the hypothetical function `square' is safe to call fewer +times than the program says. + + Note that a function that has pointer arguments and examines the +data pointed to must *not* be declared `const'. Likewise, a function +that calls a non-`const' function usually must not be `const'. + + Some people object to this feature, claiming that ANSI C's +`#pragma' should be used instead. There are two reasons I did not do +this. + + 1. It is impossible to generate `#pragma' commands from a macro. + + 2. The `#pragma' command is just as likely as these keywords to + mean something else in another compiler. + + These two reasons apply to *any* application whatever: as far as I +can see, `#pragma' is never useful. + + +File: gcc.info, Node: Dollar Signs, Next: Alignment, Prev: Function Attributes, Up: Extensions + +Dollar Signs in Identifier Names +================================ + + In GNU C, you may use dollar signs in identifier names. This is +because many traditional C implementations allow such identifiers. + + Dollar signs are allowed if you specify `-traditional'; they are +not allowed if you specify `-ansi'. Whether they are allowed by +default depends on the target machine; usually, they are not. + + +File: gcc.info, Node: Alignment, Next: Inline, Prev: Dollar Signs, Up: Extensions + +Inquiring about the Alignment of a Type or Variable +=================================================== + + The keyword `__alignof__' allows you to inquire about how an +object is aligned, or the minimum alignment usually required by a +type. Its syntax is just like `sizeof'. + + For example, if the target machine requires a `double' value to be +aligned on an 8-byte boundary, then `__alignof__ (double)' is 8. +This is true on many RISC machines. On more traditional machine +designs, `__alignof__ (double)' is 4 or even 2. + + Some machines never actually require alignment; they allow +reference to any data type even at an odd addresses. For these +machines, `__alignof__' reports the *recommended* alignment of a type. + + When the operand of `__alignof__' is an lvalue rather than a type, +the value is the largest alignment that the lvalue is known to have. +It may have this alignment as a result of its data type, or because +it is part of a structure and inherits alignment from that structure. +For example, after this declaration: + + struct foo { int x; char y; } foo1; + +the value of `__alignof__ (foo1.y)' is probably 2 or 4, the same as +`__alignof__ (int)', even though the data type of `foo1.y' does not +itself demand any alignment. + + +File: gcc.info, Node: Inline, Next: Extended Asm, Prev: Alignment, Up: Extensions + +An Inline Function is As Fast As a Macro +======================================== + + By declaring a function `inline', you can direct GNU CC to +integrate that function's code into the code for its callers. This +makes execution faster by eliminating the function-call overhead; in +addition, if any of the actual argument values are constant, their +known values may permit simplifications at compile time so that not +all of the inline function's code needs to be included. + + To declare a function inline, use the `inline' keyword in its +declaration, like this: + + inline int + inc (int *a) + { + (*a)++; + } + + (If you are writing a header file to be included in ANSI C +programs, write `__inline__' instead of `inline'. *Note Alternate +Keywords::.) + + You can also make all "simple enough" functions inline with the +option `-finline-functions'. Note that certain usages in a function +definition can make it unsuitable for inline substitution. + + When a function is both inline and `static', if all calls to the +function are integrated into the caller, and the function's address +is never used, then the function's own assembler code is never +referenced. In this case, GNU CC does not actually output assembler +code for the function, unless you specify the option +`-fkeep-inline-functions'. Some calls cannot be integrated for +various reasons (in particular, calls that precede the function's +definition cannot be integrated, and neither can recursive calls +within the definition). If there is a nonintegrated call, then the +function is compiled to assembler code as usual. The function must +also be compiled as usual if the program refers to its address, +because that can't be inlined. + + When an inline function is not `static', then the compiler must +assume that there may be calls from other source files; since a +global symbol can be defined only once in any program, the function +must not be defined in the other source files, so the calls therein +cannot be integrated. Therefore, a non-`static' inline function is +always compiled on its own in the usual fashion. + + If you specify both `inline' and `extern' in the function +definition, then the definition is used only for inlining. In no +case is the function compiled on its own, not even if you refer to +its address explicitly. Such an address becomes an external +reference, as if you had only declared the function, and had not +defined it. + + This combination of `inline' and `extern' has almost the effect of +a macro. The way to use it is to put a function definition in a +header file with these keywords, and put another copy of the +definition (lacking `inline' and `extern') in a library file. The +definition in the header file will cause most calls to the function +to be inlined. If any uses of the function remain, they will refer +to the single copy in the library. + + +File: gcc.info, Node: Extended Asm, Next: Asm Labels, Prev: Inline, Up: Extensions + +Assembler Instructions with C Expression Operands +================================================= + + In an assembler instruction using `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 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. + + For example, here is how to use the 68881's `fsinx' instruction: + + asm ("fsinx %1,%0" : "=f" (result) : "f" (angle)); + +Here `angle' is the C expression for the input operand while `result' +is that of the output operand. Each has `"f"' as its operand +constraint, saying that a floating-point register is required. The +`=' in `=f' indicates that the operand is an output; all output +operands' constraints must use `='. The constraints use the same +language used in the machine description (*note 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 the maximum number of operands in any instruction pattern +in the machine description. + + If there are no output operands, and there are input operands, +then there must be 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 `asm' feature is most often +used for machine instructions that the compiler itself does not know +exist. + + 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 `+', +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) `combine' instruction with `bar' as +its read-only source operand and `foo' as its read-write destination: + + asm ("combine %2,%0" : "=r" (foo) : "0" (foo), "g" (bar)); + +The constraint `"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 `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: + + asm ("combine %2,%0" : "=r" (foo) : "r" (foo), "g" (bar)); + + Various optimizations or reloading could cause operands 0 and 1 to +be in different registers; GNU CC knows no reason not to do so. For +example, the compiler might find a copy of the value of `foo' in one +register and use it for operand 1, but generate the output operand 0 +in a different register (copying it afterward to `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. + + Unless an output operand has the `&' 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. This assumption may be false if the assembler code +actually consists of more than one instruction. In such a case, use +`&' for each output operand that may not overlap an input. *Note +Modifiers::. + + 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: + + asm volatile ("movc3 %0,%1,%2" + : /* no outputs */ + : "g" (from), "g" (to), "g" (count) + : "r0", "r1", "r2", "r3", "r4", "r5"); + + You can put multiple assembler instructions together in a single +`asm' template, separated either with newlines (written as `\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 `_foo' accepts arguments in registers 9 and 10: + + asm ("movl %0,r9;movl %1,r10;call _foo" + : /* no outputs */ + : "g" (from), "g" (to) + : "r9", "r10"); + + If you want to test the condition code produced by an assembler +instruction, you must include a branch and a label in the `asm' +construct, as follows: + + asm ("clr %0;frob %1;beq 0f;mov #1,%0;0:" + : "g" (result) + : "g" (input)); + +This assumes your assembler supports local labels, as the GNU +assembler and most Unix assemblers do. + + Usually the most convenient way to use these `asm' instructions is +to encapsulate them in macros that look like functions. For example, + + #define sin(x) \ + ({ double __value, __arg = (x); \ + asm ("fsinx %1,%0": "=f" (__value): "f" (__arg)); \ + __value; }) + +Here the variable `__arg' is used to make sure that the instruction +operates on a proper `double' value, and to accept only those +arguments `x' which can convert automatically to a `double'. + + Another way to make sure the instruction operates on the correct +data type is to use a cast in the `asm'. This is different from +using a variable `__arg' in that it converts more different types. +For example, if the desired type were `int', casting the argument to +`int' would accept a pointer with no complaint, while assigning the +argument to an `int' variable named `__arg' would warn about using a +pointer unless the caller explicitly casts it. + + If an `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. + + You can prevent an `asm' instruction from being deleted, moved or +combined by writing the keyword `volatile' after the `asm'. For +example: + + #define set_priority(x) \ + asm volatile ("set_priority %0": /* no outputs */ : "g" (x)) + +(However, an instruction without output operands will not be deleted +or moved, regardless, unless it is unreachable.) + + It is a natural idea to look for a way to give access to the +condition code left by the assembler instruction. However, when we +attempted to implement this, we found no way to make it work +reliably. The problem is that output operands might need reloading, +which would result in additional following "store" instructions. On +most machines, these instructions would alter the condition code +before there was time to test it. This problem doesn't arise for +ordinary "test" and "compare" instructions because they don't have +any output operands. + + If you are writing a header file that should be includable in ANSI +C programs, write `__asm__' instead of `asm'. *Note Alternate +Keywords::. + + +File: gcc.info, Node: Asm Labels, Next: Explicit Reg Vars, Prev: Extended Asm, Up: Extensions + +Controlling Names Used in Assembler Code +======================================== + + You can specify the name to be used in the assembler code for a C +function or variable by writing the `asm' (or `__asm__') keyword +after the declarator as follows: + + int foo asm ("myfoo") = 2; + +This specifies that the name to be used for the variable `foo' in the +assembler code should be `myfoo' rather than the usual `_foo'. + + On systems where an underscore is normally prepended to the name +of a C function or variable, this feature allows you to define names +for the linker that do not start with an underscore. + + You cannot use `asm' in this way in a function *definition*; but +you can get the same effect by writing a declaration for the function +before its definition and putting `asm' there, like this: + + extern func () asm ("FUNC"); + + func (x, y) + int x, y; + ... + + It is up to you to make sure that the assembler names you choose +do not conflict with any other assembler symbols. Also, you must not +use a register name; that would produce completely invalid assembler +code. GNU CC does not as yet have the ability to store static +variables in registers. Perhaps that will be added. + + +File: gcc.info, Node: Explicit Reg Vars, Next: Alternate Keywords, Prev: Asm Labels, Up: Extensions + +Variables in Specified Registers +================================ + + GNU C allows you to put a few global variables into specified +hardware registers. You can also specify the register in which an +ordinary register variable should be allocated. + + * Global register variables reserve registers throughout the + program. This may be useful in programs such as programming + language interpreters which have a couple of global variables + that are accessed very often. + + * Local register variables in specific registers do not reserve + the registers. The compiler's data flow analysis is capable of + determining where the specified registers contain live values, + and where they are available for other uses. These local + variables are sometimes convenient for use with the extended + `asm' feature (*note Extended Asm::.). + +* Menu: + +* Global Reg Vars:: +* Local Reg Vars:: + + +File: gcc.info, Node: Global Reg Vars, Next: Local Reg Vars, Prev: Explicit Reg Vars, Up: Explicit Reg Vars + +Defining Global Register Variables +---------------------------------- + + You can define a global register variable in GNU C like this: + + register int *foo asm ("a5"); + +Here `a5' is the name of the register which should be used. Choose a +register which is normally saved and restored by function calls on +your machine, so that library routines will not clobber it. + + Naturally the register name is cpu-dependent, so you would need to +conditionalize your program according to cpu type. The register `a5' +would be a good choice on a 68000 for a variable of pointer type. On +machines with register windows, be sure to choose a "global" register +that is not affected magically by the function call mechanism. + + 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 `%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 a global register variable in a certain register reserves +that register entirely for this use, at least within the current +compilation. The register will not be allocated for any other +purpose in the functions in the current compilation. The register +will not be saved and restored by these functions. Stores into this +register are never deleted even if they would appear to be dead, but +references may be deleted or moved or simplified. + + It is not safe to access the global register variables from signal +handlers, or from more than one thread of control, because the system +library routines may temporarily use the register for other things +(unless you recompile them specially for the task at hand). + + It is not safe for one function that uses a global register +variable to call another such function `foo' by way of a third +function `lose' that was compiled without knowledge of this variable +(i.e. in a different source file in which the variable wasn't +declared). This is because `lose' might save the register and put +some other value there. For example, you can't expect a global +register variable to be available in the comparison-function that you +pass to `qsort', since `qsort' might have put something else in that +register. (If you are prepared to recompile `qsort' with the same +global register variable, you can solve this problem.) + + If you want to recompile `qsort' or other source files which do +not actually use your global register variable, so that they will not +use that register for any other purpose, then it suffices to specify +the compiler option `-ffixed-REG'. You need not actually add a +global register declaration to their source code. + + A function which can alter the value of a global register variable +cannot safely be called from a function compiled without this +variable, because it could clobber the value the caller expects to +find there on return. Therefore, the function which is the entry +point into the part of the program that uses the global register +variable must explicitly save and restore the value which belongs to +its caller. + + On most machines, `longjmp' will restore to each global register +variable the value it had at the time of the `setjmp'. On some +machines, however, `longjmp' will not change the value of global +register variables. To be portable, the function that called +`setjmp' should make other arrangements to save the values of the +global register variables, and to restore them in a `longjmp'. This +way, the same thing will happen regardless of what `longjmp' does. + + All global register variable declarations must precede all +function definitions. If such a declaration could appear after +function definitions, the declaration would be too late to prevent +the register from being used for other purposes in the preceding +functions. + + Global register variables may not have initial values, because an +executable file has no means to supply initial contents for a register. + + +File: gcc.info, Node: Local Reg Vars, Prev: Global Reg Vars, Up: Explicit Reg Vars + +Specifying Registers for Local Variables +---------------------------------------- + + You can define a local register variable with a specified register +like this: + + register int *foo asm ("a5"); + +Here `a5' is the name of the register which should be used. Note +that this is the same syntax used for defining global register +variables, but for a local variable it would appear within a function. + + Naturally the register name is cpu-dependent, but this is not a +problem, since specific registers are most often useful with explicit +assembler instructions (*note Extended Asm::.). Both of these things +generally require that you conditionalize your program according to +cpu type. + + 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 `%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. + + +File: gcc.info, Node: Alternate Keywords, Prev: Explicit Reg Vars, Up: Extensions + +Alternate Keywords +================== + + The option `-traditional' disables certain keywords; `-ansi' +disables certain others. This causes trouble when you want to use +GNU C extensions, or ANSI C features, in a general-purpose header +file that should be usable by all programs, including ANSI C programs +and traditional ones. The keywords `asm', `typeof' and `inline' +cannot be used since they won't work in a program compiled with +`-ansi', while the keywords `const', `volatile', `signed', `typeof' +and `inline' won't work in a program compiled with `-traditional'. + + The way to solve these problems is to put `__' at the beginning +and end of each problematical keyword. For example, use `__asm__' +instead of `asm', `__const__' instead of `const', and `__inline__' +instead of `inline'. + + Other C compilers won't accept these alternative keywords; if you +want to compile with another compiler, you can define the alternate +keywords as macros to replace them with the customary keywords. It +looks like this: + + #ifndef __GNUC__ + #define __asm__ asm + #endif + + +File: gcc.info, Node: Bugs, Next: Portability, Prev: Extensions, Up: Top + +Reporting Bugs +************** + + Your bug reports play an essential role in making GNU CC reliable. + + When you encounter a problem, the first thing to do is to see if +it is already known. *Note Trouble::. Also look in *Note +Incompatibilities::. If it isn't known, then you should report the +problem. + + Reporting a bug may help you by bringing a solution to your +problem, or it may not. (If it does not, look in the service +directory; see *Note Service::.) In any case, the principal function +of a bug report is to help the entire community by making the next +version of GNU CC work better. Bug reports are your contribution to +the maintenance of GNU CC. + + 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? +* Reporting: Bug Reporting. How to report a bug effectively. + + +File: gcc.info, Node: Bug Criteria, Next: Bug Reporting, Prev: Bugs, Up: Bugs + +Have You Found a Bug? +===================== + + If you are not sure whether you have found a bug, here are some +guidelines: + + * If the compiler gets a fatal signal, for any input whatever, + that is a compiler bug. Reliable compilers never crash. + + * If the compiler produces invalid assembly code, for any input + whatever (except an `asm' statement), that is a compiler bug, + unless the compiler reports errors (not just warnings) which + would ordinarily prevent the assembler from being run. + + * 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 may + have run into an incompatibility between GNU C and traditional C + (*note Incompatibilities::.). These incompatibilities might be + considered bugs, but they are inescapable consequences of + valuable features. + + Or you may have a program whose behavior is undefined, which + happened by chance to give the desired results with another C + compiler. + + For example, in many nonoptimizing compilers, you can write `x;' + at the end of a function instead of `return x;', with the same + results. But the value of the function is undefined if `return' + is omitted; it is not a bug when GNU CC produces different + results. + + Problems often result from expressions with two increment + operators, as in `f (*p++, *p++)'. Your previous compiler might + have interpreted that expression the way you intended; GNU CC + might interpret it another way. Neither compiler is wrong. The + bug is in your code. + + 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. + + * If the compiler produces an error message for valid input, that + is a compiler bug. + + Note that the following is not valid input, and the error + message for it is not a bug: + + int foo (char); + + int + foo (x) + char x; + { ... } + + The prototype says to pass a `char', while the definition says + to pass an `int' and treat the value as a `char'. This is what + the ANSI standard says, and it makes sense. + + * 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 my idea of "an extension" + or "support for traditional practice". + + * If you are an experienced user of C compilers, your suggestions + for improvement of GNU CC are welcome in any case. + + \ No newline at end of file diff --git a/gcc-1.40/gcc.info-5 b/gcc-1.40/gcc.info-5 new file mode 100644 index 0000000..cbf4147 --- /dev/null +++ b/gcc-1.40/gcc.info-5 @@ -0,0 +1,1117 @@ +Info file gcc.info, produced by Makeinfo, -*- Text -*- from input +file gcc.texinfo. + + This file documents the use and the internals of the GNU compiler. + + Copyright (C) 1988, 1989, 1990 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. + + 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" and "Protect +Your Freedom--Fight `Look And Feel'" 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" and "Protect Your Freedom--Fight `Look And Feel'" and this +permission notice may be included in translations approved by the +Free Software Foundation instead of in the original English. + + +File: gcc.info, Node: Bug Reporting, Prev: Bug Criteria, Up: Bugs + +How to Report Bugs +================== + + Send bug reports for GNU C to one of these addresses: + + bug-gcc@prep.ai.mit.edu + {ucbvax|mit-eddie|uunet}!prep.ai.mit.edu!bug-gcc + + *Do not send bug reports to `help-gcc', or to the newsgroup +`gnu.gcc.help'.* Most users of GNU CC do not want to receive bug +reports. Those that do, have asked to be on `bug-gcc'. + + The mailing list `bug-gcc' has a newsgroup which serves as a +repeater. The mailing list and the newsgroup carry exactly the same +messages. 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 crucial: a newsgroup posting does not contain a +mail path back to the sender. Thus, if I need to ask for more +information, I may be unable to reach you. For this reason, it is +better to send bug reports to the mailing list. + + As a last resort, send bug reports on paper to: + + GNU Compiler Bugs + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + + The fundamental principle of reporting bugs usefully is this: +*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 me 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?" Those bug reports are useless, and I urge everyone to +*refuse to respond to them* except to chide the sender to report bugs +properly. + + To enable me to fix the bug, you should include all these things: + + * The version of GNU CC. You can get this by running it with the + `-v' option. + + Without this, I won't know whether there is any point in looking + for the bug in the current version of GNU CC. + + * A complete input file that will reproduce the bug. If the bug + is in the C preprocessor, send me a source file and any header + files that it requires. If the bug is in the compiler proper + (`cc1'), run your source file through the C preprocessor by + doing `gcc -E SOURCEFILE > OUTFILE', then include the contents + of OUTFILE in the bug report. (Any `-I', `-D' or `-U' options + that you used in actual compilation should also be used when + doing this.) + + A single statement is not enough of an example. In order to + compile it, it must be embedded in a function definition; and + the bug might depend on the details of how this is done. + + Without a real example I can compile, all I 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. + + * The command arguments you gave GNU CC to compile that example + and observe the bug. For example, did you use `-O'? To + guarantee you won't omit something important, list them all. + + If I were to try to guess the arguments, I would probably guess + wrong and then I would not encounter the bug. + + * The names of the files that you used for `tm.h' and `md' when + you installed the compiler. + + * The type of machine you are using, and the operating system name + and version number. + + * A description of what behavior you observe that you believe is + incorrect. For example, "It gets a fatal signal," or, "There is + an incorrect assembler instruction in the output." + + Of course, if the bug is that the compiler gets a fatal signal, + then I will certainly notice it. But if the bug is incorrect + output, I might not notice unless it is glaringly wrong. I + won't study all the assembler code from a 50-line C program just + on the off chance that it might be wrong. + + 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 mine would not. If you + told me to expect a crash, then when mine fails to crash, I + would know that the bug was not happening for me. If you had + not told me to expect a crash, then I would not be able to draw + any conclusion from my observations. + + Often the observed symptom is incorrect output when your program + is run. Sad to say, this is not enough information for me + unless the program is short and simple. If you send me a large + program, I don't have time 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 me which source line + it is, and what incorrect result happens when that line is + executed. A person who understands the test program can find + this as easily as a bug in the program itself. + + * If you send me examples of output from GNU CC, please use `-g' + when you make them. The debugging information includes source + line numbers which are essential for correlating the output with + the input. + + * If you wish to suggest changes to the GNU CC source, send me + context diffs. If you even discuss something in the GNU CC + source, refer to it by context, not by line number. + + The line numbers in my development sources don't match those in + your sources. Your line numbers would convey no useful + information to me. + + * Additional information from a debugger might enable me to find a + problem on a machine which I do not have available myself. + However, you need to think when you collect this information if + you want it to have any chance of being useful. + + For example, many people send just a backtrace, but that is + never useful by itself. A simple backtrace with arguments + conveys little about GNU CC 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. + + 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 `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 `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. + + In addition, include a debugging dump from just before the pass + in which the crash happens. Most bugs involve a series of + insns, not just one. + + Here are some things that are not necessary: + + * 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 I will find the bug is by running a single example under the + debugger with breakpoints, not by pure deduction from a series + of examples. I recommend that you save your time for something + else. + + Of course, if you can find a simpler example to report *instead* + of the original one, that is a convenience for me. Errors in + the output will be easier to spot, running under the debugger + will take less time, etc. Most GNU CC 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 may 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 me the entire test case you + used. + + * A patch for the bug. + + A patch for the bug does help me 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 I need. I might see problems + with your patch and decide to fix the problem another way, or I + might not understand it at all. + + Sometimes with a program as complicated as GNU CC 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 me the + example, I won't be able to construct one, so I won't be able to + verify that the bug is fixed. + + And if I can't understand what bug you are trying to fix, or why + your patch should be an improvement, I won't install it. A test + case will help me to understand. + + * A guess about what the bug is or what it depends on. + + Such guesses are usually wrong. Even I can't guess right about + such things without first using the debugger to find the facts. + + +File: gcc.info, Node: Portability, Next: Interface, Prev: Bugs, Up: Top + +GNU CC and Portability +********************** + + The main goal of GNU CC was to make a good, fast compiler for +machines in the class that the GNU system aims to run on: 32-bit +machines that address 8-bit bytes and have several general registers. +Elegance, theoretical power and simplicity are only secondary. + + GNU CC gets most of the information about the target machine from +a machine description which gives an algebraic formula for each of +the machine's instructions. This is a very clean way to describe the +target. But when the compiler needs information that is difficult to +express in this fashion, I have not hesitated to define an ad-hoc +parameter to the machine description. The purpose of portability is +to reduce the total work needed on the compiler; it was not of +interest for its own sake. + + GNU CC does not contain machine dependent code, but it does +contain code that depends on machine parameters such as endianness +(whether the most significant byte has the highest or lowest address +of the bytes in a word) and the availability of autoincrement +addressing. In the RTL-generation pass, it is often necessary to +have multiple strategies for generating code for a particular kind of +syntax tree, strategies that are usable for different combinations of +parameters. Often I have not tried to address all possible cases, +but only the common ones or only the ones that I have encountered. +As a result, a new target may require additional strategies. You +will know if this happens because the compiler will call `abort'. +Fortunately, the new strategies can be added in a machine-independent +fashion, and will affect only the target machines that need them. + + +File: gcc.info, Node: Interface, Next: Passes, Prev: Portability, Up: Top + +Interfacing to GNU CC Output +**************************** + + GNU CC is normally configured to use the same function calling +convention normally in use on the target system. This is done with +the machine-description macros described (*note Machine Macros::.). + + However, returning of structure and union values is done +differently on some target machines. As a result, functions compiled +with PCC returning such types cannot be called from code compiled +with GNU CC, and vice versa. This does not cause trouble often +because few Unix library routines return structures or unions. + + GNU CC code returns structures and unions that are 1, 2, 4 or 8 +bytes long in the same registers used for `int' or `double' return +values. (GNU CC typically allocates variables of such types in +registers also.) Structures and unions of other sizes are returned +by storing them into an address passed by the caller (usually in a +register). The machine-description macros `STRUCT_VALUE' and +`STRUCT_INCOMING_VALUE' tell GNU CC where to pass this address. + + By contrast, PCC on most target machines returns structures and +unions of any size by copying the data into an area of static +storage, and then returning the address of that storage as if it were +a pointer value. The caller must copy the data from that memory area +to the place where the value is wanted. This is slower than the +method used by GNU CC, and fails to be reentrant. + + On some target machines, such as RISC machines and the 80386, the +standard system convention is to pass to the subroutine the address +of where to return the value. On these machines, GNU CC has been +configured to be compatible with the standard compiler, when this +method is used. It may not be compatible for structures of 1, 2, 4 +or 8 bytes. + + GNU CC uses the system's standard convention for passing +arguments. On some machines, the first few arguments are passed in +registers; in others, all are passed on the stack. It would be +possible to use registers for argument passing on any machine, and +this would probably result in a significant speedup. But the result +would be complete incompatibility with code that follows the standard +convention. So this change is practical only if you are switching to +GNU CC as the sole C compiler for the system. We may implement +register argument passing on certain machines once we have a complete +GNU system so that we can compile the libraries with GNU CC. + + If you use `longjmp', beware of automatic variables. ANSI C says +that automatic variables that are not declared `volatile' have +undefined values after a `longjmp'. And this is all GNU CC promises +to do, because it is very difficult to restore register variables +correctly, and one of GNU CC's features is that it can put variables +in registers without your asking it to. + + If you want a variable to be unaltered by `longjmp', and you don't +want to write `volatile' because old C compilers don't accept it, +just take the address of the variable. If a variable's address is +ever taken, even if just to compute it and ignore it, then the +variable cannot go in a register: + + { + int careful; + &careful; + ... + } + + Code compiled with GNU CC may call certain library routines. Most +of them handle arithmetic for which there are no instructions. This +includes multiply and divide on some machines, and floating point +operations on any machine for which floating point support is +disabled with `-msoft-float'. Some standard parts of the C library, +such as `bcopy' or `memcpy', are also called automatically. The +usual function call interface is used for calling the library routines. + + These library routines should be defined in the library `gnulib', +which GNU CC automatically searches whenever it links a program. On +machines that have multiply and divide instructions, if hardware +floating point is in use, normally `gnulib' is not needed, but it is +searched just in case. + + Each arithmetic function is defined in `gnulib.c' to use the +corresponding C arithmetic operator. As long as the file is compiled +with another C compiler, which supports all the C arithmetic +operators, this file will work portably. However, `gnulib.c' does +not work if compiled with GNU CC, because each arithmetic function +would compile into a call to itself! + + +File: gcc.info, Node: Passes, Next: RTL, Prev: Interface, Up: Top + +Passes and Files of the Compiler +******************************** + + The overall control structure of the compiler is in `toplev.c'. +This file is responsible for initialization, decoding arguments, +opening and closing files, and sequencing the passes. + + The parsing pass is invoked only once, to parse the entire input. +The RTL intermediate code for a function is generated as the function +is parsed, a statement at a time. Each statement is read in as a +syntax tree and then converted to RTL; then the storage for the tree +for the statement is reclaimed. Storage for types (and the +expressions for their sizes), declarations, and a representation of +the binding contours and how they nest, remains until the function is +finished being compiled; these are all needed to output the debugging +information. + + Each time the parsing pass reads a complete function definition or +top-level declaration, it calls the function `rest_of_compilation' or +`rest_of_decl_compilation' in `toplev.c', which are responsible for +all further processing necessary, ending with output of the assembler +language. All other compiler passes run, in sequence, within +`rest_of_compilation'. When that function returns from compiling a +function definition, the storage used for that function definition's +compilation is entirely freed, unless it is an inline function (*note +Inline::.). + + Here is a list of all the passes of the compiler and their source +files. Also included is a description of where debugging dumps can +be requested with `-d' options. + + * Parsing. This pass reads the entire text of a function + definition, constructing partial syntax trees. This and RTL + generation are no longer truly separate passes (formerly they + were), but it is easier to think of them as separate. + + The tree representation does not entirely follow C syntax, + because it is intended to support other languages as well. + + C data type analysis is also done in this pass, and every tree + node that represents an expression has a data type attached. + Variables are represented as declaration nodes. + + Constant folding and associative-law simplifications are also + done during this pass. + + The source files for parsing are `c-parse.y', `c-decl.c', + `c-typeck.c', `c-convert.c', `stor-layout.c', `fold-const.c', + and `tree.c'. The last three files are intended to be + language-independent. There are also header files `c-parse.h', + `c-tree.h', `tree.h' and `tree.def'. The last two define the + format of the tree representation. + + * RTL generation. This is the conversion of syntax tree into RTL + code. It is actually done statement-by-statement during + parsing, but for most purposes it can be thought of as a + separate pass. + + This is where the bulk of target-parameter-dependent code is + found, since often it is necessary for strategies to apply only + when certain standard kinds of instructions are available. The + purpose of named instruction patterns is to provide this + information to the RTL generation pass. + + Optimization is done in this pass for `if'-conditions that are + comparisons, boolean operations or conditional expressions. + Tail recursion is detected at this time also. Decisions are + made about how best to arrange loops and how to output `switch' + statements. + + The source files for RTL generation are `stmt.c', `expr.c', + `explow.c', `expmed.c', `optabs.c' and `emit-rtl.c'. Also, the + file `insn-emit.c', generated from the machine description by + the program `genemit', is used in this pass. The header files + `expr.h' is used for communication within this pass. + + The header files `insn-flags.h' and `insn-codes.h', generated + from the machine description by the programs `genflags' and + `gencodes', tell this pass which standard names are available + for use and which patterns correspond to them. + + Aside from debugging information output, none of the following + passes refers to the tree structure representation of the + function (only part of which is saved). + + The decision of whether the function can and should be expanded + inline in its subsequent callers is made at the end of rtl + generation. The function must meet certain criteria, currently + related to the size of the function and the types and number of + parameters it has. Note that this function may contain loops, + recursive calls to itself (tail-recursive functions can be + inlined!), gotos, in short, all constructs supported by GNU CC. + + The option `-dr' causes a debugging dump of the RTL code after + this pass. This dump file's name is made by appending `.rtl' to + the input file name. + + * Jump optimization. This pass simplifies jumps to the following + instruction, jumps across jumps, and jumps to jumps. It deletes + unreferenced labels and unreachable code, except that + unreachable code that contains a loop is not recognized as + unreachable in this pass. (Such loops are deleted later in the + basic block analysis.) + + Jump optimization is performed two or three times. The first + time is immediately following RTL generation. The second time + is after CSE, but only if CSE says repeated jump optimization is + needed. The last time is right before the final pass. That + time, cross-jumping and deletion of no-op move instructions are + done together with the optimizations described above. + + The source file of this pass is `jump.c'. + + The option `-dj' causes a debugging dump of the RTL code after + this pass is run for the first time. This dump file's name is + made by appending `.jump' to the input file name. + + * Register scan. This pass finds the first and last use of each + register, as a guide for common subexpression elimination. Its + source is in `regclass.c'. + + * Common subexpression elimination. This pass also does constant + propagation. Its source file is `cse.c'. If constant + propagation causes conditional jumps to become unconditional or + to become no-ops, jump optimization is run again when CSE is + finished. + + The option `-ds' causes a debugging dump of the RTL code after + this pass. This dump file's name is made by appending `.cse' to + the input file name. + + * Loop optimization. This pass moves constant expressions out of + loops, and optionally does strength-reduction as well. Its + source file is `loop.c'. + + The option `-dL' causes a debugging dump of the RTL code after + this pass. This dump file's name is made by appending `.loop' + to the input file name. + + * Stupid register allocation is performed at this point in a + nonoptimizing compilation. It does a little data flow analysis + as well. When stupid register allocation is in use, the next + pass executed is the reloading pass; the others in between are + skipped. The source file is `stupid.c'. + + * Data flow analysis (`flow.c'). This pass divides the program + into basic blocks (and in the process deletes unreachable + loops); then it computes which pseudo-registers are live at each + point in the program, and makes the first instruction that uses + a value point at the instruction that computed the value. + + This pass also deletes computations whose results are never + used, and combines memory references with add or subtract + instructions to make autoincrement or autodecrement addressing. + + The option `-df' causes a debugging dump of the RTL code after + this pass. This dump file's name is made by appending `.flow' + to the input file name. If stupid register allocation is in + use, this dump file reflects the full results of such allocation. + + * Instruction combination (`combine.c'). This pass attempts to + combine groups of two or three instructions that are related by + data flow into single instructions. It combines the RTL + expressions for the instructions by substitution, simplifies the + result using algebra, and then attempts to match the result + against the machine description. + + The option `-dc' causes a debugging dump of the RTL code after + this pass. This dump file's name is made by appending + `.combine' to the input file name. + + * Register class preferencing. The RTL code is scanned to find + out which register class is best for each pseudo register. The + source file is `regclass.c'. + + * Local register allocation (`local-alloc.c'). This pass + allocates hard registers to pseudo registers that are used only + within one basic block. Because the basic block is linear, it + can use fast and powerful techniques to do a very good job. + + The option `-dl' causes a debugging dump of the RTL code after + this pass. This dump file's name is made by appending `.lreg' + to the input file name. + + * Global register allocation (`global-alloc.c'). This pass + allocates hard registers for the remaining pseudo registers + (those whose life spans are not contained in one basic block). + + * Reloading. This pass renumbers pseudo registers with the + hardware registers numbers they were allocated. Pseudo + registers that did not get hard registers are replaced with + stack slots. Then it finds instructions that are invalid + because a value has failed to end up in a register, or has ended + up in a register of the wrong kind. It fixes up these + instructions by reloading the problematical values temporarily + into registers. Additional instructions are generated to do the + copying. + + Source files are `reload.c' and `reload1.c', plus the header + `reload.h' used for communication between them. + + The option `-dg' causes a debugging dump of the RTL code after + this pass. This dump file's name is made by appending `.greg' + to the input file name. + + * Jump optimization is repeated, this time including cross-jumping + and deletion of no-op move instructions. + + The option `-dJ' causes a debugging dump of the RTL code after + this pass. This dump file's name is made by appending `.jump2' + to the input file name. + + * Delayed branch scheduling may be done at this point. The source + file name is `dbranch.c'. + + The option `-dd' causes a debugging dump of the RTL code after + this pass. This dump file's name is made by appending `.dbr' to + the input file name. + + * Final. This pass outputs the assembler code for the function. + It is also responsible for identifying spurious test and compare + instructions. Machine-specific peephole optimizations are + performed at the same time. The function entry and exit + sequences are generated directly as assembler code in this pass; + they never exist as RTL. + + The source files are `final.c' plus `insn-output.c'; the latter + is generated automatically from the machine description by the + tool `genoutput'. The header file `conditions.h' is used for + communication between these files. + + * Debugging information output. This is run after final because + it must output the stack slot offsets for pseudo registers that + did not get hard registers. Source files are `dbxout.c' for DBX + symbol table format and `symout.c' for GDB's own symbol table + format. + + Some additional files are used by all or many passes: + + * Every pass uses `machmode.def', which defines the machine modes. + + * All the passes that work with RTL use the header files `rtl.h' + and `rtl.def', and subroutines in file `rtl.c'. The tools + `gen*' also use these files to read and work with the machine + description RTL. + + * Several passes refer to the header file `insn-config.h' which + contains a few parameters (C macro definitions) generated + automatically from the machine description RTL by the tool + `genconfig'. + + * Several passes use the instruction recognizer, which consists of + `recog.c' and `recog.h', plus the files `insn-recog.c' and + `insn-extract.c' that are generated automatically from the + machine description by the tools `genrecog' and `genextract'. + + * Several passes use the header files `regs.h' which defines the + information recorded about pseudo register usage, and + `basic-block.h' which defines the information recorded about + basic blocks. + + * `hard-reg-set.h' defines the type `HARD_REG_SET', a bit-vector + with a bit for each hard register, and some macros to manipulate + it. This type is just `int' if the machine has few enough hard + registers; otherwise it is an array of `int' and some of the + macros expand into loops. + + +File: gcc.info, Node: RTL, Next: Machine Desc, Prev: Passes, Up: Top + +RTL Representation +****************** + + Most of the work of the compiler is done on an intermediate +representation called register transfer language. In this language, +the instructions to be output are described, pretty much one by one, +in an algebraic form that describes what the instruction does. + + RTL is inspired by Lisp lists. It has both an internal form, made +up of structures that point at other structures, and a textual form +that is used in the machine description and in printed debugging +dumps. The textual form uses nested parentheses to indicate the +pointers in the internal form. + +* Menu: + +* RTL Objects:: Expressions vs vectors vs strings vs integers. +* Accessors:: Macros to access expression operands or vector elts. +* Flags:: Other flags in an RTL expression. +* Machine Modes:: Describing the size and format of a datum. +* Constants:: Expressions with constant values. +* Regs and Memory:: Expressions representing register contents or memory. +* Arithmetic:: Expressions representing arithmetic on other expressions. +* Comparisons:: Expressions representing comparison of expressions. +* Bit Fields:: Expressions representing bit-fields in memory or reg. +* Conversions:: Extending, truncating, floating or fixing. +* RTL Declarations:: Declaring volatility, constancy, etc. +* Side Effects:: Expressions for storing in registers, etc. +* Incdec:: Embedded side-effects for autoincrement addressing. +* Assembler:: Representing `asm' with operands. +* Insns:: Expression types for entire insns. +* Calls:: RTL representation of function call insns. +* Sharing:: Some expressions are unique; others *must* be copied. + + +File: gcc.info, Node: RTL Objects, Next: Accessors, Prev: RTL, Up: RTL + +RTL Object Types +================ + + RTL uses four kinds of objects: expressions, integers, strings and +vectors. Expressions are the most important ones. An RTL expression +("RTX", for short) is a C structure, but it is usually referred to +with a pointer; a type that is given the typedef name `rtx'. + + An integer is simply an `int', and a string is a `char *'. Within +RTL code, strings appear only inside `symbol_ref' expressions, but +they appear in other contexts in the RTL expressions that make up +machine descriptions. Their written form uses decimal digits. + + A string is a sequence of characters. In core it is represented +as a `char *' in usual C fashion, and it is written in C syntax as +well. However, strings in RTL may never be null. If you write an +empty string in a machine description, it is represented in core as a +null pointer rather than as a pointer to a null character. In +certain contexts, these null pointers instead of strings are valid. + + A vector contains an arbitrary, specified number of pointers to +expressions. The number of elements in the vector is explicitly +present in the vector. The written form of a vector consists of +square brackets (`[...]') surrounding the elements, in sequence and +with whitespace separating them. Vectors of length zero are not +created; null pointers are used instead. + + Expressions are classified by "expression codes" (also called RTX +codes). The expression code is a name defined in `rtl.def', which is +also (in upper case) a C enumeration constant. The possible +expression codes and their meanings are machine-independent. The +code of an RTX can be extracted with the macro `GET_CODE (X)' and +altered with `PUT_CODE (X, NEWCODE)'. + + The expression code determines how many operands the expression +contains, and what kinds of objects they are. In RTL, unlike Lisp, +you cannot tell by looking at an operand what kind of object it is. +Instead, you must know from its context--from the expression code of +the containing expression. For example, in an expression of code +`subreg', the first operand is to be regarded as an expression and +the second operand as an integer. In an expression of code `plus', +there are two operands, both of which are to be regarded as +expressions. In a `symbol_ref' expression, there is one operand, +which is to be regarded as a string. + + Expressions are written as parentheses containing the name of the +expression type, its flags and machine mode if any, and then the +operands of the expression (separated by spaces). + + Expression code names in the `md' file are written in lower case, +but when they appear in C code they are written in upper case. In +this manual, they are shown as follows: `const_int'. + + In a few contexts a null pointer is valid where an expression is +normally wanted. The written form of this is `(nil)'. + + +File: gcc.info, Node: Accessors, Next: Flags, Prev: RTL Objects, Up: RTL + +Access to Operands +================== + + For each expression type `rtl.def' specifies the number of +contained objects and their kinds, with four possibilities: `e' for +expression (actually a pointer to an expression), `i' for integer, +`s' for string, and `E' for vector of expressions. The sequence of +letters for an expression code is called its "format". Thus, the +format of `subreg' is `ei'. + + Two other format characters are used occasionally: `u' and `0'. +`u' is equivalent to `e' except that it is printed differently in +debugging dumps, and `0' means a slot whose contents do not fit any +normal category. `0' slots are not printed at all in dumps, and are +often used in special ways by small parts of the compiler. + + There are macros to get the number of operands and the format of +an expression code: + +`GET_RTX_LENGTH (CODE)' + Number of operands of an RTX of code CODE. + +`GET_RTX_FORMAT (CODE)' + The format of an RTX of code CODE, as a C string. + + Operands of expressions are accessed using the macros `XEXP', +`XINT' and `XSTR'. Each of these macros takes two arguments: an +expression-pointer (RTX) and an operand number (counting from zero). +Thus, + + XEXP (X, 2) + +accesses operand 2 of expression X, as an expression. + + XINT (X, 2) + +accesses the same operand as an integer. `XSTR', used in the same +fashion, would access it as a string. + + Any operand can be accessed as an integer, as an expression or as +a string. You must choose the correct method of access for the kind +of value actually stored in the operand. You would do this based on +the expression code of the containing expression. That is also how +you would know how many operands there are. + + For example, if X is a `subreg' expression, you know that it has +two operands which can be correctly accessed as `XEXP (X, 0)' and +`XINT (X, 1)'. If you did `XINT (X, 0)', you would get the address +of the expression operand but cast as an integer; that might +occasionally be useful, but it would be cleaner to write `(int) XEXP +(X, 0)'. `XEXP (X, 1)' would also compile without error, and would +return the second, integer operand cast as an expression pointer, +which would probably result in a crash when accessed. Nothing stops +you from writing `XEXP (X, 28)' either, but this will access memory +past the end of the expression with unpredictable results. + + Access to operands which are vectors is more complicated. You can +use the macro `XVEC' to get the vector-pointer itself, or the macros +`XVECEXP' and `XVECLEN' to access the elements and length of a vector. + +`XVEC (EXP, IDX)' + Access the vector-pointer which is operand number IDX in EXP. + +`XVECLEN (EXP, IDX)' + Access the length (number of elements) in the vector which is in + operand number IDX in EXP. This value is an `int'. + +`XVECEXP (EXP, IDX, ELTNUM)' + Access element number ELTNUM in the vector which is in operand + number IDX in EXP. This value is an RTX. + + It is up to you to make sure that ELTNUM is not negative and is + less than `XVECLEN (EXP, IDX)'. + + All the macros defined in this section expand into lvalues and +therefore can be used to assign the operands, lengths and vector +elements as well as to access them. + + +File: gcc.info, Node: Flags, Next: Machine Modes, Prev: Accessors, Up: RTL + +Flags in an RTL Expression +========================== + + RTL expressions contain several flags (one-bit bit-fields) that +are used in certain types of expression. Most often they are +accessed with the following macros: + +`EXTERNAL_SYMBOL_P (X)' + In a `symbol_ref' expression, nonzero if it corresponds to a + variable declared extern in the users code. Zero for all other + variables. Stored in the `volatil' field and printed as `/v'. + +`MEM_VOLATILE_P (X)' + In `mem' expressions, nonzero for volatile memory references. + Stored in the `volatil' field and printed as `/v'. + +`MEM_IN_STRUCT_P (X)' + In `mem' expressions, nonzero for reference to an entire + 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 `in_struct' field and printed as `/s'. + +`REG_USER_VAR_P (X)' + In a `reg', nonzero if it corresponds to a variable present in + the user's source code. Zero for temporaries generated + internally by the compiler. Stored in the `volatil' field and + printed as `/v'. + +`REG_FUNCTION_VALUE_P (X)' + Nonzero in a `reg' if it is the place in which this function's + value is going to be returned. (This happens only in a hard + register.) Stored in the `integrated' field and printed as `/i'. + + The same hard register may be used also for collecting the + values of functions called by this one, but + `REG_FUNCTION_VALUE_P' is zero in this kind of use. + +`RTX_UNCHANGING_P (X)' + Nonzero in a `reg' or `mem' if the value is not changed + explicitly by the current function. (If it is a memory + reference then it may be changed by other functions or by + aliasing.) Stored in the `unchanging' field and printed as `/u'. + +`RTX_INTEGRATED_P (INSN)' + Nonzero in an insn if it resulted from an in-line function call. + Stored in the `integrated' field and printed as `/i'. This may + be deleted; nothing currently depends on it. + +`INSN_DELETED_P (INSN)' + In an insn, nonzero if the insn has been deleted. Stored in the + `volatil' field and printed as `/v'. + +`CONSTANT_POOL_ADDRESS_P (X)' + Nonzero in a `symbol_ref' if it refers to part of the current + function's "constants pool". These are addresses close to the + beginning of the function, and GNU CC assumes they can be + addressed directly (perhaps with the help of base registers). + Stored in the `unchanging' field and printed as `/u'. + + These are the fields which the above macros refer to: + +`used' + This flag is used only momentarily, at the end of RTL generation + for a function, to count the number of times an expression + appears in insns. Expressions that appear more than once are + copied, according to the rules for shared structure (*note + Sharing::.). + +`volatil' + This flag is used in `mem',`symbol_ref' and `reg' expressions + and in insns. In RTL dump files, it is printed as `/v'. + + In a `mem' expression, it is 1 if the memory reference is + volatile. Volatile memory references may not be deleted, + reordered or combined. + + In a `reg' expression, it is 1 if the value is a user-level + variable. 0 indicates an internal compiler temporary. + + In a `symbol_ref' expression, it is 1 if the symbol is declared + `extern'. + + In an insn, 1 means the insn has been deleted. + +`in_struct' + This flag is used in `mem' expressions. It is 1 if the memory + datum referred to is all or part of a structure or array; 0 if + it is (or might be) a scalar variable. A reference through a C + pointer has 0 because the pointer might point to a scalar + variable. + + This information allows the compiler to determine something + about possible cases of aliasing. + + In an RTL dump, this flag is represented as `/s'. + +`unchanging' + This flag is used in `reg' and `mem' expressions. 1 means that + the value of the expression never changes (at least within the + current function). + + In an RTL dump, this flag is represented as `/u'. + +`integrated' + In some kinds of expressions, including insns, this flag means + the rtl was produced by procedure integration. + + In a `reg' expression, this flag indicates the register + containing the value to be returned by the current function. On + machines that pass parameters in registers, the same register + number may be used for parameters as well, but this flag is not + set on such uses. + + +File: gcc.info, Node: Machine Modes, Next: Constants, Prev: Flags, Up: RTL + +Machine Modes +============= + + A machine mode describes a size of data object and the +representation used for it. In the C code, machine modes are +represented by an enumeration type, `enum machine_mode', defined in +`machmode.def'. Each RTL expression has room for a machine mode and +so do certain kinds of tree expressions (declarations and types, to +be precise). + + In debugging dumps and machine descriptions, the machine mode of +an RTL expression is written after the expression code with a colon +to separate them. The letters `mode' which appear at the end of each +machine mode name are omitted. For example, `(reg:SI 38)' is a `reg' +expression with machine mode `SImode'. If the mode is `VOIDmode', it +is not written at all. + + Here is a table of machine modes. + +`QImode' + "Quarter-Integer" mode represents a single byte treated as an + integer. + +`HImode' + "Half-Integer" mode represents a two-byte integer. + +`PSImode' + "Partial Single Integer" mode represents an integer which + occupies four bytes but which doesn't really use all four. On + some machines, this is the right mode to use for pointers. + +`SImode' + "Single Integer" mode represents a four-byte integer. + +`PDImode' + "Partial Double Integer" mode represents an integer which + occupies eight bytes but which doesn't really use all eight. On + some machines, this is the right mode to use for certain pointers. + +`DImode' + "Double Integer" mode represents an eight-byte integer. + +`TImode' + "Tetra Integer" (?) mode represents a sixteen-byte integer. + +`SFmode' + "Single Floating" mode represents a single-precision (four byte) + floating point number. + +`DFmode' + "Double Floating" mode represents a double-precision (eight + byte) floating point number. + +`XFmode' + "Extended Floating" mode represents a triple-precision (twelve + byte) floating point number. This mode is used for IEEE + extended floating point. + +`TFmode' + "Tetra Floating" mode represents a quadruple-precision (sixteen + byte) floating point number. + +`BLKmode' + "Block" mode represents values that are aggregates to which none + of the other modes apply. In RTL, only memory references can + have this mode, and only if they appear in string-move or vector + instructions. On machines which have no such instructions, + `BLKmode' will not appear in RTL. + +`VOIDmode' + Void mode means the absence of a mode or an unspecified mode. + For example, RTL expressions of code `const_int' have mode + `VOIDmode' because they can be taken to have whatever mode the + context requires. In debugging dumps of RTL, `VOIDmode' is + expressed by the absence of any mode. + +`EPmode' + "Entry Pointer" mode is intended to be used for function + variables in Pascal and other block structured languages. Such + values contain both a function address and a static chain + pointer for access to automatic variables of outer levels. This + mode is only partially implemented since C does not use it. + +`CSImode, ...' + "Complex Single Integer" mode stands for a complex number + represented as a pair of `SImode' integers. Any of the integer + and floating modes may have `C' prefixed to its name to obtain a + complex number mode. For example, there are `CQImode', + `CSFmode', and `CDFmode'. Since C does not support complex + numbers, these machine modes are only partially implemented. + +`BImode' + This is the machine mode of a bit-field in a structure. It is + used only in the syntax tree, never in RTL, and in the syntax + tree it appears only in declaration nodes. In C, it appears + only in `FIELD_DECL' nodes for structure fields defined with a + bit size. + + The machine description defines `Pmode' as a C macro which expands +into the machine mode used for addresses. Normally this is `SImode'. + + The only modes which a machine description must support are +`QImode', `SImode', `SFmode' and `DFmode'. The compiler will attempt +to use `DImode' for two-word structures and unions, but this can be +prevented by overriding the definition of `MAX_FIXED_MODE_SIZE'. +Likewise, you can arrange for the C type `short int' to avoid using +`HImode'. In the long term it might be desirable to make the set of +available machine modes machine-dependent and eliminate all +assumptions about specific machine modes or their uses from the +machine-independent code of the compiler. + + To help begin this process, the machine modes are divided into +mode classes. These are represented by the enumeration type `enum +mode_class' defined in `rtl.h'. The possible mode classes are: + +`MODE_INT' + Integer modes. By default these are `QImode', `HImode', + `SImode', `DImode', `TImode', and also `BImode'. + +`MODE_FLOAT' + Floating-point modes. By default these are `QFmode', `HFmode', + `SFmode', `DFmode' and `TFmode', but the MC68881 also defines + `XFmode' to be an 80-bit extended-precision floating-point mode. + +`MODE_COMPLEX_INT' + Complex integer modes. By default these are `CQImode', + `CHImode', `CSImode', `CDImode' and `CTImode'. + +`MODE_COMPLEX_FLOAT' + Complex floating-point modes. By default these are `CQFmode', + `CHFmode', `CSFmode', `CDFmode' and `CTFmode', + +`MODE_FUNCTION' + Algol or Pascal function variables including a static chain. + (These are not currently implemented). + +`MODE_RANDOM' + This is a catchall mode class for modes which don't fit into the + above classes. Currently `VOIDmode', `BLKmode' and `EPmode' are + in `MODE_RANDOM'. + + Here are some C macros that relate to machine modes: + +`GET_MODE (X)' + Returns the machine mode of the RTX X. + +`PUT_MODE (X, NEWMODE)' + Alters the machine mode of the RTX X to be NEWMODE. + +`NUM_MACHINE_MODES' + Stands for the number of machine modes available on the target + machine. This is one greater than the largest numeric value of + any machine mode. + +`GET_MODE_NAME (M)' + Returns the name of mode M as a string. + +`GET_MODE_CLASS (M)' + Returns the mode class of mode M. + +`GET_MODE_SIZE (M)' + Returns the size in bytes of a datum of mode M. + +`GET_MODE_BITSIZE (M)' + Returns the size in bits of a datum of mode M. + +`GET_MODE_UNIT_SIZE (M)' + Returns the size in bits of the subunits of a datum of mode M. + This is the same as `GET_MODE_SIZE' except in the case of + complex modes and `EPmode'. For them, the unit size is the size + of the real or imaginary part, or the size of the function + pointer or the context pointer. + + \ No newline at end of file diff --git a/gcc-1.40/gcc.info-6 b/gcc-1.40/gcc.info-6 new file mode 100644 index 0000000..b11bdf0 --- /dev/null +++ b/gcc-1.40/gcc.info-6 @@ -0,0 +1,1162 @@ +Info file gcc.info, produced by Makeinfo, -*- Text -*- from input +file gcc.texinfo. + + This file documents the use and the internals of the GNU compiler. + + Copyright (C) 1988, 1989, 1990 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. + + 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" and "Protect +Your Freedom--Fight `Look And Feel'" 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" and "Protect Your Freedom--Fight `Look And Feel'" and this +permission notice may be included in translations approved by the +Free Software Foundation instead of in the original English. + + +File: gcc.info, Node: Constants, Next: Regs and Memory, Prev: Machine Modes, Up: RTL + +Constant Expression Types +========================= + + The simplest RTL expressions are those that represent constant +values. + +`(const_int I)' + This type of expression represents the integer value I. I is + customarily accessed with the macro `INTVAL' as in `INTVAL + (EXP)', which is equivalent to `XINT (EXP, 0)'. + + There is only one expression object for the integer value zero; + it is the value of the variable `const0_rtx'. Likewise, the + only expression for integer value one is found in `const1_rtx'. + Any attempt to create an expression of code `const_int' and + value zero or one will return `const0_rtx' or `const1_rtx' as + appropriate. + +`(const_double:M I0 I1)' + Represents a 64-bit constant of mode M. All floating point + constants are represented in this way, and so are 64-bit + `DImode' integer constants. + + The two integers I0 and I1 together contain the bits of the + value. If the constant is floating point (either single or + double precision), then they represent a `double'. To convert + them to a `double', do + + union { double d; int i[2];} u; + u.i[0] = CONST_DOUBLE_LOW(x); + u.i[1] = CONST_DOUBLE_HIGH(x); + + and then refer to `u.d'. + + The global variables `dconst0_rtx' and `fconst0_rtx' hold + `const_double' expressions with value 0, in modes `DFmode' and + `SFmode', respectively. The macro `CONST0_RTX (MODE)' refers to + a `const_double' expression with value 0 in mode MODE. The mode + MODE must be of mode class `MODE_FLOAT'. + +`(symbol_ref SYMBOL)' + Represents the value of an assembler label for data. SYMBOL is + a string that describes the name of the assembler label. If it + starts with a `*', the label is the rest of SYMBOL not including + the `*'. Otherwise, the label is SYMBOL, prefixed with `_'. + +`(label_ref LABEL)' + Represents the value of an assembler label for code. It + contains one operand, an expression, which must be a + `code_label' that appears in the instruction sequence to + identify the place where the label should go. + + The reason for using a distinct expression type for code label + references is so that jump optimization can distinguish them. + +`(const EXP)' + Represents a constant that is the result of an assembly-time + arithmetic computation. The operand, EXP, is an expression that + contains only constants (`const_int', `symbol_ref' and + `label_ref' expressions) combined with `plus' and `minus'. + However, not all combinations are valid, since the assembler + cannot do arbitrary arithmetic on relocatable symbols. + + +File: gcc.info, Node: Regs and Memory, Next: Arithmetic, Prev: Constants, Up: RTL + +Registers and Memory +==================== + + Here are the RTL expression types for describing access to machine +registers and to main memory. + +`(reg:M N)' + For small values of the integer N (less than + `FIRST_PSEUDO_REGISTER'), this stands for a reference to machine + register number N: a "hard register". For larger values of N, + it stands for a temporary value or "pseudo register". The + compiler's strategy is to generate code assuming an unlimited + number of such pseudo registers, and later convert them into + hard registers or into memory references. + + The symbol `FIRST_PSEUDO_REGISTER' is defined by the machine + description, since the number of hard registers on the machine + is an invariant characteristic of the machine. Note, however, + that not all of the machine registers must be general registers. + All the machine registers that can be used for storage of data + are given hard register numbers, even those that can be used + only in certain instructions or can hold only certain types of + data. + + Each pseudo register number used in a function's RTL code is + represented by a unique `reg' expression. + + M is the machine mode of the reference. It is necessary because + machines can generally refer to each register in more than one + mode. For example, a register may contain a full word but there + may be instructions to refer to it as a half word or as a single + byte, as well as instructions to refer to it as a floating point + number of various precisions. + + Even for a register that the machine can access in only one + mode, the mode must always be specified. + + A hard register may be accessed in various modes throughout one + function, but each pseudo register is given a natural mode and + is accessed only in that mode. When it is necessary to describe + an access to a pseudo register using a nonnatural mode, a + `subreg' expression is used. + + A `reg' expression with a machine mode that specifies more than + one word of data may actually stand for several consecutive + registers. If in addition the register number specifies a + hardware register, then it actually represents several + consecutive hardware registers starting with the specified one. + + Such multi-word hardware register `reg' expressions must not be + live across the boundary of a basic block. The lifetime + analysis pass does not know how to record properly that several + consecutive registers are actually live there, and therefore + register allocation would be confused. The CSE pass must go out + of its way to make sure the situation does not arise. + +`(subreg:M REG WORDNUM)' + `subreg' expressions are used to refer to a register in a + machine mode other than its natural one, or to refer to one + register of a multi-word `reg' that actually refers to several + registers. + + Each pseudo-register has a natural mode. If it is necessary to + operate on it in a different mode--for example, to perform a + fullword move instruction on a pseudo-register that contains a + single byte--the pseudo-register must be enclosed in a `subreg'. + In such a case, WORDNUM is zero. + + The other use of `subreg' is to extract the individual registers + of a multi-register value. Machine modes such as `DImode' and + `EPmode' indicate values longer than a word, values which + usually require two consecutive registers. To access one of the + registers, use a `subreg' with mode `SImode' and a WORDNUM that + says which register. + + The compilation parameter `WORDS_BIG_ENDIAN', if defined, says + that word number zero is the most significant part; otherwise, + it is the least significant part. + + Between the combiner pass and the reload pass, it is possible to + have a `subreg' which contains a `mem' instead of a `reg' as its + first operand. The reload pass eliminates these cases by + reloading the `mem' into a suitable register. + + Note that it is not valid to access a `DFmode' value in `SFmode' + using a `subreg'. On some machines the most significant part of + a `DFmode' value does not have the same format as a + single-precision floating value. + +`(cc0)' + This refers to the machine's condition code register. It has no + operands and may not have a machine mode. There are two ways to + use it: + + * To stand for a complete set of condition code flags. This + is best on most machines, where each comparison sets the + entire series of flags. + + With this technique, `(cc0)' may be validly used in only + two contexts: as the destination of an assignment (in test + and compare instructions) and in comparison operators + comparing against zero (`const_int' with value zero; that + is to say, `const0_rtx'). + + * To stand for a single flag that is the result of a single + condition. This is useful on machines that have only a + single flag bit, and in which comparison instructions must + specify the condition to test. + + With this technique, `(cc0)' may be validly used in only + two contexts: as the destination of an assignment (in test + and compare instructions) where the source is a comparison + operator, and as the first operand of `if_then_else' (in a + conditional branch). + + There is only one expression object of code `cc0'; it is the + value of the variable `cc0_rtx'. Any attempt to create an + expression of code `cc0' will return `cc0_rtx'. + + One special thing about the condition code register is that + instructions can set it implicitly. On many machines, nearly + all instructions set the condition code based on the value that + they compute or store. It is not necessary to record these + actions explicitly in the RTL because the machine description + includes a prescription for recognizing the instructions that do + so (by means of the macro `NOTICE_UPDATE_CC'). Only + instructions whose sole purpose is to set the condition code, + and instructions that use the condition code, need mention + `(cc0)'. + + In some cases, better code may result from recognizing + combinations or peepholes that include instructions that set the + condition codes, even in cases where some reloading is + inevitable. For examples, search for `addcc' and `andcc' in + `sparc.md'. + +`(pc)' + This represents the machine's program counter. It has no + operands and may not have a machine mode. `(pc)' may be validly + used only in certain specific contexts in jump instructions. + + There is only one expression object of code `pc'; it is the + value of the variable `pc_rtx'. Any attempt to create an + expression of code `pc' will return `pc_rtx'. + + All instructions that do not jump alter the program counter + implicitly by incrementing it, but there is no need to mention + this in the RTL. + +`(mem:M ADDR)' + This RTX represents a reference to main memory at an address + represented by the expression ADDR. M specifies how large a + unit of memory is accessed. + + +File: gcc.info, Node: Arithmetic, Next: Comparisons, Prev: Regs and Memory, Up: RTL + +RTL Expressions for Arithmetic +============================== + +`(plus:M X Y)' + Represents the sum of the values represented by X and Y carried + out in machine mode M. This is valid only if X and Y both are + valid for mode M. + +`(minus:M X Y)' + Like `plus' but represents subtraction. + +`(compare X Y)' + Represents the result of subtracting Y from X for purposes of + comparison. The absence of a machine mode in the `compare' + expression indicates that the result is computed without + overflow, as if with infinite precision. + + Of course, machines can't really subtract with infinite precision. + However, they can pretend to do so when only the sign of the + result will be used, which is the case when the result is stored + in `(cc0)'. And that is the only way this kind of expression + may validly be used: as a value to be stored in the condition + codes. + +`(neg:M X)' + Represents the negation (subtraction from zero) of the value + represented by X, carried out in mode M. X must be valid for + mode M. + +`(mult:M X Y)' + Represents the signed product of the values represented by X and + Y carried out in machine mode M. If X and Y are both valid for + mode M, this is ordinary size-preserving multiplication. + Alternatively, both X and Y may be valid for a different, + narrower mode. This represents the kind of multiplication that + generates a product wider than the operands. Widening + multiplication and same-size multiplication are completely + distinct and supported by different machine instructions; + machines may support one but not the other. + + `mult' may be used for floating point multiplication as well. + Then M is a floating point machine mode. + +`(umult:M X Y)' + Like `mult' but represents unsigned multiplication. It may be + used in both same-size and widening forms, like `mult'. `umult' + is used only for fixed-point multiplication. + +`(div:M X Y)' + Represents the quotient in signed division of X by Y, carried + out in machine mode M. If M is a floating-point mode, it + represents the exact quotient; otherwise, the integerized + quotient. If X and Y are both valid for mode M, this is + ordinary size-preserving division. Some machines have division + instructions in which the operands and quotient widths are not + all the same; such instructions are represented by `div' + expressions in which the machine modes are not all the same. + +`(udiv:M X Y)' + Like `div' but represents unsigned division. + +`(mod:M X Y)' +`(umod:M X Y)' + Like `div' and `udiv' but represent the remainder instead of the + quotient. + +`(not:M X)' + Represents the bitwise complement of the value represented by X, + carried out in mode M, which must be a fixed-point machine mode. + x must be valid for mode M, which must be a fixed-point mode. + +`(and:M X Y)' + Represents the bitwise logical-and of the values represented by + X and Y, carried out in machine mode M. This is valid only if X + and Y both are valid for mode M, which must be a fixed-point mode. + +`(ior:M X Y)' + Represents the bitwise inclusive-or of the values represented by + X and Y, carried out in machine mode M. This is valid only if X + and Y both are valid for mode M, which must be a fixed-point mode. + +`(xor:M X Y)' + Represents the bitwise exclusive-or of the values represented by + X and Y, carried out in machine mode M. This is valid only if X + and Y both are valid for mode M, which must be a fixed-point mode. + +`(lshift:M X C)' + Represents the result of logically shifting X left by C places. + X must be valid for the mode M, a fixed-point machine mode. C + must be valid for a fixed-point mode; which mode is determined + by the mode called for in the machine description entry for the + left-shift instruction. For example, on the Vax, the mode of C + is `QImode' regardless of M. + + On some machines, negative values of C may be meaningful; this + is why logical left shift and arithmetic left shift are + distinguished. For example, Vaxes have no right-shift + instructions, and right shifts are represented as left-shift + instructions whose counts happen to be negative constants or + else computed (in a previous instruction) by negation. + +`(ashift:M X C)' + Like `lshift' but for arithmetic left shift. + +`(lshiftrt:M X C)' +`(ashiftrt:M X C)' + Like `lshift' and `ashift' but for right shift. + +`(rotate:M X C)' +`(rotatert:M X C)' + Similar but represent left and right rotate. + +`(abs:M X)' + Represents the absolute value of X, computed in mode M. X must + be valid for M. + +`(sqrt:M X)' + Represents the square root of X, computed in mode M. X must be + valid for M. Most often M will be a floating point mode. + +`(ffs:M X)' + Represents one plus the index of the least significant 1-bit in + X, represented as an integer of mode M. (The value is zero if X + is zero.) The mode of X need not be M; depending on the target + machine, various mode combinations may be valid. + + +File: gcc.info, Node: Comparisons, Next: Bit Fields, Prev: Arithmetic, Up: RTL + +Comparison Operations +===================== + + Comparison operators test a relation on two operands and are +considered to represent a machine-dependent nonzero value +(`STORE_FLAG_VALUE') if the relation holds, or zero if it does not. +The mode of the comparison is determined by the operands; they must +both be valid for a common machine mode. A comparison with both +operands constant would be invalid as the machine mode could not be +deduced from it, but such a comparison should never exist in RTL due +to constant folding. + + Inequality comparisons come in two flavors, signed and unsigned. +Thus, there are distinct expression codes `gt' and `gtu' for signed +and unsigned greater-than. These can produce different results for +the same pair of integer values: for example, 1 is signed +greater-than -1 but not unsigned greater-than, because -1 when +regarded as unsigned is actually `0xffffffff' which is greater than 1. + + The signed comparisons are also used for floating point values. +Floating point comparisons are distinguished by the machine modes of +the operands. + + The comparison operators may be used to compare the condition +codes `(cc0)' against zero, as in `(eq (cc0) (const_int 0))'. Such a +construct actually refers to the result of the preceding instruction +in which the condition codes were set. The above example stands for +1 if the condition codes were set to say "zero" or "equal", 0 +otherwise. Although the same comparison operators are used for this +as may be used in other contexts on actual data, no confusion can +result since the machine description would never allow both kinds of +uses in the same context. + +`(eq X Y)' + 1 if the values represented by X and Y are equal, otherwise 0. + +`(ne X Y)' + 1 if the values represented by X and Y are not equal, otherwise 0. + +`(gt X Y)' + 1 if the X is greater than Y. If they are fixed-point, the + comparison is done in a signed sense. + +`(gtu X Y)' + Like `gt' but does unsigned comparison, on fixed-point numbers + only. + +`(lt X Y)' +`(ltu X Y)' + Like `gt' and `gtu' but test for "less than". + +`(ge X Y)' +`(geu X Y)' + Like `gt' and `gtu' but test for "greater than or equal". + +`(le X Y)' +`(leu X Y)' + Like `gt' and `gtu' but test for "less than or equal". + +`(if_then_else COND THEN ELSE)' + This is not a comparison operation but is listed here because it + is always used in conjunction with a comparison operation. To + be precise, COND is a comparison expression. This expression + represents a choice, according to COND, between the value + represented by THEN and the one represented by ELSE. + + On most machines, `if_then_else' expressions are valid only to + express conditional jumps. + + +File: gcc.info, Node: Bit Fields, Next: Conversions, Prev: Comparisons, Up: RTL + +Bit-fields +========== + + Special expression codes exist to represent bit-field instructions. +These types of expressions are lvalues in RTL; they may appear on the +left side of an assignment, indicating insertion of a value into the +specified bit field. + +`(sign_extract:SI LOC SIZE POS)' + This represents a reference to a sign-extended bit-field + contained or starting in LOC (a memory or register reference). + The bit field is SIZE bits wide and starts at bit POS. The + compilation option `BITS_BIG_ENDIAN' says which end of the + memory unit POS counts from. + + Which machine modes are valid for LOC depends on the machine, + but typically LOC should be a single byte when in memory or a + full word in a register. + +`(zero_extract:SI LOC SIZE POS)' + Like `sign_extract' but refers to an unsigned or zero-extended + bit field. The same sequence of bits are extracted, but they + are filled to an entire word with zeros instead of by + sign-extension. + + +File: gcc.info, Node: Conversions, Next: RTL Declarations, Prev: Bit Fields, Up: RTL + +Conversions +=========== + + All conversions between machine modes must be represented by +explicit conversion operations. For example, an expression which is +the sum of a byte and a full word cannot be written as `(plus:SI +(reg:QI 34) (reg:SI 80))' because the `plus' operation requires two +operands of the same machine mode. Therefore, the byte-sized operand +is enclosed in a conversion operation, as in + + (plus:SI (sign_extend:SI (reg:QI 34)) (reg:SI 80)) + + The conversion operation is not a mere placeholder, because there +may be more than one way of converting from a given starting mode to +the desired final mode. The conversion operation code says how to do +it. + +`(sign_extend:M X)' + Represents the result of sign-extending the value X to machine + mode M. M must be a fixed-point mode and X a fixed-point value + of a mode narrower than M. + +`(zero_extend:M X)' + Represents the result of zero-extending the value X to machine + mode M. M must be a fixed-point mode and X a fixed-point value + of a mode narrower than M. + +`(float_extend:M X)' + Represents the result of extending the value X to machine mode + M. M must be a floating point mode and X a floating point value + of a mode narrower than M. + +`(truncate:M X)' + Represents the result of truncating the value X to machine mode + M. M must be a fixed-point mode and X a fixed-point value of a + mode wider than M. + +`(float_truncate:M X)' + Represents the result of truncating the value X to machine mode + M. M must be a floating point mode and X a floating point value + of a mode wider than M. + +`(float:M X)' + Represents the result of converting fixed point value X, + regarded as signed, to floating point mode M. + +`(unsigned_float:M X)' + Represents the result of converting fixed point value X, + regarded as unsigned, to floating point mode M. + +`(fix:M X)' + When M is a fixed point mode, represents the result of + converting floating point value X to mode M, regarded as signed. + How rounding is done is not specified, so this operation may be + used validly in compiling C code only for integer-valued operands. + +`(unsigned_fix:M X)' + Represents the result of converting floating point value X to + fixed point mode M, regarded as unsigned. How rounding is done + is not specified. + +`(fix:M X)' + When M is a floating point mode, represents the result of + converting floating point value X (valid for mode M) to an + integer, still represented in floating point mode M, by rounding + towards zero. + + +File: gcc.info, Node: RTL Declarations, Next: Side Effects, Prev: Conversions, Up: RTL + +Declarations +============ + + Declaration expression codes do not represent arithmetic +operations but rather state assertions about their operands. + +`(strict_low_part (subreg:M (reg:N R) 0))' + This expression code is used in only one context: operand 0 of a + `set' expression. In addition, the operand of this expression + must be a `subreg' expression. + + The presence of `strict_low_part' says that the part of the + register which is meaningful in mode N, but is not part of mode + M, is not to be altered. Normally, an assignment to such a + subreg is allowed to have undefined effects on the rest of the + register when M is less than a word. + + +File: gcc.info, Node: Side Effects, Next: Incdec, Prev: RTL Declarations, Up: RTL + +Side Effect Expressions +======================= + + The expression codes described so far represent values, not actions. +But machine instructions never produce values; they are meaningful +only for their side effects on the state of the machine. Special +expression codes are used to represent side effects. + + The body of an instruction is always one of these side effect +codes; the codes described above, which represent values, appear only +as the operands of these. + +`(set LVAL X)' + Represents the action of storing the value of X into the place + represented by LVAL. LVAL must be an expression representing a + place that can be stored in: `reg' (or `subreg' or + `strict_low_part'), `mem', `pc' or `cc0'. + + If LVAL is a `reg', `subreg' or `mem', it has a machine mode; + then X must be valid for that mode. + + If LVAL is a `reg' whose machine mode is less than the full + width of the register, then it means that the part of the + register specified by the machine mode is given the specified + value and the rest of the register receives an undefined value. + Likewise, if LVAL is a `subreg' whose machine mode is narrower + than `SImode', the rest of the register can be changed in an + undefined way. + + If LVAL is a `strict_low_part' of a `subreg', then the part of + the register specified by the machine mode of the `subreg' is + given the value X and the rest of the register is not changed. + + If LVAL is `(cc0)', it has no machine mode, and X may have any + mode. This represents a "test" or "compare" instruction. + + If LVAL is `(pc)', we have a jump instruction, and the + possibilities for X are very limited. It may be a `label_ref' + expression (unconditional jump). It may be an `if_then_else' + (conditional jump), in which case either the second or the third + operand must be `(pc)' (for the case which does not jump) and + the other of the two must be a `label_ref' (for the case which + does jump). X may also be a `mem' or `(plus:SI (pc) Y)', where + Y may be a `reg' or a `mem'; these unusual patterns are used to + represent jumps through branch tables. + +`(return)' + Represents a return from the current function, on machines where + this can be done with one instruction, such as Vaxes. On + machines where a multi-instruction "epilogue" must be executed + in order to return from the function, returning is done by + jumping to a label which precedes the epilogue, and the `return' + expression code is never used. + +`(call FUNCTION NARGS)' + Represents a function call. FUNCTION is a `mem' expression + whose address is the address of the function to be called. + NARGS is an expression which can be used for two purposes: on + some machines it represents the number of bytes of stack + argument; on others, it represents the number of argument + registers. + + Each machine has a standard machine mode which FUNCTION must + have. The machine description defines macro `FUNCTION_MODE' to + expand into the requisite mode name. The purpose of this mode + is to specify what kind of addressing is allowed, on machines + where the allowed kinds of addressing depend on the machine mode + being addressed. + +`(clobber X)' + Represents the storing or possible storing of an unpredictable, + undescribed value into X, which must be a `reg' or `mem' + expression. + + One place this is used is in string instructions that store + standard values into particular hard registers. It may not be + worth the trouble to describe the values that are stored, but it + is essential to inform the compiler that the registers will be + altered, lest it attempt to keep data in them across the string + instruction. + + X may also be null--a null C pointer, no expression at all. + Such a `(clobber (null))' expression means that all memory + locations must be presumed clobbered. + + Note that the machine description classifies certain hard + registers as "call-clobbered". All function call instructions + are assumed by default to clobber these registers, so there is + no need to use `clobber' expressions to indicate this fact. + Also, each function call is assumed to have the potential to + alter any memory location, unless the function is declared + `const'. + + When a `clobber' expression for a register appears inside a + `parallel' with other side effects, GNU CC guarantees that the + register is unoccupied both before and after that insn. + Therefore, it is safe for the assembler code produced by the + insn to use the register as a temporary. You can clobber either + a specific hard register or a pseudo register; in the latter + case, GNU CC will allocate a hard register that is available + there for use as a temporary. + + If you clobber a pseudo register in this way, use a pseudo + register which appears nowhere else--generate a new one each + time. Otherwise, you may confuse CSE. + + There is one other known use for clobbering a pseudo register in + a `parallel': when one of the input operands of the insn is also + clobbered by the insn. In this case, using the same pseudo + register in the clobber and elsewhere in the insn produces the + expected results. + +`(use X)' + Represents the use of the value of X. It indicates that the + value in X at this point in the program is needed, even though + 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 X. X must be a `reg' expression. + +`(parallel [X0 X1 ...])' + Represents several side effects performed in parallel. The + square brackets stand for a vector; the operand of `parallel' is + a vector of expressions. X0, X1 and so on are individual side + effect expressions--expressions of code `set', `call', `return', + `clobber' or `use'. + + "In parallel" means that first all the values used in the + individual side-effects are computed, and second all the actual + side-effects are performed. For example, + + (parallel [(set (reg:SI 1) (mem:SI (reg:SI 1))) + (set (mem:SI (reg:SI 1)) (reg:SI 1))]) + + says unambiguously that the values of hard register 1 and the + memory location addressed by it are interchanged. In both + places where `(reg:SI 1)' appears as a memory address it refers + to the value in register 1 *before* the execution of the insn. + + It follows that it is *incorrect* to use `parallel' and expect + the result of one `set' to be available for the next one. For + example, people sometimes attempt to represent a jump-if-zero + instruction this way: + + (parallel [(set (cc0) (reg:SI 34)) + (set (pc) (if_then_else + (eq (cc0) (const_int 0)) + (label_ref ...) + (pc)))]) + + But this is incorrect, because it says that the jump condition + depends on the condition code value *before* this instruction, + not on the new value that is set by this instruction. + + Peephole optimization, which takes place in together with final + assembly code output, can produce insns whose patterns consist + of a `parallel' whose elements are the operands needed to output + the resulting assembler code--often `reg', `mem' or constant + expressions. This would not be well-formed RTL at any other + stage in compilation, but it is ok then because no further + optimization remains to be done. However, the definition of the + macro `NOTICE_UPDATE_CC' must deal with such insns if you define + any peephole optimizations. + +`(sequence [INSNS ...])' + Represents a sequence of insns. Each of the INSNS that appears + in the vector is suitable for appearing in the chain of insns, + so it must be an `insn', `jump_insn', `call_insn', `code_label', + `barrier' or `note'. + + A `sequence' RTX never appears in an actual insn. It represents + the sequence of insns that result from a `define_expand' + *before* those insns are passed to `emit_insn' to insert them in + the chain of insns. When actually inserted, the individual + sub-insns are separated out and the `sequence' is forgotten. + + Three expression codes appear in place of a side effect, as the +body of an insn, though strictly speaking they do not describe side +effects as such: + +`(asm_input S)' + Represents literal assembler code as described by the string S. + +`(addr_vec:M [LR0 LR1 ...])' + Represents a table of jump addresses. The vector elements LR0, + etc., are `label_ref' expressions. The mode M specifies how + much space is given to each address; normally M would be `Pmode'. + +`(addr_diff_vec:M BASE [LR0 LR1 ...])' + Represents a table of jump addresses expressed as offsets from + BASE. The vector elements LR0, etc., are `label_ref' + expressions and so is BASE. The mode M specifies how much space + is given to each address-difference. + + +File: gcc.info, Node: Incdec, Next: Assembler, Prev: Side Effects, Up: RTL + +Embedded Side-Effects on Addresses +================================== + + Four special side-effect expression codes appear as memory +addresses. + +`(pre_dec:M X)' + Represents the side effect of decrementing X by a standard + amount and represents also the value that X has after being + decremented. X must be a `reg' or `mem', but most machines + allow only a `reg'. M must be the machine mode for pointers on + the machine in use. The amount X is decremented by is the + length in bytes of the machine mode of the containing memory + reference of which this expression serves as the address. Here + is an example of its use: + + (mem:DF (pre_dec:SI (reg:SI 39))) + + This says to decrement pseudo register 39 by the length of a + `DFmode' value and use the result to address a `DFmode' value. + +`(pre_inc:M X)' + Similar, but specifies incrementing X instead of decrementing it. + +`(post_dec:M X)' + Represents the same side effect as `pre_dec' but a different + value. The value represented here is the value X has before + being decremented. + +`(post_inc:M X)' + Similar, but specifies incrementing X instead of decrementing it. + + These embedded side effect expressions must be used with care. +Instruction patterns may not use them. Until the `flow' pass of the +compiler, they may occur only to represent pushes onto the stack. +The `flow' pass finds cases where registers are incremented or +decremented in one instruction and used as an address shortly before +or after; these cases are then transformed to use pre- or +post-increment or -decrement. + + Explicit popping of the stack could be represented with these +embedded side effect operators, but that would not be safe; the +instruction combination pass could move the popping past pushes, thus +changing the meaning of the code. + + An instruction that can be represented with an embedded side +effect could also be represented using `parallel' containing an +additional `set' to describe how the address register is altered. +This is not done because machines that allow these operations at all +typically allow them wherever a memory address is called for. +Describing them as additional parallel stores would require doubling +the number of entries in the machine description. + + +File: gcc.info, Node: Assembler, Next: Insns, Prev: IncDec, Up: RTL + +Assembler Instructions as Expressions +===================================== + + The RTX code `asm_operands' represents a value produced by a +user-specified assembler instruction. It is used to represent an +`asm' statement with arguments. An `asm' statement with a single +output operand, like this: + + asm ("foo %1,%2,%0" : "=a" (outputvar) : "g" (x + y), "di" (*z)); + +is represented using a single `asm_operands' RTX which represents the +value that is stored in `outputvar': + + (set RTX-FOR-OUTPUTVAR + (asm_operands "foo %1,%2,%0" "a" 0 + [RTX-FOR-ADDITION-RESULT RTX-FOR-*Z] + [(asm_input:M1 "g") + (asm_input:M2 "di")])) + +Here the operands of the `asm_operands' RTX are the assembler +template string, the output-operand's constraint, the index-number of +the output operand among the output operands specified, a vector of +input operand RTX's, and a vector of input-operand modes and +constraints. The mode M1 is the mode of the sum `x+y'; M2 is that of +`*z'. + + When an `asm' statement has multiple output values, its insn has +several such `set' RTX's inside of a `parallel'. Each `set' contains +a `asm_operands'; all of these share the same assembler template and +vectors, but each contains the constraint for the respective output +operand. They are also distinguished by the output-operand index +number, which is 0, 1, ... for successive output operands. + + +File: gcc.info, Node: Insns, Next: Calls, Prev: Assembler, Up: RTL + +Insns +===== + + The RTL representation of the code for a function is a +doubly-linked chain of objects called "insns". Insns are expressions +with special codes that are used for no other purpose. Some insns +are actual instructions; others represent dispatch tables for +`switch' statements; others represent labels to jump to or various +sorts of declarative information. + + In addition to its own specific data, each insn must have a unique +id-number that distinguishes it from all other insns in the current +function, and chain pointers to the preceding and following insns. +These three fields occupy the same position in every insn, +independent of the expression code of the insn. They could be +accessed with `XEXP' and `XINT', but instead three special macros are +always used: + +`INSN_UID (I)' + Accesses the unique id of insn I. + +`PREV_INSN (I)' + Accesses the chain pointer to the insn preceding I. If I is the + first insn, this is a null pointer. + +`NEXT_INSN (I)' + Accesses the chain pointer to the insn following I. If I is the + last insn, this is a null pointer. + + The `NEXT_INSN' and `PREV_INSN' pointers must always correspond: +if INSN is not the first insn, + + NEXT_INSN (PREV_INSN (INSN)) == INSN + +is always true. + + Every insn has one of the following six expression codes: + +`insn' + The expression code `insn' is used for instructions that do not + jump and do not do function calls. Insns with code `insn' have + four additional fields beyond the three mandatory ones listed + above. These four are described in a table below. + +`jump_insn' + The expression code `jump_insn' is used for instructions that + may jump (or, more generally, may contain `label_ref' + expressions). `jump_insn' insns have the same extra fields as + `insn' insns, accessed in the same way. If there is an + instruction to return from the current function, it is recorded + as a `jump_insn'. + +`call_insn' + The expression code `call_insn' is used for instructions that + may do function calls. It is important to distinguish these + instructions because they imply that certain registers and + memory locations may be altered unpredictably. + + `call_insn' insns have the same extra fields as `insn' insns, + accessed in the same way. + +`code_label' + A `code_label' insn represents a label that a jump insn can jump + to. It contains one special field of data in addition to the + three standard ones. It is used to hold the "label number", a + number that identifies this label uniquely among all the labels + in the compilation (not just in the current function). + Ultimately, the label is represented in the assembler output as + an assembler label `LN' where N is the label number. + +`barrier' + Barriers are placed in the instruction stream after + unconditional jump instructions to indicate that the jumps are + unconditional. They contain no information beyond the three + standard fields. + +`note' + `note' insns are used to represent additional debugging and + declarative information. They contain two nonstandard fields, + an integer which is accessed with the macro `NOTE_LINE_NUMBER' + and a string accessed with `NOTE_SOURCE_FILE'. + + If `NOTE_LINE_NUMBER' is positive, the note represents the + position of a source line and `NOTE_SOURCE_FILE' is the source + file name that the line came from. These notes control + generation of line number data in the assembler output. + + Otherwise, `NOTE_LINE_NUMBER' is not really a line number but a + code with one of the following values (and `NOTE_SOURCE_FILE' + must contain a null pointer): + + `NOTE_INSN_DELETED' + Such a note is completely ignorable. Some passes of the + compiler delete insns by altering them into notes of this + kind. + + `NOTE_INSN_BLOCK_BEG' + `NOTE_INSN_BLOCK_END' + 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. + + `NOTE_INSN_LOOP_BEG' + `NOTE_INSN_LOOP_END' + These types of notes indicate the position of the beginning + and end of a `while' or `for' loop. They enable the loop + optimizer to find loops quickly. + + `NOTE_INSN_FUNCTION_END' + Appears near the end of the function body, just before the + label that `return' statements jump to (on machine where a + single instruction does not suffice for returning). This + note may be deleted by jump optimization. + + `NOTE_INSN_SETJMP' + Appears following each call to `setjmp' or a related + function. + + `NOTE_INSN_LOOP_CONT' + Appears at the place in a loop that `continue' statements + jump to. + + These codes are printed symbolically when they appear in + debugging dumps. + + The machine mode of an insn is normally zero (`VOIDmode'), but the +reload pass sets it to `QImode' if the insn needs reloading. + + Here is a table of the extra fields of `insn', `jump_insn' and +`call_insn' insns: + +`PATTERN (I)' + An expression for the side effect performed by this insn. + +`INSN_CODE (I)' + An integer that says which pattern in the machine description + matches this insn, or -1 if the matching has not yet been + attempted. + + Such matching is never attempted and this field is not used on + an insn whose pattern consists of a single `use', `clobber', + `asm', `addr_vec' or `addr_diff_vec' expression. + +`LOG_LINKS (I)' + A list (chain of `insn_list' expressions) of previous "related" + insns: insns which store into registers values that are used for + the first time in this insn. (An additional constraint is that + neither a jump nor a label may come between the related insns). + This list is set up by the flow analysis pass; it is a null + pointer until then. + +`REG_NOTES (I)' + A list (chain of `expr_list' expressions) giving information + about the usage of registers in this insn. This list is set up + by the flow analysis pass; it is a null pointer until then. + + The `LOG_LINKS' field of an insn is a chain of `insn_list' +expressions. Each of these has two operands: the first is an insn, +and the second is another `insn_list' expression (the next one in the +chain). The last `insn_list' in the chain has a null pointer as +second operand. The significant thing about the chain is which insns +appear in it (as first operands of `insn_list' expressions). Their +order is not significant. + + The `REG_NOTES' field of an insn is a similar chain but of +`expr_list' expressions instead of `insn_list'. There are several +kinds of register notes, which are distinguished by the machine mode +of the `expr_list', which in a register note is really understood as +being an `enum reg_note'. The first operand OP of the `expr_list' is +data whose meaning depends on the kind of note. Here are the kinds +of register note: + +`REG_DEAD' + The register OP dies in this insn; that is to say, altering the + value immediately after this insn would not affect the future + behavior of the program. + +`REG_INC' + The register OP is incremented (or decremented; at this level + there is no distinction) by an embedded side effect inside this + insn. This means it appears in a `post_inc', `pre_inc', + `post_dec' or `pre_dec' RTX. + +`REG_EQUIV' + The register that is set by this insn will be equal to OP at run + time, and could validly be replaced in all its occurrences by + OP. ("Validly" here refers to the data flow of the program; + simple replacement may make some insns invalid.) + + The value which the insn explicitly copies into the register may + look different from OP, but they will be equal at run time. + + For example, when a constant is loaded into a register that is + never assigned any other value, this kind of note is used. + + When a parameter is copied into a pseudo-register at entry to a + function, a note of this kind records that the register is + equivalent to the stack 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. + +`REG_EQUAL' + The register that is set by this insn will be equal to OP at run + time at the end of this insn (but not necessarily elsewhere in + the function). + + The RTX OP is typically an arithmetic expression. For example, + when a sequence of insns such as a library call is used to + perform an arithmetic operation, this kind of note is attached + to the insn that produces or copies the final value. It tells + the CSE pass how to think of that value. + +`REG_RETVAL' + This insn copies the value of a library call, and OP is the + first insn that was generated to set up the arguments for the + library call. + + Flow analysis uses this note to delete all of a library call + whose result is dead. + +`REG_WAS_0' + The register OP contained zero before this insn. You can rely + on this note if it is present; its absence implies nothing. + +`REG_LIBCALL' + This is the inverse of `REG_RETVAL': it is placed on the first + insn of a library call, and it points to the last one. + + Loop optimization uses this note to move an entire library call + out of a loop when its value is constant. + +`REG_NONNEG' + The register OP is known to have nonnegative value when this + insn is reached. + + For convenience, the machine mode in an `insn_list' or `expr_list' +is printed using these symbolic codes in debugging dumps. + + The only difference between the expression codes `insn_list' and +`expr_list' is that the first operand of an `insn_list' is assumed to +be an insn and is printed in debugging dumps as the insn's unique id; +the first operand of an `expr_list' is printed in the ordinary way as +an expression. + + +File: gcc.info, Node: Calls, Next: Sharing, Prev: Insns, Up: RTL + +RTL Representation of Function-Call Insns +========================================= + + Insns that call subroutines have the RTL expression code +`call_insn'. These insns must satisfy special rules, and their +bodies must use a special RTL expression code, `call'. + + A `call' expression has two operands, as follows: + + (call (mem:FM ADDR) NBYTES) + +Here NBYTES is an operand that represents the number of bytes of +argument data being passed to the subroutine, FM is a machine mode +(which must equal as the definition of the `FUNCTION_MODE' macro in +the machine description) and ADDR represents the address of the +subroutine. + + For a subroutine that returns no value, the `call' RTX as shown +above is the entire body of the insn. + + For a subroutine that returns a value whose mode is not `BLKmode', +the value is returned in a hard register. If this register's number +is R, then the body of the call insn looks like this: + + (set (reg:M R) + (call (mem:FM ADDR) NBYTES)) + +This RTL expression makes it clear (to the optimizer passes) that the +appropriate register receives a useful value in this insn. + + Immediately after RTL generation, if the value of the subroutine +is actually used, this call insn is always followed closely by an +insn which refers to the register R. This remains true through all +the optimizer passes until cross jumping occurs. + + The following insn has one of two forms. Either it copies the +value into a pseudo-register, like this: + + (set (reg:M P) (reg:M R)) + +or (in the case where the calling function will simply return +whatever value the call produced, and no operation is needed to do +this): + + (use (reg:M R)) + +Between the call insn and this following insn there may intervene +only a stack-adjustment insn (and perhaps some `note' insns). + + When a subroutine returns a `BLKmode' value, it is handled by +passing to the subroutine the address of a place to store the value. +So the call insn itself does not "return" any value, and it has the +same RTL form as a call that returns nothing. + + \ No newline at end of file diff --git a/gcc-1.40/gcc.info-7 b/gcc-1.40/gcc.info-7 new file mode 100644 index 0000000..ed72551 --- /dev/null +++ b/gcc-1.40/gcc.info-7 @@ -0,0 +1,970 @@ +Info file gcc.info, produced by Makeinfo, -*- Text -*- from input +file gcc.texinfo. + + This file documents the use and the internals of the GNU compiler. + + Copyright (C) 1988, 1989, 1990 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. + + 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" and "Protect +Your Freedom--Fight `Look And Feel'" 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" and "Protect Your Freedom--Fight `Look And Feel'" and this +permission notice may be included in translations approved by the +Free Software Foundation instead of in the original English. + + +File: gcc.info, Node: Sharing, Prev: Calls, Up: RTL + +Structure Sharing Assumptions +============================= + + The compiler assumes that certain kinds of RTL expressions are +unique; there do not exist two distinct objects representing the same +value. In other cases, it makes an opposite assumption: that no RTL +expression object of a certain kind appears in more than one place in +the containing structure. + + These assumptions refer to a single function; except for the RTL +objects that describe global variables and external functions, no RTL +objects are common to two functions. + + * Each pseudo-register has only a single `reg' object to represent + it, and therefore only a single machine mode. + + * For any symbolic label, there is only one `symbol_ref' object + referring to it. + + * There is only one `const_int' expression with value zero, and + only one with value one. + + * There is only one `pc' expression. + + * There is only one `cc0' expression. + + * There is only one `const_double' expression with mode `SFmode' + and value zero, and only one with mode `DFmode' and value zero. + + * No `label_ref' appears in more than one place in the RTL + structure; in other words, it is safe to do a tree-walk of all + the insns in the function and assume that each time a + `label_ref' is seen it is distinct from all others that are seen. + + * Only one `mem' object is normally created for each static + variable or stack slot, so these objects are frequently shared + in all the places they appear. However, separate but equal + objects for these variables are occasionally made. + + * When a single `asm' statement has multiple output operands, a + distinct `asm_operands' RTX is made for each output operand. + However, these all share the vector which contains the sequence + of input operands. Because this sharing is used later on to + test whether two `asm_operands' RTX's come from the same + statement, the sharing must be guaranteed to be preserved. + + * No RTL object appears in more than one place in the RTL + structure except as described above. Many passes of the + compiler rely on this by assuming that they can modify RTL + objects in place without unwanted side-effects on other insns. + + * During initial RTL generation, shared structure is freely + introduced. After all the RTL for a function has been + generated, all shared structure is copied by `unshare_all_rtl' + in `emit-rtl.c', after which the above rules are guaranteed to + be followed. + + * During the combiner pass, shared structure with an insn can + exist temporarily. However, the shared structure is copied + before the combiner is finished with the insn. This is done by + `copy_substitutions' in `combine.c'. + + +File: gcc.info, Node: Machine Desc, Next: Machine Macros, Prev: RTL, Up: Top + +Machine Descriptions +******************** + + A machine description has two parts: a file of instruction +patterns (`.md' file) and a C header file of macro definitions. + + The `.md' file for a target machine contains a pattern for each +instruction that the target machine supports (or at least each +instruction that is worth telling the compiler about). It may also +contain comments. A semicolon causes the rest of the line to be a +comment, unless the semicolon is inside a quoted string. + + See the next chapter for information on the C header file. + +* Menu: + +* Patterns:: How to write instruction patterns. +* Example:: An explained example of a `define_insn' pattern. +* RTL Template:: The RTL template defines what insns match a pattern. +* Output Template:: The output template says how to make assembler code + from such an insn. +* Output Statement:: For more generality, write C code to output + the assembler code. +* Constraints:: When not all operands are general operands. +* Standard Names:: Names mark patterns to use for code generation. +* Pattern Ordering:: When the order of patterns makes a difference. +* Dependent Patterns:: Having one pattern may make you need another. +* Jump Patterns:: Special considerations for patterns for jump insns. +* Peephole Definitions::Defining machine-specific peephole optimizations. +* Expander Definitions::Generating a sequence of several RTL insns + for a standard operation. + + +File: gcc.info, Node: Patterns, Next: Example, Prev: Machine Desc, Up: Machine Desc + +Everything about Instruction Patterns +===================================== + + Each instruction pattern contains an incomplete RTL expression, +with pieces to be filled in later, operand constraints that restrict +how the pieces can be filled in, and an output pattern or C code to +generate the assembler output, all wrapped up in a `define_insn' +expression. + + A `define_insn' is an RTL expression containing four or five +operands: + + 1. An optional name. The presence of a name indicate that this + instruction pattern can perform a certain standard job for the + RTL-generation pass of the compiler. This pass knows certain + names and will use the instruction patterns with those names, if + the names are defined in the machine description. + + The absence of a name is indicated by writing an empty string + where the name should go. Nameless instruction patterns are + never used for generating RTL code, but they may permit several + simpler insns to be combined later on. + + Names that are not thus known and used in RTL-generation have + no effect; they are equivalent to no name at all. + + 2. The "RTL template" (*note RTL Template::.) is a vector of + incomplete RTL expressions which show what the instruction + should look like. It is incomplete because it may contain + `match_operand' and `match_dup' expressions that stand for + operands of the instruction. + + If the vector has only one element, that element is the + template for the instruction pattern. If the vector has + multiple elements, then the instruction pattern is a `parallel' + expression containing the elements described. + + 3. A condition. This is a string which contains a C expression + that is the final test to decide whether an insn body matches + this pattern. + + For a named pattern, the condition (if present) may not + depend on the data in the insn being matched, but only the + target-machine-type flags. The compiler needs to test these + conditions during initialization in order to learn exactly which + named instructions are available in a particular run. + + For nameless patterns, the condition is applied only when + matching an individual insn, and only after the insn has matched + the pattern's recognition template. The insn's operands may be + found in the vector `operands'. + + 4. The "output template": a string that says how to output matching + insns as assembler code. `%' in this string specifies where to + substitute the value of an operand. *Note Output Template::. + + When simple substitution isn't general enough, you can + specify a piece of C code to compute the output. *Note Output + Statement::. + + 5. Optionally, some "machine-specific information". The meaning of + this information is defined only by an individual machine + description; typically it might say whether this insn alters the + condition codes, or how many bytes of output it generates. + + This operand is written as a string containing a C + initializer (complete with braces) for the structure type + `INSN_MACHINE_INFO', whose definition is up to you (*note + Misc::.). + + +File: gcc.info, Node: Example, Next: RTL Template, Prev: Patterns, Up: Machine Desc + +Example of `define_insn' +======================== + + Here is an actual example of an instruction pattern, for the +68000/68020. + + (define_insn "tstsi" + [(set (cc0) + (match_operand:SI 0 "general_operand" "rm"))] + "" + "* + { if (TARGET_68020 || ! ADDRESS_REG_P (operands[0])) + return \"tstl %0\"; + return \"cmpl #0,%0\"; }") + + This is an instruction that sets the condition codes based on the +value of a general operand. It has no condition, so any insn whose +RTL description has the form shown may be handled according to this +pattern. The name `tstsi' means "test a `SImode' value" and tells +the RTL generation pass that, when it is necessary to test such a +value, an insn to do so can be constructed using this pattern. + + The output control string is a piece of C code which chooses which +output template to return based on the kind of operand and the +specific type of CPU for which code is being generated. + + `"rm"' is an operand constraint. Its meaning is explained below. + + +File: gcc.info, Node: RTL Template, Next: Output Template, Prev: Example, Up: Machine Desc + +RTL Template for Generating and Recognizing Insns +================================================= + + The RTL template is used to define which insns match the +particular pattern and how to find their operands. For named +patterns, the RTL template also says how to construct an insn from +specified operands. + + Construction involves substituting specified operands into a copy +of the template. Matching involves determining the values that serve +as the operands in the insn being matched. Both of these activities +are controlled by special expression types that direct matching and +substitution of the operands. + +`(match_operand:M N PRED CONSTRAINT)' + This expression is a placeholder for operand number N of the + insn. When constructing an insn, operand number N will be + substituted at this point. When matching an insn, whatever + appears at this position in the insn will be taken as operand + number N; but it must satisfy PRED or this instruction pattern + will not match at all. + + Operand numbers must be chosen consecutively counting from zero + in each instruction pattern. There may be only one + `match_operand' expression in the pattern for each operand + number. Usually operands are numbered in the order of + appearance in `match_operand' expressions. + + PRED is a string that is the name of a C function that accepts + two arguments, an expression and a machine mode. During + matching, the function will be called with the putative operand + as the expression and M as the mode argument. If it returns + zero, this instruction pattern fails to match. PRED may be an + empty string; then it means no test is to be done on the + operand, so anything which occurs in this position is valid. + + CONSTRAINT controls reloading and the choice of the best + register class to use for a value, as explained later (*note + Constraints::.). + + People are often unclear on the difference between the + constraint and the predicate. The predicate helps decide + whether a given insn matches the pattern. The constraint plays + no role in this decision; instead, it controls various decisions + in the case of an insn which does match. + + Most often, PRED is `"general_operand"'. This function checks + that the putative operand is either a constant, a register or a + memory reference, and that it is valid for mode M. + + For an operand that must be a register, PRED should be + `"register_operand"'. It would be valid to use + `"general_operand"', since the reload pass would copy any + non-register operands through registers, but this would make GNU + CC do extra work, and it would prevent the register allocator + from doing the best possible job. + + For an operand that must be a constant, either PRED should be + `"immediate_operand"', or the instruction pattern's extra + condition should check for constants, or both. You cannot + expect the constraints to do this work! If the constraints + allow only constants, but the predicate allows something else, + the compiler will crash when that case arises. + +`(match_dup N)' + This expression is also a placeholder for operand number N. It + is used when the operand needs to appear more than once in the + insn. + + In construction, `match_dup' behaves exactly like + `match_operand': the operand is substituted into the insn being + constructed. But in matching, `match_dup' behaves differently. + It assumes that operand number N has already been determined by + a `match_operand' appearing earlier in the recognition template, + and it matches only an identical-looking expression. + +`(match_operator:M N "PREDICATE" [OPERANDS...])' + This pattern is a kind of placeholder for a variable RTL + expression code. + + When constructing an insn, it stands for an RTL expression whose + expression code is taken from that of operand N, and whose + operands are constructed from the patterns OPERANDS. + + When matching an expression, it matches an expression if the + function PREDICATE returns nonzero on that expression *and* the + patterns OPERANDS match the operands of the expression. + + Suppose that the function `commutative_operator' is defined as + follows, to match any expression whose operator is one of the + six commutative arithmetic operators of RTL and whose mode is + MODE: + + int + commutative_operator (x, mode) + rtx x; + enum machine_mode mode; + { + enum rtx_code code = GET_CODE (x); + if (GET_MODE (x) != mode) + return 0; + return (code == PLUS || code == MULT || code == UMULT + || code == AND || code == IOR || code == XOR); + } + + Then the following pattern will match any RTL expression + consisting of a commutative operator applied to two general + operands: + + (match_operator:SI 2 "commutative_operator" + [(match_operand:SI 3 "general_operand" "g") + (match_operand:SI 4 "general_operand" "g")]) + + Here the vector `[OPERANDS...]' contains two patterns because + the expressions to be matched all contain two operands. + + When this pattern does match, the two operands of the + commutative operator are recorded as operands 3 and 4 of the + insn. (This is done by the two instances of `match_operand'.) + Operand 2 of the insn will be the entire commutative expression: + use `GET_CODE (operands[2])' to see which commutative operator + was used. + + The machine mode M of `match_operator' works like that of + `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. + + When constructing an insn, argument 2 of the gen-function will + specify the operation (i.e. the expression code) for the + expression to be made. It should be an RTL expression, whose + expression code is copied into a new expression whose operands + are arguments 3 and 4 of the gen-function. The subexpressions + of argument 2 are not used; only its expression code matters. + + There is no way to specify constraints in `match_operator'. The + operand of the insn which corresponds to the `match_operator' + never has any constraints because it is never reloaded as a whole. + However, if parts of its OPERANDS are matched by `match_operand' + patterns, those parts may have constraints of their own. + +`(address (match_operand:M N "address_operand" ""))' + This complex of expressions is a placeholder for an operand + number N in a "load address" instruction: an operand which + specifies a memory location in the usual way, but for which the + actual operand value used is the address of the location, not + the contents of the location. + + `address' expressions never appear in RTL code, only in machine + descriptions. And they are used only in machine descriptions + that do not use the operand constraint feature. When operand + constraints are in use, the letter `p' in the constraint serves + this purpose. + + M is the machine mode of the *memory location being addressed*, + not the machine mode of the address itself. That mode is always + the same on a given target machine (it is `Pmode', which + normally is `SImode'), so there is no point in mentioning it; + thus, no machine mode is written in the `address' expression. + If some day support is added for machines in which addresses of + different kinds of objects appear differently or are used + differently (such as the PDP-10), different formats would + perhaps need different machine modes and these modes might be + written in the `address' expression. + + +File: gcc.info, Node: Output Template, Next: Output Statement, Prev: RTL Template, Up: Machine Desc + +Output Templates and Operand Substitution +========================================= + + The "output template" is a string which specifies how to output +the assembler code for an instruction pattern. Most of the template +is a fixed string which is output literally. The character `%' is +used to specify where to substitute an operand; it can also be used +to identify places where different variants of the assembler require +different syntax. + + In the simplest case, a `%' followed by a digit N says to output +operand N at that point in the string. + + `%' followed by a letter and a digit says to output an operand in +an alternate fashion. Four letters have standard, built-in meanings +described below. The machine description macro `PRINT_OPERAND' can +define additional letters with nonstandard meanings. + + `%cDIGIT' can be used to substitute an operand that is a constant +value without the syntax that normally indicates an immediate operand. + + `%nDIGIT' is like `%cDIGIT' except that the value of the constant +is negated before printing. + + `%aDIGIT' can be used to substitute an operand as if it were a +memory reference, with the actual operand treated as the address. +This may be useful when outputting a "load address" instruction, +because often the assembler syntax for such an instruction requires +you to write the operand as if it were a memory reference. + + `%lDIGIT' is used to substitute a `label_ref' into a jump +instruction. + + `%' followed by a punctuation character specifies a substitution +that does not use an operand. Only one case is standard: `%%' +outputs a `%' into the assembler code. Other nonstandard cases can +be defined in the `PRINT_OPERAND' macro. You must also define which +punctuation characters are valid with the +`PRINT_OPERAND_PUNCT_VALID_P' macro. + + The template may generate multiple assembler instructions. Write +the text for the instructions, with `\;' between them. + + When the RTL contains two operands which are required by +constraint to match each other, the output template must refer only +to the lower-numbered operand. Matching operands are not always +identical, and the rest of the compiler arranges to put the proper +RTL expression for printing into the lower-numbered operand. + + One use of nonstandard letters or punctuation following `%' is to +distinguish between different assembler languages for the same +machine; for example, Motorola syntax versus MIT syntax for the +68000. Motorola syntax requires periods in most opcode names, while +MIT syntax does not. For example, the opcode `movel' in MIT syntax +is `move.l' in Motorola syntax. The same file of patterns is used +for both kinds of output syntax, but the character sequence `%.' is +used in each place where Motorola syntax wants a period. The +`PRINT_OPERAND' macro for Motorola syntax defines the sequence to +output a period; the macro for MIT syntax defines it to do nothing. + + +File: gcc.info, Node: Output Statement, Next: Constraints, Prev: Output Template, Up: Machine Desc + +C Statements for Generating Assembler Output +============================================ + + Often a single fixed template string cannot produce correct and +efficient assembler code for all the cases that are recognized by a +single instruction pattern. For example, the opcodes may depend on +the kinds of operands; or some unfortunate combinations of operands +may require extra machine instructions. + + If the output control string starts with a `*', then it is not an +output template but rather a piece of C program that should compute a +template. It should execute a `return' statement to return the +template-string you want. Most such templates use C string literals, +which require doublequote characters to delimit them. To include +these doublequote characters in the string, prefix each one with `\'. + + The operands may be found in the array `operands', whose C data +type is `rtx []'. + + It is possible to output an assembler instruction and then go on +to output or compute more of them, using the subroutine +`output_asm_insn'. This receives two arguments: a template-string +and a vector of operands. The vector may be `operands', or it may be +another array of `rtx' that you declare locally and initialize +yourself. + + When an insn pattern has multiple alternatives in its constraints, +often the appearance of the assembler code is determined mostly by +which alternative was matched. When this is so, the C code can test +the variable `which_alternative', which is the ordinal number of the +alternative that was actually satisfied (0 for the first, 1 for the +second alternative, etc.). + + For example, suppose there are two opcodes for storing zero, +`clrreg' for registers and `clrmem' for memory locations. Here is +how a pattern could use `which_alternative' to choose between them: + + (define_insn "" + [(set (match_operand:SI 0 "general_operand" "r,m") + (const_int 0))] + "" + "* + return (which_alternative == 0 + ? \"clrreg %0\" : \"clrmem %0\"); + ") + + +File: gcc.info, Node: Constraints, Next: Standard Names, Prev: Output Statement, Up: Machine Desc + +Operand Constraints +=================== + + Each `match_operand' in an instruction pattern can specify a +constraint for the type of operands allowed. Constraints can say +whether an operand may be in a register, and which kinds of register; +whether the operand can be a memory reference, and which kinds of +address; whether the operand may be an immediate constant, and which +possible values it may have. Constraints can also require two +operands to match. + +* Menu: + +* Simple Constraints:: Basic use of constraints. +* Multi-Alternative:: When an insn has two alternative constraint-patterns. +* Class Preferences:: Constraints guide which hard register to put things in. +* Modifiers:: More precise control over effects of constraints. +* No Constraints:: Describing a clean machine without constraints. + + +File: gcc.info, Node: Simple Constraints, Next: Multi-Alternative, Prev: Constraints, Up: Constraints + +Simple Constraints +------------------ + + The simplest kind of constraint is a string full of letters, each +of which describes one kind of operand that is permitted. Here are +the letters that are allowed: + +`m' + A memory operand is allowed, with any kind of address that the + machine supports in general. + +`o' + A memory operand is allowed, but only if the address is + "offsettable". This means that adding a small integer + (actually, the width in bytes of the operand, as determined by + its machine mode) may be added to the address and the result is + also a valid memory address. + + For example, an address which is constant is offsettable; so is + an address that is the sum of a register and a constant (as long + as a slightly larger constant is also within the range of + address-offsets supported by the machine); but an autoincrement + or autodecrement address is not offsettable. More complicated + indirect/indexed addresses may or may not be offsettable + depending on the other addressing modes that the machine supports. + + Note that in an output operand which can be matched by another + operand, the constraint letter `o' is valid only when + accompanied by both `<' (if the target machine has predecrement + addressing) and `>' (if the target machine has preincrement + addressing). + + When the constraint letter `o' is used, the reload pass may + generate instructions which copy a nonoffsettable address into + an index register. The idea is that the register can be used as + a replacement offsettable address. But this method requires + that there be patterns to copy any kind of address into a + register. Auto-increment and auto-decrement addresses are an + exception; there need not be an instruction that can copy such + an address into a register, because reload handles these cases + specially. + + Most older machine designs have "load address" instructions + which do just what is needed here. Some RISC machines do not + advertise such instructions, but the possible addresses on these + machines are very limited, so it is easy to fake them. + +`<' + A memory operand with autodecrement addressing (either + predecrement or postdecrement) is allowed. + +`>' + A memory operand with autoincrement addressing (either + preincrement or postincrement) is allowed. + +`r' + A register operand is allowed provided that it is in a general + register. + +`d', `a', `f', ... + Other letters can be defined in machine-dependent fashion to + stand for particular classes of registers. `d', `a' and `f' are + defined on the 68000/68020 to stand for data, address and + floating point registers. + +`i' + An immediate integer operand (one with constant value) is allowed. + This includes symbolic constants whose values will be known only + at assembly time. + +`n' + An immediate integer operand with a known numeric value is + allowed. Many systems cannot support assembly-time constants + for operands less than a word wide. Constraints for these + operands should use `n' rather than `i'. + +`I', `J', `K', ... + Other letters in the range `I' through `M' may be defined in a + machine-dependent fashion to permit immediate integer operands + with explicit integer values in specified ranges. For example, + on the 68000, `I' is defined to stand for the range of values 1 + to 8. This is the range permitted as a shift count in the shift + instructions. + +`F' + An immediate floating operand (expression code `const_double') + is allowed. + +`G', `H' + `G' and `H' may be defined in a machine-dependent fashion to + permit immediate floating operands in particular ranges of values. + +`s' + An immediate integer operand whose value is not an explicit + integer is allowed. + + This might appear strange; if an insn allows a constant operand + with a value not known at compile time, it certainly must allow + any known value. So why use `s' instead of `i'? Sometimes it + allows better code to be generated. + + For example, on the 68000 in a fullword instruction it is + possible to use an immediate operand; but if the immediate value + is between -128 and 127, better code results from loading the + value into a register and using the register. This is because + the load into the register can be done with a `moveq' + instruction. We arrange for this to happen by defining the + letter `K' to mean "any integer outside the range -128 to 127", + and then specifying `Ks' in the operand constraints. + +`g' + Any register, memory or immediate integer operand is allowed, + except for registers that are not general registers. + +`N' (a digit) + An operand that matches operand number N is allowed. If a digit + is used together with letters, the digit should come last. + + This is called a "matching constraint" and what it really means + is that the assembler has only a single operand that fills two + roles considered separate in the RTL insn. For example, an add + insn has two input operands and one output operand in the RTL, + but on most machines an add instruction really has only two + operands, one of them an input-output operand. + + Matching constraints work only in circumstances like that add + insn. More precisely, the matching constraint must appear in an + input-only operand and the operand that it matches must be an + output-only operand with a lower number. Thus, operand N must + have `=' in its constraint. + + For operands to match in a particular case usually means that + they are identical-looking RTL expressions. But in a few + special cases specific kinds of dissimilarity are allowed. For + example, `*x' as an input operand will match `*x++' as an output + operand. For proper results in such cases, the output template + should always use the output-operand's number when printing the + operand. + +`p' + An operand that is a valid memory address is allowed. This is + for "load address" and "push address" instructions. + + `p' in the constraint must be accompanies by `address_operand' + as the predicate in the `match_operand'. + + In order to have valid assembler code, each operand must satisfy +its constraint. But a failure to do so does not prevent the pattern +from applying to an insn. Instead, it directs the compiler to modify +the code so that the constraint will be satisfied. Usually this is +done by copying an operand into a register. + + Contrast, therefore, the two instruction patterns that follow: + + (define_insn "" + [(set (match_operand:SI 0 "general_operand" "r") + (plus:SI (match_dup 0) + (match_operand:SI 1 "general_operand" "r")))] + "" + "...") + +which has two operands, one of which must appear in two places, and + + (define_insn "" + [(set (match_operand:SI 0 "general_operand" "r") + (plus:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "r")))] + "" + "...") + +which has three operands, two of which are required by a constraint +to be identical. If we are considering an insn of the form + + (insn N PREV NEXT + (set (reg:SI 3) + (plus:SI (reg:SI 6) (reg:SI 109))) + ...) + +the first pattern would not apply at all, because this insn does not +contain two identical subexpressions in the right place. The pattern +would say, "That does not look like an add instruction; try other +patterns." The second pattern would say, "Yes, that's an add +instruction, but there is something wrong with it." It would direct +the reload pass of the compiler to generate additional insns to make +the constraint true. The results might look like this: + + (insn N2 PREV N + (set (reg:SI 3) (reg:SI 6)) + ...) + + (insn N N2 NEXT + (set (reg:SI 3) + (plus:SI (reg:SI 3) (reg:SI 109))) + ...) + + It is up to you to make sure that each operand, in each pattern, +has constraints that can handle any RTL expression that could be +present for that operand. (When multiple alternatives are in use, +each pattern must, for each possible combination of operand +expressions, have at least one alternative which can handle that +combination of operands.) The constraints don't need to *allow* any +possible operand--when this is the case, they do not constrain--but +they must at least point the way to reloading any possible operand so +that it will fit. + + * If the constraint accepts whatever operands the predicate + permits, there is no problem: reloading is never necessary for + this operand. + + For example, an operand whose constraints permit everything + except registers is safe provided its predicate rejects registers. + + An operand whose predicate accepts only constant values is safe + provided its constraints include the letter `i'. If any + possible constant value is accepted, then nothing less than `i' + will do; if the predicate is more selective, then the + constraints may also be more selective. + + * Any operand expression can be reloaded by copying it into a + register. So if an operand's constraints allow some kind of + register, it is certain to be safe. It need not permit all + classes of registers; the compiler knows how to copy a register + into another register of the proper class in order to make an + instruction valid. + + * A nonoffsettable memory reference can be reloaded by copying the + address into a register. So if the constraint uses the letter + `o', all memory references are taken care of. + + * A constant operand can be reloaded by allocating space in memory + to hold it as preinitialized data. Then the memory reference + can be used in place of the constant. So if the constraint uses + the letters `o' or `m', constant operands are not a problem. + + 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. + + +File: gcc.info, Node: Multi-Alternative, Next: Class Preferences, Prev: Simple Constraints, Up: Constraints + +Multiple Alternative Constraints +-------------------------------- + + Sometimes a single instruction has multiple alternative sets of +possible operands. For example, on the 68000, a logical-or +instruction can combine register or an immediate value into memory, +or it can combine any kind of operand into a register; but it cannot +combine one memory location into another. + + These constraints are represented as multiple alternatives. An +alternative can be described by a series of letters for each operand. +The overall constraint for an operand is made from the letters for +this operand from the first alternative, a comma, the letters for +this operand from the second alternative, a comma, and so on until +the last alternative. Here is how it is done for fullword logical-or +on the 68000: + + (define_insn "iorsi3" + [(set (match_operand:SI 0 "general_operand" "=m,d") + (ior:SI (match_operand:SI 1 "general_operand" "%0,0") + (match_operand:SI 2 "general_operand" "dKs,dmKs")))] + ...) + + The first alternative has `m' (memory) for operand 0, `0' for +operand 1 (meaning it must match operand 0), and `dKs' for operand 2. +The second alternative has `d' (data register) for operand 0, `0' for +operand 1, and `dmKs' for operand 2. The `=' and `%' in the +constraints apply to all the alternatives; their meaning is explained +in the next section. + + If all the operands fit any one alternative, the instruction is +valid. Otherwise, for each alternative, the compiler counts how many +instructions must be added to copy the operands so that that +alternative applies. The alternative requiring the least copying is +chosen. If two alternatives need the same amount of copying, the one +that comes first is chosen. These choices can be altered with the +`?' and `!' characters: + +`?' + Disparage slightly the alternative that the `?' appears in, as a + choice when no alternative applies exactly. The compiler + regards this alternative as one unit more costly for each `?' + that appears in it. + +`!' + Disparage severely the alternative that the `!' appears in. + When operands must be copied into registers, the compiler will + never choose this alternative as the one to strive for. + + When an insn pattern has multiple alternatives in its constraints, +often the appearance of the assembler code is determined mostly by +which alternative was matched. When this is so, the C code for +writing the assembler code can use the variable `which_alternative', +which is the ordinal number of the alternative that was actually +satisfied (0 for the first, 1 for the second alternative, etc.). For +example: + + (define_insn "" + [(set (match_operand:SI 0 "general_operand" "r,m") + (const_int 0))] + "" + "* + return (which_alternative == 0 + ? \"clrreg %0\" : \"clrmem %0\"); + ") + + +File: gcc.info, Node: Class Preferences, Next: Modifiers, Prev: Multi-Alternative, Up: Constraints + +Register Class Preferences +-------------------------- + + The operand constraints have another function: they enable the +compiler to decide which kind of hardware register a pseudo register +is best allocated to. The compiler examines the constraints that +apply to the insns that use the pseudo register, looking for the +machine-dependent letters such as `d' and `a' that specify classes of +registers. The pseudo register is put in whichever class gets the +most "votes". The constraint letters `g' and `r' also vote: they +vote in favor of a general register. The machine description says +which registers are considered general. + + Of course, on some machines all registers are equivalent, and no +register classes are defined. Then none of this complexity is +relevant. + + +File: gcc.info, Node: Modifiers, Next: No Constraints, Prev: Class Preferences, Up: Constraints + +Constraint Modifier Characters +------------------------------ + +`=' + Means that this operand is write-only for this instruction: the + previous value is discarded and replaced by output data. + +`+' + Means that this operand is both read and written by the + instruction. + + When the compiler fixes up the operands to satisfy the + constraints, it needs to know which operands are inputs to the + instruction and which are outputs from it. `=' identifies an + output; `+' identifies an operand that is both input and output; + all other operands are assumed to be input only. + +`&' + 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. + + `&' applies only to the alternative in which it is written. In + constraints with multiple alternatives, sometimes one + alternative requires `&' while others do not. See, for example, + the `movdf' insn of the 68000. + + `&' does not obviate the need to write `='. + +`%' + Declares the instruction to be commutative for this operand and + the following operand. This means that the compiler may + interchange the two operands if that is the cheapest way to make + all operands fit the constraints. This is often used in + patterns for addition instructions that really have only two + operands: the result must go in one of the arguments. Here for + example, is how the 68000 halfword-add instruction is defined: + + (define_insn "addhi3" + [(set (match_operand:HI 0 "general_operand" "=m,r") + (plus:HI (match_operand:HI 1 "general_operand" "%0,0") + (match_operand:HI 2 "general_operand" "di,g")))] + ...) + + Note that in previous versions of GNU CC the `%' constraint + modifier always applied to operands 1 and 2 regardless of which + operand it was written in. The usual custom was to write it in + operand 0. Now it must be in operand 1 if the operands to be + exchanged are 1 and 2. + +`#' + Says that all following characters, up to the next comma, are to + be ignored as a constraint. They are significant only for + choosing register preferences. + +`*' + Says that the following character should be ignored when + choosing register preferences. `*' has no effect on the meaning + of the constraint as a constraint. + + Here is an example: the 68000 has an instruction to sign-extend + a halfword in a data register, and can also sign-extend a value + by copying it into an address register. While either kind of + register is acceptable, the constraints on an address-register + destination are less strict, so it is best if register + allocation makes an address register its goal. Therefore, `*' + is used so that the `d' constraint letter (for data register) is + ignored when computing register preferences. + + (define_insn "extendhisi2" + [(set (match_operand:SI 0 "general_operand" "=*d,a") + (sign_extend:SI + (match_operand:HI 1 "general_operand" "0,g")))] + ...) + + +File: gcc.info, Node: No Constraints, Prev: Modifiers, Up: Constraints + +Not Using Constraints +--------------------- + + Some machines are so clean that operand constraints are not +required. For example, on the Vax, an operand valid in one context +is valid in any other context. On such a machine, every operand +constraint would be `g', excepting only operands of "load address" +instructions which are written as if they referred to a memory +location's contents but actual refer to its address. They would have +constraint `p'. + + For such machines, instead of writing `g' and `p' for all the +constraints, you can choose to write a description with empty +constraints. Then you write `""' for the constraint in every +`match_operand'. Address operands are identified by writing an +`address' expression around the `match_operand', not by their +constraints. + + When the machine description has just empty constraints, certain +parts of compilation are skipped, making the compiler faster. +However, few machines actually do not need constraints; all machine +descriptions now in existence use constraints. + + \ No newline at end of file diff --git a/gcc-1.40/gcc.info-8 b/gcc-1.40/gcc.info-8 new file mode 100644 index 0000000..340bb33 --- /dev/null +++ b/gcc-1.40/gcc.info-8 @@ -0,0 +1,1152 @@ +Info file gcc.info, produced by Makeinfo, -*- Text -*- from input +file gcc.texinfo. + + This file documents the use and the internals of the GNU compiler. + + Copyright (C) 1988, 1989, 1990 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. + + 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" and "Protect +Your Freedom--Fight `Look And Feel'" 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" and "Protect Your Freedom--Fight `Look And Feel'" and this +permission notice may be included in translations approved by the +Free Software Foundation instead of in the original English. + + +File: gcc.info, Node: Standard Names, Next: Pattern Ordering, Prev: Constraints, Up: Machine Desc + +Standard Names for Patterns Used in Generation +============================================== + + 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. + +`movM' + Here M stands for a two-letter machine mode name, in lower case. + This instruction pattern moves data with that machine mode from + operand 1 to operand 0. For example, `movsi' moves full-word + data. + + If operand 0 is a `subreg' with mode M of a register whose own + mode is wider than M, the effect of this instruction is to store + the specified value in the part of the register that corresponds + to mode M. The effect on the rest of the register is undefined. + + This class of patterns is special in several ways. First of + all, each of these names *must* be defined, because there is no + other way to copy a datum from one place to another. + + Second, these patterns are not used solely in the RTL generation + pass. Even the reload pass can generate move insns to copy + values from stack slots into temporary registers. When it does + so, one of the operands is a hard register and the other is an + operand that can need to be reloaded into a register. + + Therefore, when given such a pair of operands, the pattern must + generate RTL which needs no reloading and needs no temporary + registers--no registers other than the operands. For example, + if you support the pattern with a `define_expand', then in such + a case the `define_expand' mustn't call `force_reg' or any other + such function which might generate new pseudo registers. + + This requirement exists even for subword modes on a RISC machine + where fetching those modes from memory normally requires several + insns and some temporary registers. Look in `spur.md' to see + how the requirement can be satisfied. + + The variety of operands that have reloads depends on the rest of + the machine description, but typically on a RISC machine these + can only be pseudo registers that did not get hard registers, + while on other machines explicit memory references will get + optional reloads. + + The constraints on a `moveM' must allow any hard register to be + moved to any other hard register (provided that + `HARD_REGNO_MODE_OK' permits mode M in both registers). + + It is obligatory to support floating point `moveM' instructions + into and out of any registers that can hold fixed point values, + because unions and structures (which have modes `SImode' or + `DImode') can be in those registers and they may have floating + point members. + + There may also be a need to support fixed point `moveM' + 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 `HARD_REGNO_MODE_OK' rejects + fixed point values in floating point registers, then the + constraints of the fixed point `moveM' instructions must be + designed to avoid ever trying to reload into a floating point + register. + +`movstrictM' + Like `movM' except that if operand 0 is a `subreg' with mode M + of a register whose natural mode is wider, the `movstrictM' + instruction is guaranteed not to alter any of the register + except the part which belongs to mode M. + +`addM3' + Add operand 2 and operand 1, storing the result in operand 0. + All operands must have mode M. This can be used even on + two-address machines, by means of constraints requiring operands + 1 and 0 to be the same location. + +`subM3', `mulM3', `umulM3', `divM3', `udivM3', `modM3', `umodM3', `andM3', `iorM3', `xorM3' + Similar, for other arithmetic operations. + + There are special considerations for register classes for + logical-and instructions, affecting also the macro + `PREFERRED_RELOAD_CLASS'. They apply not only to the patterns + with these standard names, but to any patterns that will match + such an instruction. *Note Register Classes::. + +`mulhisi3' + Multiply operands 1 and 2, which have mode `HImode', and store a + `SImode' product in operand 0. + +`mulqihi3', `mulsidi3' + Similar widening-multiplication instructions of other widths. + +`umulqihi3', `umulhisi3', `umulsidi3' + Similar widening-multiplication instructions that do unsigned + multiplication. + +`divmodM4' + Signed division that produces both a quotient and a remainder. + Operand 1 is divided by operand 2 to produce a quotient stored + in operand 0 and a remainder stored in operand 3. + +`udivmodM4' + Similar, but does unsigned division. + +`ashlM3' + Arithmetic-shift operand 1 left by a number of bits specified by + operand 2, and store the result in operand 0. Operand 2 has + mode `SImode', not mode M. + +`ashrM3', `lshlM3', `lshrM3', `rotlM3', `rotrM3' + Other shift and rotate instructions. + + Logical and arithmetic left shift are the same. Machines that + do not allow negative shift counts often have only one + instruction for shifting left. On such machines, you should + define a pattern named `ashlM3' and leave `lshlM3' undefined. + + There are special considerations for register classes for shift + instructions, affecting also the macro `PREFERRED_RELOAD_CLASS'. + They apply not only to the patterns with these standard names, + but to any patterns that will match such an instruction. *Note + Register Classes::. + +`negM2' + Negate operand 1 and store the result in operand 0. + +`absM2' + Store the absolute value of operand 1 into operand 0. + +`sqrtM2' + Store the square root of operand 1 into operand 0. + +`ffsM2' + Store into operand 0 one plus the index of the least significant + 1-bit of operand 1. If operand 1 is zero, store zero. M is the + mode of operand 0; operand 1's mode is specified by the + instruction pattern, and the compiler will convert the operand + to that mode before generating the instruction. + +`one_cmplM2' + Store the bitwise-complement of operand 1 into operand 0. + +`cmpM' + Compare operand 0 and operand 1, and set the condition codes. + The RTL pattern should look like this: + + (set (cc0) (compare (match_operand:M 0 ...) + (match_operand:M 1 ...))) + + Each such definition in the machine description, for integer + mode M, must have a corresponding `tstM' pattern, because + optimization can simplify the compare into a test when operand 1 + is zero. + +`tstM' + Compare operand 0 against zero, and set the condition codes. + The RTL pattern should look like this: + + (set (cc0) (match_operand:M 0 ...)) + +`movstrM' + Block move instruction. The addresses of the destination and + source strings are the first two operands, and both are in mode + `Pmode'. The number of bytes to move is the third operand, in + mode M. The fourth operand is the known shared alignment of the + source and destination, in the form of a `const_int' rtx. + +`cmpstrM' + Block compare instruction, with operands like `movstrM' except + that the two memory blocks are compared byte by byte in + lexicographic order. The effect of the instruction is to set + the condition codes. + +`floatMN2' + Convert signed integer operand 1 (valid for fixed point mode M) + to floating point mode N and store in operand 0 (which has mode + N). + +`floatunsMN2' + Convert unsigned integer operand 1 (valid for fixed point mode + M) to floating point mode N and store in operand 0 (which has + mode N). + +`fixMN2' + Convert operand 1 (valid for floating point mode M) to fixed + point mode N as a signed number and store in operand 0 (which + has mode N). This instruction's result is defined only when the + value of operand 1 is an integer. + +`fixunsMN2' + Convert operand 1 (valid for floating point mode M) to fixed + point mode N as an unsigned number and store in operand 0 (which + has mode N). This instruction's result is defined only when the + value of operand 1 is an integer. + +`ftruncM2' + Convert operand 1 (valid for floating point mode M) to an + integer value, still represented in floating point mode M, and + store it in operand 0 (valid for floating point mode M). + +`fix_truncMN2' + Like `fixMN2' but works for any floating point value of mode M + by converting the value to an integer. + +`fixuns_truncMN2' + Like `fixunsMN2' but works for any floating point value of mode + M by converting the value to an integer. + +`truncMN' + Truncate operand 1 (valid for mode M) to mode N and store in + operand 0 (which has mode N). Both modes must be fixed point or + both floating point. + +`extendMN' + Sign-extend operand 1 (valid for mode M) to mode N and store in + operand 0 (which has mode N). Both modes must be fixed point or + both floating point. + +`zero_extendMN' + Zero-extend operand 1 (valid for mode M) to mode N and store in + operand 0 (which has mode N). Both modes must be fixed point. + +`extv' + Extract a bit-field from operand 1 (a register or memory + operand), where operand 2 specifies the width in bits and + operand 3 the starting bit, and store it in operand 0. Operand + 0 must have `SImode'. Operand 1 may have mode `QImode' or + `SImode'; often `SImode' is allowed only for registers. + Operands 2 and 3 must be valid for `SImode'. + + The RTL generation pass generates this instruction only with + constants for operands 2 and 3. + + The bit-field value is sign-extended to a full word integer + before it is stored in operand 0. + +`extzv' + Like `extv' except that the bit-field value is zero-extended. + +`insv' + Store operand 3 (which must be valid for `SImode') into a + bit-field in operand 0, where operand 1 specifies the width in + bits and operand 2 the starting bit. Operand 0 may have mode + `QImode' or `SImode'; often `SImode' is allowed only for + registers. Operands 1 and 2 must be valid for `SImode'. + + The RTL generation pass generates this instruction only with + constants for operands 1 and 2. + +`sCOND' + Store zero or nonzero in the operand according to the condition + codes. Value stored is nonzero iff the condition COND is true. + COND is the name of a comparison operation expression code, such + as `eq', `lt' or `leu'. + + You specify the mode that the operand must have when you write + the `match_operand' expression. The compiler automatically sees + which mode you have used and supplies an operand of that mode. + + The value stored for a true condition must have 1 as its low + bit, or else must be negative. Otherwise the instruction is not + suitable and must be omitted from the machine description. You + must tell the compiler exactly which value is stored by defining + the macro `STORE_FLAG_VALUE'. + +`bCOND' + Conditional branch instruction. Operand 0 is a `label_ref' that + refers to the label to jump to. Jump if the condition codes + meet condition COND. + +`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 `SImode', except it is normally a + `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 to put this information into the assembler code; they + can put it in the RTL instead of operand 1. + + Operand 0 should be a `mem' RTX whose address is the address of + the function. + +`call_value' + Subroutine call instruction returning a value. Operand 0 is the + hard register in which the value is returned. There are three + more operands, the same as the three operands of the `call' + instruction (but with numbers increased by one). + + Subroutines that return `BLKmode' objects use the `call' insn. + +`return' + Subroutine return instruction. This instruction pattern name + should be defined only if a single instruction can do all the + work of returning from a function. + +`nop' + No-op instruction. This instruction pattern name should always + be defined to output a no-op in assembler code. `(const_int 0)' + will do as an RTL pattern. + +`casesi' + Instruction to jump through a dispatch table, including bounds + checking. This instruction takes five operands: + + 1. The index to dispatch on, which has mode `SImode'. + + 2. The lower bound for indices in the table, an integer + constant. + + 3. The total range of indices in the table--the largest index + minus the smallest one (both inclusive). + + 4. A label to jump to if the index has a value outside the + bounds. (If the machine-description macro + `CASE_DROPS_THROUGH' is defined, then an out-of-bounds + index drops through to the code following the jump table + instead of jumping to this label. In that case, this label + is not actually used by the `casesi' instruction, but it is + always provided as an operand.) + + 5. A label that precedes the table itself. + + The table is a `addr_vec' or `addr_diff_vec' inside of a + `jump_insn'. The number of elements in the table is one plus + the difference between the upper bound and the lower bound. + +`tablejump' + Instruction to jump to a variable address. This is a low-level + capability which can be used to implement a dispatch table when + there is no `casesi' pattern. + + This pattern requires two operands: the address or offset, and a + label which should immediately precede the jump table. If the + macro `CASE_VECTOR_PC_RELATIVE' is defined then the first + operand is an offset that counts from the address of the table; + otherwise, it is an absolute address to jump to. + + The `tablejump' insn is always the last insn before the jump + 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. + + +File: gcc.info, Node: Pattern Ordering, Next: Dependent Patterns, Prev: Standard Names, Up: Machine Desc + +When the Order of Patterns Matters +================================== + + Sometimes an insn can match more than one instruction pattern. +Then the pattern that appears first in the machine description is the +one used. Therefore, more specific patterns (patterns that will +match fewer things) and faster instructions (those that will produce +better code when they do match) should usually go first in the +description. + + In some cases the effect of ordering the patterns can be used to +hide a pattern when it is not valid. For example, the 68000 has an +instruction for converting a fullword to floating point and another +for converting a byte to floating point. An instruction converting +an integer to floating point could match either one. We put the +pattern to convert the fullword first to make sure that one will be +used rather than the other. (Otherwise a large integer might be +generated as a single-byte immediate quantity, which would not work.) +Instead of using this pattern ordering it would be possible to make +the pattern for convert-a-byte smart enough to deal properly with any +constant value. + + +File: gcc.info, Node: Dependent Patterns, Next: Jump Patterns, Prev: Pattern Ordering, Up: Machine Desc + +Interdependence of Patterns +=========================== + + Every machine description must have a named pattern for each of +the conditional branch names `bCOND'. The recognition template must +always have the form + + (set (pc) + (if_then_else (COND (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc))) + +In addition, every machine description must have an anonymous pattern +for each of the possible reverse-conditional branches. These +patterns look like + + (set (pc) + (if_then_else (COND (cc0) (const_int 0)) + (pc) + (label_ref (match_operand 0 "" "")))) + +They are necessary because jump optimization can turn +direct-conditional branches into reverse-conditional branches. + + The compiler does more with RTL than just create it from patterns +and recognize the patterns: it can perform arithmetic expression +codes when constant values for their operands can be determined. As +a result, sometimes having one pattern can require other patterns. +For example, the Vax has no `and' instruction, but it has `and not' +instructions. Here is the definition of one of them: + + (define_insn "andcbsi2" + [(set (match_operand:SI 0 "general_operand" "") + (and:SI (match_dup 0) + (not:SI (match_operand:SI + 1 "general_operand" ""))))] + "" + "bicl2 %1,%0") + +If operand 1 is an explicit integer constant, an instruction +constructed using that pattern can be simplified into an `and' like +this: + + (set (reg:SI 41) + (and:SI (reg:SI 41) + (const_int 0xffff7fff))) + +(where the integer constant is the one's complement of what appeared +in the original instruction). + + To avoid a fatal error, the compiler must have a pattern that +recognizes such an instruction. Here is what is used: + + (define_insn "" + [(set (match_operand:SI 0 "general_operand" "") + (and:SI (match_dup 0) + (match_operand:SI 1 "general_operand" "")))] + "GET_CODE (operands[1]) == CONST_INT" + "* + { operands[1] + = gen_rtx (CONST_INT, VOIDmode, ~INTVAL (operands[1])); + return \"bicl2 %1,%0\"; + }") + +Whereas a pattern to match a general `and' instruction is impossible +to support on the Vax, this pattern is possible because it matches +only a constant second argument: a special case that can be output as +an `and not' instruction. + + A "compare" instruction whose RTL looks like this: + + (set (cc0) (compare OPERAND (const_int 0))) + +may be simplified by optimization into a "test" like this: + + (set (cc0) OPERAND) + +So in the machine description, each "compare" pattern for an integer +mode must have a corresponding "test" pattern that will match the +result of such simplification. + + In some cases machines support instructions identical except for +the machine mode of one or more operands. For example, there may be +"sign-extend halfword" and "sign-extend byte" instructions whose +patterns are + + (set (match_operand:SI 0 ...) + (extend:SI (match_operand:HI 1 ...))) + + (set (match_operand:SI 0 ...) + (extend:SI (match_operand:QI 1 ...))) + +Constant integers do not specify a machine mode, so an instruction to +extend a constant value could match either pattern. The pattern it +actually will match is the one that appears first in the file. For +correct results, this must be the one for the widest possible mode +(`HImode', here). If the pattern matches the `QImode' instruction, +the results will be incorrect if the constant value does not actually +fit that mode. + + Such instructions to extend constants are rarely generated because +they are optimized away, but they do occasionally happen in +nonoptimized compilations. + + When an instruction has the constraint letter `o', the reload pass +may generate instructions which copy a nonoffsettable address into an +index register. The idea is that the register can be used as a +replacement offsettable address. In order for these generated +instructions to work, there must be patterns to copy any kind of +valid address into a register. + + Most older machine designs have "load address" instructions which +do just what is needed here. Some RISC machines do not advertise +such instructions, but the possible addresses on these machines are +very limited, so it is easy to fake them. + + Auto-increment and auto-decrement addresses are an exception; +there need not be an instruction that can copy such an address into a +register, because reload handles these cases in a different manner. + + +File: gcc.info, Node: Jump Patterns, Next: Peephole Definitions, Prev: Dependent Patterns, Up: Machine Desc + +Defining Jump Instruction Patterns +================================== + + GNU CC assumes that the machine has a condition code. A +comparison insn sets the condition code, recording the results of +both signed and unsigned comparison of the given operands. A +separate branch insn tests the condition code and branches or not +according its value. The branch insns come in distinct signed and +unsigned flavors. Many common machines, such as the Vax, the 68000 +and the 32000, work this way. + + Some machines have distinct signed and unsigned compare +instructions, and only one set of conditional branch instructions. +The easiest way to handle these machines is to treat them just like +the others until the final stage where assembly code is written. At +this time, when outputting code for the compare instruction, peek +ahead at the following branch using `NEXT_INSN (insn)'. (The +variable `insn' refers to the insn being output, in the +output-writing code in an instruction pattern.) If the RTL says that +is an unsigned branch, output an unsigned compare; otherwise output a +signed compare. When the branch itself is output, you can treat +signed and unsigned branches identically. + + The reason you can do this is that GNU CC always generates a pair +of consecutive RTL insns, one to set the condition code and one to +test it, and keeps the pair inviolate until the end. + + To go with this technique, you must define the machine-description +macro `NOTICE_UPDATE_CC' to do `CC_STATUS_INIT'; in other words, no +compare instruction is superfluous. + + Some machines have compare-and-branch instructions and no +condition code. A similar technique works for them. When it is time +to "output" a compare instruction, record its operands in two static +variables. When outputting the branch-on-condition-code instruction +that follows, actually output a compare-and-branch instruction that +uses the remembered operands. + + It also works to define patterns for compare-and-branch +instructions. In optimizing compilation, the pair of compare and +branch instructions will be combined according to these patterns. +But this does not happen if optimization is not requested. So you +must use one of the solutions above in addition to any special +patterns you define. + + +File: gcc.info, Node: Peephole Definitions, Next: Expander Definitions, Prev: Jump Patterns, Up: Machine Desc + +Defining Machine-Specific Peephole Optimizers +============================================= + + In addition to instruction patterns the `md' file may contain +definitions of machine-specific peephole optimizations. + + The combiner does not notice certain peephole optimizations when +the data flow in the program does not suggest that it should try +them. For example, sometimes two consecutive insns related in +purpose can be combined even though the second one does not appear to +use a register computed in the first one. A machine-specific +peephole optimizer can detect such opportunities. + + A definition looks like this: + + (define_peephole + [INSN-PATTERN-1 + INSN-PATTERN-2 + ...] + "CONDITION" + "TEMPLATE" + "MACHINE-SPECIFIC INFO") + +The last string operand may be omitted if you are not using any +machine-specific information in this machine description. If +present, it must obey the same rules as in a `define_insn'. + + In this skeleton, INSN-PATTERN-1 and so on are patterns to match +consecutive insns. The optimization applies to a sequence of insns +when INSN-PATTERN-1 matches the first one, INSN-PATTERN-2 matches the +next, and so on. + + Each of the insns matched by a peephole must also match a +`define_insn'. Peepholes are checked only at the last stage just +before code generation, and only optionally. Therefore, any insn +which would match a peephole but no `define_insn' will cause a crash +in code generation in an unoptimized compilation, or at various +optimization stages. + + The operands of the insns are matched with `match_operands' and +`match_dup', as usual. What is not usual is that the operand numbers +apply to all the insn patterns in the definition. So, you can check +for identical operands in two insns by using `match_operand' in one +insn and `match_dup' in the other. + + The operand constraints used in `match_operand' patterns do not +have any direct effect on the applicability of the peephole, but they +will be validated afterward, so make sure your constraints are +general enough to apply whenever the peephole matches. If the +peephole matches but the constraints are not satisfied, the compiler +will crash. + + It is safe to omit constraints in all the operands of the +peephole; or you can write constraints which serve as a double-check +on the criteria previously tested. + + Once a sequence of insns matches the patterns, the CONDITION is +checked. This is a C expression which makes the final decision +whether to perform the optimization (we do so if the expression is +nonzero). If CONDITION is omitted (in other words, the string is +empty) then the optimization is applied to every sequence of insns +that matches the patterns. + + The defined peephole optimizations are applied after register +allocation is complete. Therefore, the peephole definition can check +which operands have ended up in which kinds of registers, just by +looking at the operands. + + The way to refer to the operands in CONDITION is to write +`operands[I]' for operand number I (as matched by `(match_operand I +...)'). Use the variable `insn' to refer to the last of the insns +being matched; use `PREV_INSN' to find the preceding insns (but be +careful to skip over any `note' insns that intervene). + + When optimizing computations with intermediate results, you can +use CONDITION to match only when the intermediate results are not +used elsewhere. Use the C expression `dead_or_set_p (INSN, OP)', +where INSN is the insn in which you expect the value to be used for +the last time (from the value of `insn', together with use of +`PREV_INSN'), and OP is the intermediate value (from `operands[I]'). + + Applying the optimization means replacing the sequence of insns +with one new insn. The TEMPLATE controls ultimate output of +assembler code for this combined insn. It works exactly like the +template of a `define_insn'. Operand numbers in this template are +the same ones used in matching the original sequence of insns. + + The result of a defined peephole optimizer does not need to match +any of the insn patterns in the machine description; it does not even +have an opportunity to match them. The peephole optimizer definition +itself serves as the insn pattern to control how the insn is output. + + Defined peephole optimizers are run as assembler code is being +output, so the insns they produce are never combined or rearranged in +any way. + + Here is an example, taken from the 68000 machine description: + + (define_peephole + [(set (reg:SI 15) (plus:SI (reg:SI 15) (const_int 4))) + (set (match_operand:DF 0 "register_operand" "f") + (match_operand:DF 1 "register_operand" "ad"))] + "FP_REG_P (operands[0]) && ! FP_REG_P (operands[1])" + "* + { + rtx xoperands[2]; + xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1); + #ifdef MOTOROLA + output_asm_insn (\"move.l %1,(sp)\", xoperands); + output_asm_insn (\"move.l %1,-(sp)\", operands); + return \"fmove.d (sp)+,%0\"; + #else + output_asm_insn (\"movel %1,sp@\", xoperands); + output_asm_insn (\"movel %1,sp@-\", operands); + return \"fmoved sp@+,%0\"; + #endif + } + ") + + The effect of this optimization is to change + + jbsr _foobar + addql #4,sp + movel d1,sp@- + movel d0,sp@- + fmoved sp@+,fp0 + +into + + jbsr _foobar + movel d1,sp@ + movel d0,sp@- + fmoved sp@+,fp0 + + INSN-PATTERN-1 and so on look *almost* like the second operand of +`define_insn'. There is one important difference: the second operand +of `define_insn' consists of one or more RTX's enclosed in square +brackets. Usually, there is only one: then the same action can be +written as an element of a `define_peephole'. But when there are +multiple actions in a `define_insn', they are implicitly enclosed in +a `parallel'. Then you must explicitly write the `parallel', and the +square brackets within it, in the `define_peephole'. Thus, if an +insn pattern looks like this, + + (define_insn "divmodsi4" + [(set (match_operand:SI 0 "general_operand" "=d") + (div:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "dmsK"))) + (set (match_operand:SI 3 "general_operand" "=d") + (mod:SI (match_dup 1) (match_dup 2)))] + "TARGET_68020" + "divsl%.l %2,%3:%0") + +then the way to mention this insn in a peephole is as follows: + + (define_peephole + [... + (parallel + [(set (match_operand:SI 0 "general_operand" "=d") + (div:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "dmsK"))) + (set (match_operand:SI 3 "general_operand" "=d") + (mod:SI (match_dup 1) (match_dup 2)))]) + ...] + ...) + + +File: gcc.info, Node: Expander Definitions, Prev: Peephole Definitions, Up: Machine Desc + +Defining RTL Sequences for Code Generation +========================================== + + On some target machines, some standard pattern names for RTL +generation cannot be handled with single insn, but a sequence of RTL +insns can represent them. For these target machines, you can write a +`define_expand' to specify how to generate the sequence of RTL. + + A `define_expand' is an RTL expression that looks almost like a +`define_insn'; but, unlike the latter, a `define_expand' is used only +for RTL generation and it can produce more than one RTL insn. + + A `define_expand' RTX has four operands: + + * The name. Each `define_expand' must have a name, since the only + use for it is to refer to it by name. + + * The RTL template. This is just like the RTL template for a + `define_peephole' in that it is a vector of RTL expressions each + being one insn. + + * The condition, a string containing a C expression. This + expression is used to express how the availability of this + pattern depends on subclasses of target machine, selected by + command-line options when GNU CC is run. This is just like the + condition of a `define_insn' that has a standard name. + + * The preparation statements, a string containing zero or more C + statements which are to be executed before RTL code is generated + from the RTL template. + + Usually these statements prepare temporary registers for use as + internal operands in the RTL template, but they can also + generate RTL insns directly by calling routines such as + `emit_insn', etc. Any such insns precede the ones that come + from the RTL template. + + Every RTL insn emitted by a `define_expand' must match some +`define_insn' in the machine description. Otherwise, the compiler +will crash when trying to generate code for the insn or trying to +optimize it. + + The RTL template, in addition to controlling generation of RTL +insns, also describes the operands that need to be specified when +this pattern is used. In particular, it gives a predicate for each +operand. + + A true operand, which need to be specified in order to generate +RTL from the pattern, should be described with a `match_operand' in +its first occurrence in the RTL template. This enters information on +the operand's predicate into the tables that record such things. GNU +CC uses the information to preload the operand into a register if +that is required for valid RTL code. If the operand is referred to +more than once, subsequent references should use `match_dup'. + + The RTL template may also refer to internal "operands" which are +temporary registers or labels used only within the sequence made by +the `define_expand'. Internal operands are substituted into the RTL +template with `match_dup', never with `match_operand'. The values of +the internal operands are not passed in as arguments by the compiler +when it requests use of this pattern. Instead, they are computed +within the pattern, in the preparation statements. These statements +compute the values and store them into the appropriate elements of +`operands' so that `match_dup' can find them. + + There are two special macros defined for use in the preparation +statements: `DONE' and `FAIL'. Use them with a following semicolon, +as a statement. + +`DONE' + Use the `DONE' macro to end RTL generation for the pattern. The + only RTL insns resulting from the pattern on this occasion will + be those already emitted by explicit calls to `emit_insn' within + the preparation statements; the RTL template will not be + generated. + +`FAIL' + Make the pattern fail on this occasion. When a pattern fails, + it means that the pattern was not truly available. The calling + routines in the compiler will try other strategies for code + generation using other patterns. + + Failure is currently supported only for binary operations + (addition, multiplication, shifting, etc.). + + Do not emit any insns explicitly with `emit_insn' before failing. + + Here is an example, the definition of left-shift for the SPUR chip: + + (define_expand "ashlsi3" + [(set (match_operand:SI 0 "register_operand" "") + (ashift:SI + (match_operand:SI 1 "register_operand" "") + (match_operand:SI 2 "nonmemory_operand" "")))] + "" + " + { + if (GET_CODE (operands[2]) != CONST_INT + || (unsigned) INTVAL (operands[2]) > 3) + FAIL; + }") + +This example uses `define_expand' so that it can generate an RTL insn +for shifting when the shift-count is in the supported range of 0 to 3 +but fail in other cases where machine insns aren't available. When +it fails, the compiler tries another strategy using different +patterns (such as, a library call). + + If the compiler were able to handle nontrivial condition-strings +in patterns with names, then it would be possible to use a +`define_insn' in that case. Here is another case (zero-extension on +the 68000) which makes more use of the power of `define_expand': + + (define_expand "zero_extendhisi2" + [(set (match_operand:SI 0 "general_operand" "") + (const_int 0)) + (set (strict_low_part + (subreg:HI + (match_dup 0) + 0)) + (match_operand:HI 1 "general_operand" ""))] + "" + "operands[1] = make_safe_from (operands[1], operands[0]);") + +Here two RTL insns are generated, one to clear the entire output +operand and the other to copy the input operand into its low half. +This sequence is incorrect if the input operand refers to [the old +value of] the output operand, so the preparation statement makes sure +this isn't so. The function `make_safe_from' copies the +`operands[1]' into a temporary register if it refers to +`operands[0]'. It does this by emitting another RTL insn. + + Finally, a third example shows the use of an internal operand. +Zero-extension on the SPUR chip is done by `and'-ing the result +against a halfword mask. But this mask cannot be represented by a +`const_int' because the constant value is too large to be legitimate +on this machine. So it must be copied into a register with +`force_reg' and then the register used in the `and'. + + (define_expand "zero_extendhisi2" + [(set (match_operand:SI 0 "register_operand" "") + (and:SI (subreg:SI + (match_operand:HI 1 "register_operand" "") + 0) + (match_dup 2)))] + "" + "operands[2] + = force_reg (SImode, gen_rtx (CONST_INT, + VOIDmode, 65535)); ") + + *Note:* If the `define_expand' is used to serve a standard binary +or unary arithmetic operation, then the last insn it generates must +not be a `code_label', `barrier' or `note'. It must be an `insn', +`jump_insn' or `call_insn'. + + +File: gcc.info, Node: Machine Macros, Next: Config, Prev: Machine Desc, Up: Top + +Machine Description Macros +************************** + + The other half of the machine description is a C header file +conventionally given the name `tm-MACHINE.h'. The file `tm.h' should +be a link to it. The header file `config.h' includes `tm.h' and most +compiler source files include `config.h'. + +* Menu: + +* Run-time Target:: Defining `-m' options like `-m68000' and `-m68020'. +* Storage Layout:: Defining sizes and alignments of data types. +* Registers:: Naming and describing the hardware registers. +* Register Classes:: Defining the classes of hardware registers. +* Stack Layout:: Defining which way the stack grows and by how much. +* Library Calls:: Specifying how to call certain library routines. +* Addressing Modes:: Defining addressing modes valid for memory operands. +* Delayed Branch:: Do branches execute the following instruction? +* Condition Code:: Defining how insns update the condition code. +* Cross-compilation:: Handling floating point for cross-compilers. +* Misc:: Everything else. +* Assembler Format:: Defining how to write insns and pseudo-ops to output. + + +File: gcc.info, Node: Run-time Target, Next: Storage Layout, Prev: Machine Macros, Up: Machine Macros + +Run-time Target Specification +============================= + +`CPP_PREDEFINES' + Define this to be a string constant containing `-D' options to + define the predefined macros that identify this machine and + system. These macros will be predefined unless the `-ansi' + option is specified. + + In addition, a parallel set of macros are predefined, whose + names are made by appending `__' at the beginning and at the + end. These `__' macros are permitted by the ANSI standard, so + they are predefined regardless of whether `-ansi' is specified. + + For example, on the Sun, one can use the following value: + + "-Dmc68000 -Dsun -Dunix" + + The result is to define the macros `__mc68000__', `__sun__' and + `__unix__' unconditionally, and the macros `mc68000', `sun' and + `unix' provided `-ansi' is not specified. + +`CPP_SPEC' + A C string constant that tells the GNU CC driver program options + to pass to CPP. It can also specify how to translate options + you give to GNU CC into options for GNU CC to pass to the CPP. + + Do not define this macro if it does not need to do anything. + +`CC1_SPEC' + A C string constant that tells the GNU CC driver program options + to pass to CC1. It can also specify how to translate options + you give to GNU CC into options for GNU CC to pass to the CC1. + + Do not define this macro if it does not need to do anything. + +`extern int target_flags;' + This declaration should be present. + +`TARGET_...' + This series of macros is to allow compiler command arguments to + enable or disable the use of optional features of the target + machine. For example, one machine description serves both the + 68000 and the 68020; a command argument tells the compiler + whether it should use 68020-only instructions or not. This + command argument works by means of a macro `TARGET_68020' that + tests a bit in `target_flags'. + + Define a macro `TARGET_FEATURENAME' for each such option. Its + definition should test a bit in `target_flags'; for example: + + #define TARGET_68020 (target_flags & 1) + + One place where these macros are used is in the + condition-expressions of instruction patterns. Note how + `TARGET_68020' appears frequently in the 68000 machine + description file, `m68k.md'. Another place they are used is in + the definitions of the other macros in the `tm-MACHINE.h' file. + +`TARGET_SWITCHES' + This macro defines names of command options to set and clear + bits in `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 + `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 `-m' to the specified name. + + One of the subgroupings should have a null string. The number + in this grouping is the default value for `target_flags'. Any + target options act starting with that value. + + Here is an example which defines `-m68000' and `-m68020' with + opposite meanings, and picks the latter as the default: + + #define TARGET_SWITCHES \ + { { "68020", 1}, \ + { "68000", -1}, \ + { "", 1}} + +`OVERRIDE_OPTIONS' + 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. + + +File: gcc.info, Node: Storage Layout, Next: Registers, Prev: Run-time Target, Up: Machine Macros + +Storage Layout +============== + + Note that the definitions of the macros in this table which are +sizes or alignments measured in bits do not need to be constant. +They can be C expressions that refer to static variables, such as the +`target_flags'. *Note Run-time Target::. + +`BITS_BIG_ENDIAN' + Define this macro if the most significant bit in a byte has the + lowest number. This means that bit-field instructions count + from the most significant bit. If the machine has no bit-field + instructions, this macro is irrelevant. + + This macro does not affect the way structure fields are packed + into bytes or words; that is controlled by `BYTES_BIG_ENDIAN'. + +`BYTES_BIG_ENDIAN' + Define this macro if the most significant byte in a word has the + lowest number. + +`WORDS_BIG_ENDIAN' + Define this macro if, in a multiword object, the most + significant word has the lowest number. + +`BITS_PER_UNIT' + Number of bits in an addressable storage unit (byte); normally 8. + +`BITS_PER_WORD' + Number of bits in a word; normally 32. + +`UNITS_PER_WORD' + Number of storage units in a word; normally 4. + +`POINTER_SIZE' + Width of a pointer, in bits. + +`POINTER_BOUNDARY' + Alignment required for pointers stored in memory, in bits. + +`PARM_BOUNDARY' + Normal alignment required for function parameters on the stack, + in bits. All stack parameters receive least this much alignment + regardless of data type. On most machines, this is the same as + the size of an integer. + +`MAX_PARM_BOUNDARY' + Largest alignment required for any stack parameters, in bits. + If the data type of the parameter calls for more alignment than + `PARM_BOUNDARY', then it is given extra padding up to this limit. + + Don't define this macro if it would be equal to `PARM_BOUNDARY'; + in other words, if the alignment of a stack parameter should not + depend on its data type (as is the case on most machines). + +`STACK_BOUNDARY' + Define this macro if you wish to preserve a certain alignment + for the stack pointer at all times. The definition is a C + expression for the desired alignment (measured in bits). + +`FUNCTION_BOUNDARY' + Alignment required for a function entry point, in bits. + +`BIGGEST_ALIGNMENT' + Biggest alignment that any data type can require on this + machine, in bits. + +`CONSTANT_ALIGNMENT (CODE, TYPEALIGN)' + A C expression to compute the alignment for a constant. The + argument TYPEALIGN is the alignment required for the constant's + data type. CODE is the tree code of the constant itself. + + If this macro is not defined, the default is to use TYPEALIGN. + If you do define this macro, the value must be a multiple of + TYPEALIGN. + + The purpose of defining this macro is usually to cause string + constants to be word aligned so that `dhrystone' can be made to + run faster. + +`EMPTY_FIELD_BOUNDARY' + Alignment in bits to be given to a structure bit field that + follows an empty field such as `int : 0;'. + +`STRUCTURE_SIZE_BOUNDARY' + Number of bits which any structure or union's size must be a + multiple of. Each structure or union's size is rounded up to a + multiple of this. + + If you do not define this macro, the default is the same as + `BITS_PER_UNIT'. + +`STRICT_ALIGNMENT' + Define this if instructions will fail to work if given data not + on the nominal alignment. If instructions will merely go slower + in that case, do not define this macro. + +`PCC_BITFIELD_TYPE_MATTERS' + Define this if you wish to imitate a certain bizarre behavior + pattern of some instances of PCC: a bit field whose declared + type is `int' has the same effect on the size and alignment of a + structure as an actual `int' would have. + + If the macro is defined, then its definition should be a C + expression; a nonzero value for the expression enables + PCC-compatible behavior. + + Just what effect that is in GNU CC depends on other parameters, + but on most machines it would force the structure's alignment + and size to a multiple of 32 or `BIGGEST_ALIGNMENT' bits. + +`MAX_FIXED_MODE_SIZE' + An integer expression for the largest integer machine mode that + should actually be used. All integer machine modes of this size + or smaller can be used for structures and unions with the + appropriate sizes. + +`CHECK_FLOAT_VALUE (MODE, VALUE)' + A C statement to validate the value VALUE (or type `double') for + mode MODE. This means that you check whether VALUE fits within + the possible range of values for mode MODE on this target + machine. The mode MODE is always `SFmode' or `DFmode'. + + If VALUE is not valid, you should call `error' to print an error + message and then assign some valid value to VALUE. Allowing an + invalid value to go through the compiler can produce incorrect + assembler code which may even cause Unix assemblers to crash. + + This macro need not be defined if there is no work for it to do. + + \ No newline at end of file diff --git a/gcc-1.40/gcc.info-9 b/gcc-1.40/gcc.info-9 new file mode 100644 index 0000000..2540b06 --- /dev/null +++ b/gcc-1.40/gcc.info-9 @@ -0,0 +1,1066 @@ +Info file gcc.info, produced by Makeinfo, -*- Text -*- from input +file gcc.texinfo. + + This file documents the use and the internals of the GNU compiler. + + Copyright (C) 1988, 1989, 1990 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. + + 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" and "Protect +Your Freedom--Fight `Look And Feel'" 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" and "Protect Your Freedom--Fight `Look And Feel'" and this +permission notice may be included in translations approved by the +Free Software Foundation instead of in the original English. + + +File: gcc.info, Node: Registers, Next: Register Classes, Prev: Storage Layout, Up: Machine Macros + +Register Usage +============== + +`FIRST_PSEUDO_REGISTER' + Number of hardware registers known to the compiler. They + receive numbers 0 through `FIRST_PSEUDO_REGISTER-1'; thus, the + first pseudo register's number really is assigned the number + `FIRST_PSEUDO_REGISTER'. + +`FIXED_REGISTERS' + An initializer that says which registers are used for fixed + purposes all throughout the compiled code and are therefore not + available for general allocation. These would include the stack + pointer, the frame pointer (except on machines where that can be + used as a general register when no frame pointer is needed), the + program counter on machines where that is considered one of the + addressable registers, and any other numbered register with a + standard use. + + This information is expressed as a sequence of numbers, + separated by commas and surrounded by braces. The Nth number is + 1 if register N is fixed, 0 otherwise. + + The table initialized from this macro, and the table initialized + by the following one, may be overridden at run time either + automatically, by the actions of the macro + `CONDITIONAL_REGISTER_USAGE', or by the user with the command + options `-ffixed-REG', `-fcall-used-REG' and `-fcall-saved-REG'. + +`CALL_USED_REGISTERS' + Like `FIXED_REGISTERS' but has 1 for each register that is + clobbered (in general) by function calls as well as for fixed + registers. This macro therefore identifies the registers that + are not available for general allocation of values that must + live across function calls. + + If a register has 0 in `CALL_USED_REGISTERS', the compiler + automatically saves it on function entry and restores it on + function exit, if the register is used within the function. + +`DEFAULT_CALLER_SAVES' + Define this macro if function calls on the target machine do not + preserve any registers; in other words, if `CALL_USED_REGISTERS' + has 1 for all registers. This macro enables `-fcaller-saves' by + default. Eventually that option will be enabled by default on + all machines and both the option and this macro will be + eliminated. + +`CONDITIONAL_REGISTER_USAGE' + Zero or more C statements that may conditionally modify two + variables `fixed_regs' and `call_used_regs' (both of type `char + []') after they have been initialized from the two preceding + macros. + + This is necessary in case the fixed or call-clobbered registers + depend on target flags. + + You need not define this macro if it has no work to do. + + 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 `fixed_regs' and `call_used_regs' to 1 for each of the + registers in the classes which should not be used by GCC. Also + define the macro `REG_CLASS_FROM_LETTER' to return `NO_REGS' if + it is called with a letter for a class that shouldn't be used. + + (However, if this class is not included in `GENERAL_REGS' and + all of the insn patterns whose constraints permit this class are + controlled by target switches, then GCC will automatically avoid + using these registers when the target switches are opposed to + them.) + +`OVERLAPPING_REGNO_P (REGNO)' + If defined, this is a C expression whose value is nonzero if + hard register number REGNO is an overlapping register. This + means a hard register which overlaps a hard register with a + different number. (Such overlap is undesirable, but + occasionally it allows a machine to be supported which otherwise + could not be.) This macro must return nonzero for *all* the + registers which overlap each other. GNU CC can use an + overlapping register only in certain limited ways. It can be + used for allocation within a basic block, and may be spilled for + reloading; that is all. + + If this macro is not defined, it means that none of the hard + registers overlap each other. This is the usual situation. + +`INSN_CLOBBERS_REGNO_P (INSN, REGNO)' + If defined, this is a C expression whose value should be nonzero + if the insn INSN has the effect of mysteriously clobbering the + contents of hard register number REGNO. By "mysterious" we mean + that the insn's RTL expression doesn't describe such an effect. + + If this macro is not defined, it means that no insn clobbers + registers mysteriously. This is the usual situation; all else + being equal, it is best for the RTL expression to show all the + activity. + +`PRESERVE_DEATH_INFO_REGNO_P (REGNO)' + If defined, this is a C expression whose value is nonzero if + accurate `REG_DEAD' notes are needed for hard register number + 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. + + 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 code looks at the death notes. This is + necessary only when the actual 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.) + + If this macro is not defined, it means that no death notes need + to be preserved. This is the usual situation. + +`HARD_REGNO_NREGS (REGNO, MODE)' + A C expression for the number of consecutive hard registers, + starting at register number REGNO, required to hold a value of + mode MODE. + + On a machine where all registers are exactly one word, a + suitable definition of this macro is + + #define HARD_REGNO_NREGS(REGNO, MODE) \ + ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) \ + / UNITS_PER_WORD)) + +`HARD_REGNO_MODE_OK (REGNO, MODE)' + A C expression that is nonzero if it is permissible to store a + value of mode MODE in hard register number REGNO (or in several + registers starting with that one). For a machine where all + registers are equivalent, a suitable definition is + + #define HARD_REGNO_MODE_OK(REGNO, MODE) 1 + + 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. + + 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. + + 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 `HARD_REGNO_MODE_OK' must not allow this mode in + those registers. + + Many machines have special registers for floating point + arithmetic. Often people assume that floating point machine + modes are allowed only in floating point registers. This is not + true. Any registers that can hold integers can safely *hold* a + floating point machine mode, whether or not floating arithmetic + can be done on it in those registers. + + On some machines, though, the converse is true: fixed-point + machine modes may not go in floating registers. This is true if + the floating registers normalize any value stored in them, + because storing a non-floating value there would garble it. In + this case, `HARD_REGNO_MODE_OK' should reject fixed-point + machine modes in floating registers. But if the floating + registers do not automatically normalize, if you can store any + bit pattern in one and retrieve it unchanged without a trap, + then any machine mode may go in a floating register and this + macro should say so. + + The primary significance of special floating registers is rather + that they are the registers acceptable in floating point + arithmetic instructions. However, this is of no concern to + `HARD_REGNO_MODE_OK'. You handle it by writing the proper + constraints for those instructions. + + On some machines, the floating registers are especially slow to + access, so that it is better to store a value in a stack frame + than in such a register if floating point arithmetic is not + being done. As long as the floating registers are not in class + `GENERAL_REGS', they will not be used unless some insn's + constraint asks for one. + +`MODES_TIEABLE_P (MODE1, 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 MODE1 and a value of mode MODE2. + + If `HARD_REGNO_MODE_OK (R, MODE1)' and `HARD_REGNO_MODE_OK (R, + MODE2)' are ever different for any R, then `MODES_TIEABLE_P + (MODE1, MODE2)' must be zero. + +`PC_REGNUM' + If the program counter has a register number, define this as + that register number. Otherwise, do not define it. + +`STACK_POINTER_REGNUM' + The register number of the stack pointer register, which must + also be a fixed register according to `FIXED_REGISTERS'. On + many machines, the hardware determines which register this is. + +`FRAME_POINTER_REGNUM' + The register number of the frame pointer register, which is used + to access automatic variables in the stack frame. On some + machines, the hardware determines which register this is. On + other machines, you can choose any register you wish for this + purpose. + +`FRAME_POINTER_REQUIRED' + A C expression which is nonzero if a function must have and use + a frame pointer. This expression is evaluated twice: at the + beginning of generating RTL, and in the reload pass. If its + value is nonzero at either time, then the function will have a + frame pointer. + + The expression can in principle examine the current function and + decide according to the facts, but on most machines the constant + 0 or the constant 1 suffices. Use 0 when the machine allows + code to be generated with no frame pointer, and doing so saves + some time or space. Use 1 when there is no possible advantage + to avoiding a frame pointer. + + In certain cases, the compiler does not know how to produce + valid code without a frame pointer. The compiler recognizes + those cases and automatically gives the function a frame pointer + regardless of what `FRAME_POINTER_REQUIRED' says. You don't + need to worry about them. + + In a function that does not require a frame pointer, the frame + pointer register can be allocated for ordinary usage, unless you + mark it as a fixed register. See `FIXED_REGISTERS' for more + information. + +`ARG_POINTER_REGNUM' + The register number of the arg pointer register, which is used + to access the function's argument list. On some machines, this + is the same as the frame pointer register. On some machines, + the hardware determines which register this is. On other + machines, you can choose any register you wish for this purpose. + If this is not the same register as the frame pointer register, + then you must mark it as a fixed register according to + `FIXED_REGISTERS'. + +`STATIC_CHAIN_REGNUM' + The register number used for passing a function's static chain + pointer. This is needed for languages such as Pascal and Algol + where functions defined within other functions can access the + local variables of the outer functions; it is not currently used + because C does not provide this feature, but you must define the + macro. + + The static chain register need not be a fixed register. + +`STRUCT_VALUE_REGNUM' + When a function's value's mode is `BLKmode', the value is not + returned according to `FUNCTION_VALUE'. Instead, the caller + passes the address of a block of memory in which the value + should be stored. + + If this value is passed in a register, then + `STRUCT_VALUE_REGNUM' should be the number of that register. + +`STRUCT_VALUE' + If the structure value address is not passed in a register, + define `STRUCT_VALUE' as an expression returning an RTX for the + place where the address is passed. If it returns a `mem' RTX, + the address is passed as an "invisible" first argument. + +`STRUCT_VALUE_INCOMING_REGNUM' + On some architectures the place where the structure value + address is found by the called function is not the same place + that the caller put it. This can be due to register windows, or + it could be because the function prologue moves it to a + different place. + + If the incoming location of the structure value address is in a + register, define this macro as the register number. + +`STRUCT_VALUE_INCOMING' + If the incoming location is not a register, define + `STRUCT_VALUE_INCOMING' as an expression for an RTX for where + the called function should find the value. If it should find + the value on the stack, define this to create a `mem' which + refers to the frame pointer. If the value is a `mem', the + compiler assumes it is for an invisible first argument, and + leaves space for it when finding the first real argument. + +`REG_ALLOC_ORDER' + If defined, an initializer for a vector of integers, containing + the numbers of hard registers in the order in which the GNU CC + should prefer to use them (from most preferred to least). + + If this macro is not defined, registers are used lowest numbered + first (all else being equal). + + One use of this macro is on the 360, where the highest numbered + registers must always be saved and the save-multiple-registers + instruction supports only sequences of consecutive registers. + This macro is defined to cause the highest numbered allocatable + registers to be used first. + + +File: gcc.info, Node: Register Classes, Next: Stack Layout, Prev: Registers, Up: Machine Macros + +Register Classes +================ + + On many machines, the numbered registers are not all equivalent. +For example, certain registers may not be allowed for indexed +addressing; certain registers may not be allowed in some +instructions. These machine restrictions are described to the +compiler using "register classes". + + You define a number of register classes, giving each one a name +and saying which of the registers belong to it. Then you can specify +register classes that are allowed as operands to particular +instruction patterns. + + In general, each register will belong to several classes. In +fact, one class must be named `ALL_REGS' and contain all the +registers. Another class must be named `NO_REGS' and contain no +registers. Often the union of two classes will be another class; +however, this is not required. + + One of the classes must be named `GENERAL_REGS'. There is nothing +terribly special about the name, but the operand constraint letters +`r' and `g' specify this class. If `GENERAL_REGS' is the same as +`ALL_REGS', just define it as a macro which expands to `ALL_REGS'. + + The way classes other than `GENERAL_REGS' are specified in operand +constraints is through machine-dependent operand constraint letters. +You can define such letters to correspond to various classes, then +use them in operand constraints. + + You should define a class for the union of two classes whenever +some instruction allows both classes. For example, if an instruction +allows either a floating-point (coprocessor) register or a general +register for a certain operand, you should define a class +`FLOAT_OR_GENERAL_REGS' which includes both of them. Otherwise you +will get suboptimal code. + + You must also specify certain redundant information about the +register classes: for each class, which classes contain it and which +ones are contained in it; for each pair of classes, the largest class +contained in their union. + + When a value occupying several consecutive registers is expected +in a certain class, all the registers used must belong to that class. +Therefore, register classes cannot be used to enforce a requirement +for a register pair to start with an even-numbered register. The way +to specify this requirement is with `HARD_REGNO_MODE_OK'. + + Register classes used for input-operands of bitwise-and or shift +instructions have a special requirement: each such class must have, +for each fixed-point machine mode, a subclass whose registers can +transfer that mode to or from memory. For example, on some machines, +the operations for single-byte values (`QImode') are limited to +certain registers. When this is so, each register class that is used +in a bitwise-and or shift instruction must have a subclass consisting +of registers from which single-byte values can be loaded or stored. +This is so that `PREFERRED_RELOAD_CLASS' can always have a possible +value to return. + +`enum reg_class' + An enumeral type that must be defined with all the register + class names as enumeral values. `NO_REGS' must be first. + `ALL_REGS' must be the last register class, followed by one more + enumeral value, `LIM_REG_CLASSES', which is not a register class + but rather tells how many classes there are. + + Each register class has a number, which is the value of casting + the class name to type `int'. The number serves as an index in + many of the tables described below. + +`N_REG_CLASSES' + The number of distinct register classes, defined as follows: + + #define N_REG_CLASSES (int) LIM_REG_CLASSES + +`REG_CLASS_NAMES' + An initializer containing the names of the register classes as C + string constants. These names are used in writing some of the + debugging dumps. + +`REG_CLASS_CONTENTS' + An initializer containing the contents of the register classes, + as integers which are bit masks. The Nth integer specifies the + contents of class N. The way the integer MASK is interpreted is + that register R is in the class if `MASK & (1 << R)' is 1. + + When the machine has more than 32 registers, an integer does not + suffice. 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 + `HARD_REG_SET' which is defined in `hard-reg-set.h'. + +`REGNO_REG_CLASS (REGNO)' + A C expression whose value is a register class containing hard + register REGNO. In general there is more that one such class; + choose a class which is "minimal", meaning that no smaller class + also contains the register. + +`BASE_REG_CLASS' + A macro whose definition is the name of the class to which a + valid base register must belong. A base register is one used in + an address which is the register value plus a displacement. + +`INDEX_REG_CLASS' + A macro whose definition is the name of the class to which a + valid index register must belong. An index register is one used + in an address where its value is either multiplied by a scale + factor or added to another register (as well as added to a + displacement). + +`REG_CLASS_FROM_LETTER (CHAR)' + A C expression which defines the machine-dependent operand + constraint letters for register classes. If CHAR is such a + letter, the value should be the register class corresponding to + it. Otherwise, the value should be `NO_REGS'. + +`REGNO_OK_FOR_BASE_P (NUM)' + A C expression which is nonzero if register number NUM is + 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. + +`REGNO_OK_FOR_INDEX_P (NUM)' + A C expression which is nonzero if register number NUM is + suitable for use as an index register in operand addresses. It + may be either a suitable hard register or a pseudo register that + has been allocated such a hard register. + + The difference between an index register and a base register is + that the index register may be scaled. If an address involves + the sum of two registers, neither one of them scaled, then + either one may be labeled the "base" and the other the "index"; + but whichever labeling is used must fit the machine's + constraints of which registers may serve in each capacity. The + compiler will try both labelings, looking for one that is valid, + and will reload one or both registers only if neither labeling + works. + +`PREFERRED_RELOAD_CLASS (X, CLASS)' + A C expression that places additional restrictions on the + register class to use when it is necessary to copy value X into + a register in class CLASS. The value is a register class; + perhaps CLASS, or perhaps another, smaller class. On many + machines, the definition + + #define PREFERRED_RELOAD_CLASS(X,CLASS) CLASS + + is safe. + + Sometimes returning a more restrictive class makes better code. + For example, on the 68000, when X is an integer constant that is + in range for a `moveq' instruction, the value of this macro is + always `DATA_REGS' as long as CLASS includes the data registers. + Requiring a data register guarantees that a `moveq' will be used. + + If X is a `const_double', by returning `NO_REGS' you can force X + into a memory constant. This is useful on certain machines + where immediate floating values cannot be loaded into certain + kinds of registers. + + In a shift instruction or a bitwise-and instruction, the mode of + X, the value being reloaded, may not be the same as the mode of + the instruction's operand. (They will both be fixed-point + modes, however.) In such a case, CLASS may not be a safe value + to return. CLASS is certainly valid for the instruction, but it + may not be valid for reloading X. This problem can occur on + machines such as the 68000 and 80386 where some registers can + handle full-word values but cannot handle single-byte values. + + On such machines, this macro must examine the mode of X and + return a subclass of CLASS which can handle loads and stores of + that mode. On the 68000, where address registers cannot handle + `QImode', if X has `QImode' then you must return `DATA_REGS'. + If CLASS is `ADDR_REGS', then there is no correct value to + return; but the shift and bitwise-and instructions don't use + `ADDR_REGS', so this fatal case never arises. + +`CLASS_MAX_NREGS (CLASS, MODE)' + A C expression for the maximum number of consecutive registers + of class CLASS needed to hold a value of mode MODE. + + This is closely related to the macro `HARD_REGNO_NREGS'. In + fact, the value of the macro `CLASS_MAX_NREGS (CLASS, MODE)' + should be the maximum value of `HARD_REGNO_NREGS (REGNO, MODE)' + for all REGNO values in the class CLASS. + + This macro helps control the handling of multiple-word values in + the reload pass. + + Two other special macros describe which constants fit which +constraint letters. + +`CONST_OK_FOR_LETTER_P (VALUE, C)' + A C expression that defines the machine-dependent operand + constraint letters that specify particular ranges of integer + values. If C is one of those letters, the expression should + check that VALUE, an integer, is in the appropriate range and + return 1 if so, 0 otherwise. If C is not one of those letters, + the value should be 0 regardless of VALUE. + +`CONST_DOUBLE_OK_FOR_LETTER_P (VALUE, C)' + A C expression that defines the machine-dependent operand + constraint letters that specify particular ranges of floating + values. If C is one of those letters, the expression should + check that VALUE, an RTX of code `const_double', is in the + appropriate range and return 1 if so, 0 otherwise. If C is not + one of those letters, the value should be 0 regardless of VALUE. + + +File: gcc.info, Node: Stack Layout, Next: Library Calls, Prev: Register Classes, Up: Machine Macros + +Describing Stack Layout +======================= + +`STACK_GROWS_DOWNWARD' + Define this macro if pushing a word onto the stack moves the + stack pointer to a smaller address. + + When we say, "define this macro if ...," it means that the + compiler checks this macro only with `#ifdef' so the precise + definition used does not matter. + +`FRAME_GROWS_DOWNWARD' + Define this macro if the addresses of local variable slots are + at negative offsets from the frame pointer. + +`STARTING_FRAME_OFFSET' + Offset from the frame pointer to the first local variable slot + to be allocated. + + If `FRAME_GROWS_DOWNWARD', the next slot's offset is found by + subtracting the length of the first slot from + `STARTING_FRAME_OFFSET'. Otherwise, it is found by adding the + length of the first slot to the value `STARTING_FRAME_OFFSET'. + +`PUSH_ROUNDING (NPUSHED)' + A C expression that is the number of bytes actually pushed onto + the stack when an instruction attempts to push NPUSHED bytes. + + If the target machine does not have a push instruction, do not + define this macro. That directs GNU CC to use an alternate + strategy: to allocate the entire argument block and then store + the arguments into it. + + On some machines, the definition + + #define PUSH_ROUNDING(BYTES) (BYTES) + + will suffice. But on other machines, instructions that appear + to push one byte actually push two bytes in an attempt to + maintain alignment. Then the definition should be + + #define PUSH_ROUNDING(BYTES) (((BYTES) + 1) & ~1) + +`FIRST_PARM_OFFSET (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. (In the next version of GNU CC, the + argument will be changed to the function data type rather than + its declaration.) + +`FIRST_PARM_CALLER_OFFSET (FUNDECL)' + Define this macro on machines where register parameters have + shadow locations on the stack, at addresses below the nominal + parameter. This matters because certain arguments cannot be + passed on the stack. On these machines, such arguments must be + stored into the shadow locations. + + This macro should expand into a C expression whose value is the + offset of the first parameter's shadow location from the nominal + stack pointer value. (That value is itself computed by adding + the value of `STACK_POINTER_OFFSET' to the stack pointer + register.) + +`REG_PARM_STACK_SPACE' + Define this macro if functions should assume that stack space + has been allocated for arguments even when their values are + passed in registers. + + The actual allocation of such space would be done either by the + call instruction or by the function prologue, or by defining + `FIRST_PARM_CALLER_OFFSET'. + +`STACK_ARGS_ADJUST (SIZE)' + Define this macro if the machine requires padding on the stack + for certain function calls. This is padding on a + per-function-call basis, not padding for individual arguments. + + The argument SIZE will be a C variable of type `struct arg_data' + which contains two fields, an integer named `constant' and an + RTX named `var'. These together represent a size measured in + bytes which is the sum of the integer and the RTX. Most of the + time `var' is 0, which means that the size is simply the integer. + + The definition should be a C statement or compound statement + which alters the variable supplied in whatever way you wish. + + Note that the value you leave in the variable `size' will + ultimately be rounded up to a multiple of `STACK_BOUNDARY' bits. + + This macro is not fully implemented for machines which have push + instructions (i.e., on which `PUSH_ROUNDING' is defined). + +`RETURN_POPS_ARGS (FUNTYPE)' + A C expression that should be 1 if a function pops its own + arguments on returning, or 0 if the function pops no arguments + and the caller must therefore pop them all after the function + returns. + + FUNTYPE is a C variable whose value is a tree node that + describes the function in question. Normally it is a node of + type `FUNCTION_TYPE' that describes the data type of the function. + 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, FUNTYPE + 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 a function used to perform arithmetic, whose name + is known specially in the compiler and was not mentioned in the + C code being compiled. + + On the Vax, all functions always pop their arguments, so the + definition of this macro is 1. On the 68000, using the standard + calling convention, no functions pop their arguments, so the + value of the macro is always 0 in this case. But an alternative + calling convention is available in which functions that take a + fixed number of arguments pop them but other functions (such as + `printf') pop nothing (the caller pops all). When this + convention is in use, FUNTYPE is examined to determine whether a + function takes a fixed number of arguments. + + When this macro returns nonzero, the macro + `FRAME_POINTER_REQUIRED' must also return nonzero for proper + operation. + +`FUNCTION_VALUE (VALTYPE, FUNC)' + A C expression to create an RTX representing the place where a + function returns a value of data type VALTYPE. VALTYPE is a + tree node representing a data type. Write `TYPE_MODE (VALTYPE)' + to get the machine mode used to represent that type. On many + machines, only the mode is relevant. (Actually, on most + machines, scalar values are returned in the same place + regardless of mode). + + If the precise function being called is known, FUNC is a tree + node (`FUNCTION_DECL') for it; otherwise, FUNC is a null + pointer. This makes it possible to use a different + value-returning convention for specific functions when all their + calls are known. + +`FUNCTION_OUTGOING_VALUE (VALTYPE, FUNC)' + Define this macro if the target machine has "register windows" + so that the register in which a function returns its value is + not the same as the one in which the caller sees the value. + + For such machines, `FUNCTION_VALUE' computes the register in + which the caller will see the value, and + `FUNCTION_OUTGOING_VALUE' should be defined in a similar fashion + to tell the function where to put the value. + + If `FUNCTION_OUTGOING_VALUE' is not defined, `FUNCTION_VALUE' + serves both purposes. + +`RETURN_IN_MEMORY (TYPE)' + A C expression which can inhibit the returning of certain + function values in registers, based on the type of value. A + nonzero value says to return the function value in memory, just + as large structures are always returned. Here TYPE will be a C + expression of type `tree', representing the data type of the + value. + + Note that values of mode `BLKmode' are returned in memory + regardless of this macro. Also, the option + `-fpcc-struct-return' takes effect regardless of this macro. On + most systems, it is possible to leave the macro undefined; this + causes a default definition to be used, whose value is the + constant 0. + +`LIBCALL_VALUE (MODE)' + A C expression to create an RTX representing the place where a + library function returns a value of mode MODE. If the precise + function being called is known, FUNC is a tree node + (`FUNCTION_DECL') for it; otherwise, FUNC is a null pointer. + This makes it possible to use a different value-returning + convention for specific functions when all their calls are known. + + Note that "library function" in this context means a compiler + support routine, used to perform arithmetic, whose name is known + specially by the compiler and was not mentioned in the C code + being compiled. + +`FUNCTION_VALUE_REGNO_P (REGNO)' + A C expression that is nonzero if REGNO is the number of a hard + register in which the values of called function may come back. + + A register whose use for returning values is limited to serving + as the second of a pair (for a value of type `double', say) need + not be recognized by this macro. So for most machines, this + definition suffices: + + #define FUNCTION_VALUE_REGNO_P(N) ((N) == 0) + + If the machine has register windows, so that the caller and the + called function use different registers for the return value, + this macro should recognize only the caller's register numbers. + +`FUNCTION_ARG (CUM, MODE, TYPE, NAMED)' + A C expression that controls whether a function argument is + passed in a register, and which register. + + The arguments are CUM, which summarizes all the previous + arguments; MODE, the machine mode of the argument; TYPE, the + data type of the argument as a tree node or 0 if that is not + known (which happens for C support library functions); and + NAMED, which is 1 for an ordinary argument and 0 for nameless + arguments that correspond to `...' in the called function's + prototype. + + The value of the expression should either be a `reg' RTX for the + hard register in which to pass the argument, or zero to pass the + argument on the stack. + + For the Vax and 68000, where normally all arguments are pushed, + zero suffices as a definition. + + The usual way to make the ANSI library `stdarg.h' work on a + machine where some arguments are usually passed in registers, is + to cause nameless arguments to be passed on the stack instead. + This is done by making `FUNCTION_ARG' return 0 whenever NAMED is + 0. + +`FUNCTION_INCOMING_ARG (CUM, MODE, TYPE, NAMED)' + Define this macro if the target machine has "register windows", + so that the register in which a function sees an arguments is + not necessarily the same as the one in which the caller passed + the argument. + + For such machines, `FUNCTION_ARG' computes the register in which + the caller passes the value, and `FUNCTION_INCOMING_ARG' should + be defined in a similar fashion to tell the function being + called where the arguments will arrive. + + If `FUNCTION_INCOMING_ARG' is not defined, `FUNCTION_ARG' serves + both purposes. + +`FUNCTION_ARG_PARTIAL_NREGS (CUM, MODE, TYPE, NAMED)' + A C expression for the number of words, at the beginning of an + argument, must be put in registers. The value must be zero for + arguments that are passed entirely in registers or that are + entirely pushed on the stack. + + On some machines, certain arguments must be passed partially in + registers and partially in memory. On these machines, typically + the first N words of arguments are passed in registers, and the + rest on the stack. If a multi-word argument (a `double' or a + structure) crosses that boundary, its first few words must be + passed in registers and the rest must be pushed. This macro + tells the compiler when this occurs, and how many of the words + should go in registers. + + `FUNCTION_ARG' for these arguments should return the first + register to be used by the caller for this argument; likewise + `FUNCTION_INCOMING_ARG', for the called function. + +`CUMULATIVE_ARGS' + A C type for declaring a variable that is used as the first + argument of `FUNCTION_ARG' and other related values. For some + target machines, the type `int' suffices and can hold the number + of bytes of argument so far. + +`INIT_CUMULATIVE_ARGS (CUM, FNTYPE)' + A C statement (sans semicolon) for initializing the variable CUM + for the state at the beginning of the argument list. The + variable has type `CUMULATIVE_ARGS'. The value of 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. + +`FUNCTION_ARG_ADVANCE (CUM, MODE, TYPE, NAMED)' + A C statement (sans semicolon) to update the summarizer variable + CUM to advance past an argument in the argument list. The + values MODE, TYPE and NAMED describe that argument. Once this + is done, the variable CUM is suitable for analyzing the + *following* argument with `FUNCTION_ARG', etc. + +`FUNCTION_ARG_REGNO_P (REGNO)' + A C expression that is nonzero if REGNO is the number of a hard + register in which function arguments are sometimes passed. This + does *not* include implicit arguments such as the static chain + and the structure-value address. On many machines, no registers + can be used for this purpose since all function arguments are + pushed on the stack. + +`FUNCTION_ARG_PADDING (MODE, SIZE)' + 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. + + The argument SIZE is an RTX which describes the size of the + argument, in bytes. It should be used only if MODE is + `BLKmode'. Otherwise, SIZE is 0. + + This macro does not control the *amount* of padding; that is + always just enough to reach the next multiple of `PARM_BOUNDARY'. + + This macro has a default definition which is right for most + systems. For little-endian machines, the default is to pad + upward. For big-endian machines, the default is to pad downward + for an argument of constant size shorter than an `int', and + upward otherwise. + +`FUNCTION_PROLOGUE (FILE, SIZE)' + A C compound statement that outputs the assembler code for entry + to a function. The prologue is responsible for setting up the + stack frame, initializing the frame pointer register, saving + registers that must be saved, and allocating SIZE additional + bytes of storage for the local variables. SIZE is an integer. + FILE is a stdio stream to which the assembler code should be + output. + + The label for the beginning of the function need not be output + by this macro. That has already been done when the macro is run. + + To determine which registers to save, the macro can refer to the + array `regs_ever_live': element R is nonzero if hard register R + is used anywhere within the function. This implies the function + prologue should save register R, but not if it is one of the + call-used registers. + + On machines where functions may or may not have frame-pointers, + the function entry code must vary accordingly; it must set up + the frame pointer if one is wanted, and not otherwise. To + determine whether a frame pointer is in wanted, the macro can + refer to the variable `frame_pointer_needed'. The variable's + value will be 1 at run time in a function that needs a frame + pointer. + + On machines where an argument may be passed partly in registers + and partly in memory, this macro must examine the variable + `current_function_pretend_args_size', and allocate that many + bytes of uninitialized space on the stack just underneath the + first argument arriving on the stack. (This may not be at the + very end of the stack, if the calling sequence has pushed + anything else since pushing the stack arguments. But usually, + on such machines, nothing else has been pushed yet, because the + function prologue itself does all the pushing.) + +`FUNCTION_PROFILER (FILE, LABELNO)' + 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. + +`FUNCTION_BLOCK_PROFILER (FILE, LABELNO)' + 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: + + 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 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. + +`BLOCK_PROFILER (FILE, BLOCKNO)' + 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: + + 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. + +`EXIT_IGNORE_STACK' + Define this macro as a C expression that is nonzero if the + return instruction or the function epilogue ignores the value of + the stack pointer; in other words, if it is safe to delete an + instruction to adjust the stack pointer before a return from the + function. + + Note that this macro's value is relevant only for functions for + which 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 + `EXIT_IGNORE_STACK'. + +`FUNCTION_EPILOGUE (FILE, SIZE)' + A C compound statement that outputs the assembler code for exit + from a function. The epilogue is responsible for restoring the + saved registers and stack pointer to their values when the + function was called, and returning control to the caller. This + macro takes the same arguments as the macro `FUNCTION_PROLOGUE', + and the registers to restore are determined from + `regs_ever_live' and `CALL_USED_REGISTERS' in the same way. + + On some machines, there is a single instruction that does all + the work of returning from the function. On these machines, + give that instruction the name `return' and do not define the + macro `FUNCTION_EPILOGUE' at all. + + Do not define a pattern named `return' if you want the + `FUNCTION_EPILOGUE' to be used. If you want the target switches + to control whether return instructions or epilogues are used, + define a `return' pattern with a validity condition that tests + the target switches appropriately. If the `return' pattern's + validity condition is false, epilogues will be used. + + On machines where functions may or may not have frame-pointers, + the function exit code must vary accordingly. Sometimes the + code for these two cases is completely different. To determine + whether a frame pointer is in wanted, the macro can refer to the + variable `frame_pointer_needed'. The variable's value will be 1 + at run time in a function that needs a frame pointer. + + On some machines, some functions pop their arguments on exit + while others leave that for the caller to do. For example, the + 68020 when given `-mrtd' pops arguments in functions that take a + fixed number of arguments. + + Your definition of the macro `RETURN_POPS_ARGS' decides which + functions pop their own arguments. `FUNCTION_EPILOGUE' needs to + know what was decided. The variable + `current_function_pops_args' is nonzero if the function should + pop its own arguments. If so, use the variable + `current_function_args_size' as the number of bytes to pop. + +`FIX_FRAME_POINTER_ADDRESS (ADDR, DEPTH)' + A C compound statement to alter a memory address that uses the + frame pointer register so that it uses the stack pointer + register instead. This must be done in the instructions that + load parameter values into registers, when the reload pass + determines that a frame pointer is not necessary for the + function. ADDR will be a C variable name, and the updated + address should be stored in that variable. DEPTH will be the + current depth of stack temporaries (number of bytes of arguments + currently pushed). The change in offset between a + frame-pointer-relative address and a stack-pointer-relative + address must include DEPTH. + + Even if your machine description specifies there will always be + a frame pointer in the frame pointer register, you must still + define `FIX_FRAME_POINTER_ADDRESS', but the definition will + never be executed at run time, so it may be empty. + +`LONGJMP_RESTORE_FROM_STACK' + Define this macro if the `longjmp' function restores registers + from the stack frames, rather than from those saved specifically + by `setjmp'. Certain quantities must not be kept in registers + across a call to `setjmp' on such machines. + + +File: gcc.info, Node: Library Calls, Next: Addressing Modes, Prev: Stack Layout, Up: Machine Macros + +Implicit Use of Library Routines +================================ + +`MULSI3_LIBCALL' + A C string constant giving the name of the function to call for + multiplication of one signed full-word by another. If you do + not define this macro, the default name is used, which is + `__mulsi3', a function defined in `gnulib'. + +`UMULSI3_LIBCALL' + A C string constant giving the name of the function to call for + multiplication of one unsigned full-word by another. If you do + not define this macro, the default name is used, which is + `__umulsi3', a function defined in `gnulib'. + +`DIVSI3_LIBCALL' + A C string constant giving the name of the function to call for + division of one signed full-word by another. If you do not + define this macro, the default name is used, which is + `__divsi3', a function defined in `gnulib'. + +`UDIVSI3_LIBCALL' + A C string constant giving the name of the function to call for + division of one unsigned full-word by another. If you do not + define this macro, the default name is used, which is + `__udivsi3', a function defined in `gnulib'. + +`MODSI3_LIBCALL' + A C string constant giving the name of the function to call for + the remainder in division of one signed full-word by another. + If you do not define this macro, the default name is used, which + is `__modsi3', a function defined in `gnulib'. + +`UMODSI3_LIBCALL' + A C string constant giving the name of the function to call for + the remainder in division of one unsigned full-word by another. + If you do not define this macro, the default name is used, which + is `__umodsi3', a function defined in `gnulib'. + +`TARGET_MEM_FUNCTIONS' + Define this macro if GNU CC should generate calls to the System + V (and ANSI C) library functions `memcpy' and `memset' rather + than the BSD functions `bcopy' and `bzero'. + +`GNULIB_NEEDS_DOUBLE' + Define this macro if only `float' arguments cannot be passed to + library routines (so they must be converted to `double'). This + macro affects both how library calls are generated and how the + library routines in `gnulib.c' accept their arguments. It is + useful on machines where floating and fixed point arguments are + passed differently, such as the i860. + + \ No newline at end of file diff --git a/gcc-1.40/gcc.texinfo b/gcc-1.40/gcc.texinfo new file mode 100644 index 0000000..2e3792e --- /dev/null +++ b/gcc-1.40/gcc.texinfo @@ -0,0 +1,10363 @@ +\input texinfo @c -*-texinfo-*- + +@settitle Using and Porting GNU CC +@setfilename gcc.info + +@ifinfo +This file documents the use and the internals of the GNU compiler. + +Copyright (C) 1988, 1989, 1990 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'' 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'' 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 + +@setchapternewpage odd + +@titlepage +@center @titlefont{Using and Porting GNU CC} +@sp 2 +@center Richard M. Stallman +@sp 3 +@center last updated 3 June 1991 +@sp 1 +@center for version 1.40 +@page +@vskip 0pt plus 1filll +Copyright @copyright{} 1988, 1989, 1990, 1991 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. + +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'' 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'' 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 +@node Top, Copying,, (DIR) +@ichapter Introduction + +This manual documents how to run, install and port the GNU C compiler, as +well as its new features and incompatibilities, and how to report bugs. + +@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. +* Boycott:: Protect your freedom---fight ``look and feel''. +* Options:: Command options supported by @samp{gcc}. +* Installation:: How to configure, compile and install GNU CC. +* Trouble:: If you have trouble installing GNU CC. +* Service:: How to find suppliers of services for GNU CC users. +* Incompatibilities:: Incompatibilities of GNU CC. +* Extensions:: GNU extensions to the C language. +* Bugs:: How to report bugs (if you want to get them fixed). +* Portability:: Goals of GNU CC's portability features. +* Interface:: Function-call interface of GNU CC output. +* Passes:: Order of passes, what they do, and what each file is for. +* RTL:: The intermediate representation that most passes work on. +* Machine Desc:: How to write machine description instruction patterns. +* Machine Macros:: How to write the machine description C macros. +* Config:: Writing the @file{xm-@var{machine}.h} file. +@end menu + +@node Copying, Contributors, Top, Top +@unnumbered GNU GENERAL PUBLIC LICENSE +@center Version 1, February 1989 + +@display +Copyright @copyright{} 1989 Free Software Foundation, Inc. +675 Mass Ave, Cambridge, MA 02139, 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 license agreements of most software companies try to keep users +at the mercy of those companies. By contrast, our 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. The +General Public License applies to the Free Software Foundation's +software and to any other program whose authors commit to using it. +You can use it for your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Specifically, the General Public License is designed to make +sure that you have the freedom to give away or sell copies of free +software, 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 a 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 tell them 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. + + The precise terms and conditions for copying, distribution and +modification follow. + +@iftex +@unnumberedsec TERMS AND CONDITIONS +@end iftex +@ifinfo +@center TERMS AND CONDITIONS +@end ifinfo + +@enumerate +@item +This License Agreement 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 work containing the +Program or a portion of it, either verbatim or with modifications. Each +licensee is addressed as ``you''. + +@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 +General Public License and to the absence of any warranty; and give any +other recipients of the Program a copy of this General Public License +along with the Program. You may charge a fee for the physical act of +transferring a copy. + +@item +You may modify your copy or copies of the Program or any portion of +it, and copy and distribute such modifications under the terms of Paragraph +1 above, provided that you also do the following: + +@itemize @bullet +@item +cause the modified files to carry prominent notices stating that +you changed the files and the date of any change; and + +@item +cause the whole of any work that you distribute or publish, that +in whole or in part contains the Program or any part thereof, either +with or without modifications, to be licensed at no charge to all +third parties under the terms of this General Public License (except +that you may choose to grant warranty protection to some or all +third parties, at your option). + +@item +If the modified program normally reads commands interactively when +run, you must cause it, when started running for such interactive use +in the simplest and most usual 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 General +Public License. + +@item +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. +@end itemize + +Mere aggregation of another independent work with the Program (or its +derivative) on a volume of a storage or distribution medium does not bring +the other work under the scope of these terms. + +@item +You may copy and distribute the Program (or a portion or derivative of +it, under Paragraph 2) in object code or executable form under the terms of +Paragraphs 1 and 2 above provided that you also do one of the following: + +@itemize @bullet +@item +accompany it with the complete corresponding machine-readable +source code, which must be distributed under the terms of +Paragraphs 1 and 2 above; or, + +@item +accompany it with a written offer, valid for at least three +years, to give any third party free (except for a nominal charge +for the cost of distribution) a complete machine-readable copy of the +corresponding source code, to be distributed under the terms of +Paragraphs 1 and 2 above; or, + +@item +accompany it with the information you received as to where the +corresponding source code may be obtained. (This alternative is +allowed only for noncommercial distribution and only if you +received the program in object code or executable form alone.) +@end itemize + +Source code for a work means the preferred form of the work for making +modifications to it. For an executable file, complete source code means +all the source code for all modules it contains; but, as a special +exception, it need not include source code for modules which are standard +libraries that accompany the operating system on which the executable +file runs, or for standard header files or definitions files that +accompany that operating system. + +@item +You may not copy, modify, sublicense, distribute or transfer the +Program except as expressly provided under this General Public License. +Any attempt otherwise to copy, modify, sublicense, distribute or transfer +the Program is void, and will automatically terminate your rights to use +the Program under this License. However, parties who have received +copies, or rights to use copies, from you under this General Public +License will not have their licenses terminated so long as such parties +remain in full compliance. + +@item +By copying, distributing or modifying 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. + +@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. + +@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 the 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 +the 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 Appendix: 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 humanity, 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 1, 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. +@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 `show w' and `show c' should show the +appropriate parts of the General Public License. Of course, the +commands you use may be called something other than `show w' and `show +c'; they could even be mouse-clicks or menu items---whatever suits your +program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a ``copyright disclaimer'' for the program, if +necessary. Here a sample; alter the names: + +@example +Yoyodyne, Inc., hereby disclaims all copyright interest in the +program `Gnomovision' (a program to direct compilers to make passes +at assemblers) written by James Hacker. + +@var{signature of Ty Coon}, 1 April 1989 +Ty Coon, President of Vice +@end example + +That's all there is to it! + +@node Contributors, Boycott, Copying, Top +@unnumbered Contributors to GNU CC + +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 +U. of Arizona Portable Optimizer, written 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 MCC wrote most of the description of the National +Semiconductor 32000 series cpu. He also wrote the code for inline +function integration and for the SPARC cpu and Motorola 88000 cpu +and part of the Sun FPA support. + +@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 the Vomit-Making System. + +@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 +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. +@end itemize + +@node Boycott, Options, Contributors, Top +@chapter Protect Your Freedom---Fight ``Look And Feel'' + +@quotation +@i{This section is a political message from the League for Programming +Freedom to the users of GNU CC. It is included here as an expression +of support for the League on the part of the Free Software Foundation +and Richard Stallman.} +@end quotation + +Ashton-Tate, Apple, Lotus and Xerox are trying to create a new form of +legal monopoly: a copyright on a class of user interfaces. These +monopolies would cause serious problems for users and developers of +computer software and systems. + +Until a few years ago, the law seemed clear: no one could restrict +others from using a user interface; programmers were free to implement +any interface they chose. Imitating interfaces, sometimes with changes, +was standard practice in the computer field. The interfaces we know +evolved gradually in this way; for example, the Macintosh user interface +drew ideas from the Xerox interface, which in turn drew on work done at +Stanford and SRI. 1-2-3 imitated VisiCalc, and dBase imitated a +database program from JPL. + +Most computer companies, and nearly all computer users, were happy with +this state of affairs. The companies that are suing say it does not +offer ``enough incentive'' to develop their products, but they must have +considered it ``enough'' when they made their decision to do so. It +seems they are not satisfied with the opportunity to continue to compete +in the marketplace---not even with a head start. + +If Xerox, Lotus, Apple and Ashton-Tate are permitted to make law through +the courts, the precedent will hobble the software industry: + +@itemize @bullet +@item +Gratuitous incompatibilities will burden users. Imagine if each +car manufacturer had to arrange the pedals in a different order. + +@item +Software will become and remain more expensive. Users will be +``locked in'' to proprietary interfaces, for which there is no real +competition. + +@item +Large companies have an unfair advantage wherever lawsuits become +commonplace. Since they can easily afford to sue, they can intimidate +small companies with threats even when they don't really have a case. + +@item +User interface improvements will come slower, since incremental +evolution through creative imitation will no longer be permitted. + +@item +Even Apple, etc., will find it harder to make improvements if +they can no longer adapt the good ideas that others introduce, for +fear of weakening their own legal positions. Some users suggest that +this stagnation may already have started. + +@item +If you use GNU software, you might find it of some concern that user +interface copyright will make it hard for the Free Software Foundation +to develop programs compatible with the interfaces that you already +know. +@end itemize + +To protect our freedom from lawsuits like these, a group of programmers +and users have formed a new grass-roots political organization, the +League for Programming Freedom. + +The purpose of the League is to oppose new monopolistic practices such +as user-interface copyright and software patents; it calls for a return +to the legal policies of the recent past, in which these practices were +not allowed. The League is not concerned with free software as an +issue, and not affiliated with the Free Software Foundation. + +The League's membership rolls include John McCarthy, inventor of Lisp, +Marvin Minsky, founder of the 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. + +The League needs both activist members and members who only pay their +dues. + +To join, or for more information, phone (617) 492-0023 or write to: + +@example +League for Programming Freedom +1 Kendall Square #143 +P.O. Box 9171 +Cambridge, MA 02139 league@@prep.ai.mit.edu +@end example + +Here are some suggestions from the League for how you can protect your +freedom to write programs: + +@itemize @bullet +@item +Don't buy from Xerox, Lotus, Apple or Ashton-Tate. Buy from their +competitors or from the defendants they are suing. + +@item +Don't develop software to work with the systems made by these companies. + +@item +Port your existing software to competing systems, so that you encourage +users to switch. + +@item +Write letters to company presidents to let them know their conduct +is unacceptable. + +@item +Tell your friends and colleagues about this issue and how it threatens +to ruin the computer industry. + +@item +Above all, don't work for the look-and-feel plaintiffs, and don't +accept contracts from them. + +@item +Write to Congress to explain the importance of this issue. + +@example +House Subcommittee on Intellectual Property +2137 Rayburn Bldg +Washington, DC 20515 + +Senate Subcommittee on Patents, Trademarks and Copyrights +United States Senate +Washington, DC 20510 +@end example +@end itemize + +Express your opinion! You can make a difference. + +@node Options, Installation, Boycott, Top +@chapter GNU CC Command Options + +The GNU C compiler uses a command syntax much like the Unix C compiler. +The @code{gcc} program accepts options and file names as operands. +Multiple single-letter options may @emph{not} be grouped: @samp{-dr} is +very different from @w{@samp{-d -r}}. + +When you invoke GNU CC, it normally does preprocessing, compilation, +assembly and linking. File names which end in @samp{.c} are taken as C +source to be preprocessed and compiled; file names ending in @samp{.i} +are taken as preprocessor output to be compiled; compiler output files +plus any input files with names ending in @samp{.s} are assembled; then +the resulting object files, plus any other input files, are linked +together to produce an executable. + +Command options allow you to stop this process at an intermediate stage. +For example, the @samp{-c} option says not to run the linker. Then the +output consists of object files output by the assembler. + +Other command options are passed on to one stage of processing. Some +options control the preprocessor and others the compiler itself. Yet +other options control the assembler and linker; these are not documented +here, but you rarely need to use any of them. + +Here are the options to control the overall compilation process, including +those that say whether to link, whether to assemble, and so on. + +@table @samp +@item -o @var{file} +Place output in file @var{file}. This applies regardless to whatever +sort of output is being produced, whether it be an executable file, +an object file, an assembler file or preprocessed C code. + +If @samp{-o} is not specified, the default is to put an executable file +in @file{a.out}, the object file @file{@var{source}.c} in +@file{@var{source}.o}, an assembler file in @file{@var{source}.s}, and +preprocessed C on standard output.@refill + +@item -c +Compile or assemble the source files, but do not link. Produce object +files with names made by replacing @samp{.c} or @samp{.s} with +@samp{.o} at the end of the input file names. Do nothing at all for +object files specified as input. + +@item -S +Compile into assembler code but do not assemble. The assembler output +file name is made by replacing @samp{.c} with @samp{.s} at the end of +the input file name. Do nothing at all for assembler source files or +object files specified as input. + +@item -E +Run only the C preprocessor. Preprocess all the C source files +specified and output the results to standard output. + +@item -v +Compiler driver program prints the commands it executes as it runs +the preprocessor, compiler proper, assembler and linker. Some of +these are directed to print their own version numbers. + +@item -pipe +Use pipes rather than temporary files for communication between the +various stages of compilation. This fails to work on some systems +where the assembler is unable to read from a pipe; but the GNU +assembler has no trouble. + +@item -B@var{prefix} +Compiler driver program tries @var{prefix} as a prefix for each +program it tries to run. These programs are @file{cpp}, @file{cc1}, +@file{as} and @file{ld}. + +For each subprogram to be run, the compiler driver first tries the +@samp{-B} prefix, if any. If that name is not found, or if @samp{-B} +was not specified, the driver tries two standard prefixes, which are +@file{/usr/lib/gcc-} and @file{/usr/local/lib/gcc-}. If neither of +those results in a file name that is found, the unmodified program +name is searched for using the directories specified in your +@samp{PATH} environment variable. + +The run-time support file @file{gnulib} is also searched for using +the @samp{-B} prefix, if needed. If it is not found there, the two +standard prefixes above are tried, and that is all. The file is left +out of the link if it is not found by those means. Most of the time, +on most machines, you can do without it. + +You can get a similar result from the environment variable; +@code{GCC_EXEC_PREFIX} if it is defined, its value is used as a prefix +in the same way. If both the @samp{-B} option and the +@code{GCC_EXEC_PREFIX} variable are present, the @samp{-B} option is +used first and the environment variable value second. + +@item -b@var{prefix} +The argument @var{prefix} is used as a second prefix for the compiler +executables and libraries. This prefix is optional: the compiler tries +each file first with it, then without it. This prefix follows the +prefix specified with @samp{-B} or the default prefixes. + +Thus, @samp{-bvax- -Bcc/} in the presence of environment variable +@code{GCC_EXEC_PREFIX} with definition @file{/u/foo/} causes GNU CC to +try the following file names for the preprocessor executable: + +@example +cc/vax-cpp +cc/cpp +/u/foo/vax-cpp +/u/foo/cpp +/usr/local/lib/gcc-vax-cpp +/usr/local/lib/gcc-cpp +/usr/lib/gcc-vax-cpp +/usr/lib/gcc-cpp +@end example +@end table + +These options control the details of C compilation itself. + +@table @samp +@item -ansi +Support all ANSI standard C programs. + +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. + +The alternate keywords @code{__asm__}, @code{__inline__} and +@code{__typeof__} continue to work despite @samp{-ansi}. You would not +want to use them in an ANSI C program, of course, but it useful to put +them in header files that might be included in compilations done with +@samp{-ansi}. Alternate predefined macros such as @code{__unix__} and +@code{__vax__} are also available, with or without @samp{-ansi}. + +The @samp{-ansi} option does not cause non-ANSI programs to be +rejected gratuitously. For that, @samp{-pedantic} is required in +addition to @samp{-ansi}. + +The macro @code{__STRICT_ANSI__} is predefined when the @samp{-ansi} +option is used. Some header files may notice this macro and refrain +from declaring certain functions or defining certain macros that the +ANSI standard doesn't call for; this is to avoid interfering with any +programs that might use these names for other things. + +@item -traditional +Attempt to support some aspects of traditional C compilers. +Specifically: + +@itemize @bullet +@item +All @code{extern} declarations take effect globally even if they +are written inside of a function definition. This includes implicit +declarations of functions. + +@item +The keywords @code{typeof}, @code{inline}, @code{signed}, @code{const} +and @code{volatile} are not recognized. (You can still use the alternative +keywords such as @code{__typeof__}, @code{__inline__}, and so on.) + +@item +Comparisons between pointers and integers are always allowed. + +@item +Integer types @code{unsigned short} and @code{unsigned char} promote +to @code{unsigned int}. + +@item +Out-of-range floating point literals are not an error. + +@item +String ``constants'' are not necessarily constant; they are stored in +writable space, and identical looking constants are allocated +separately. + +@item +All automatic variables not declared @code{register} are preserved by +@code{longjmp}. Ordinarily, GNU C follows ANSI C: automatic variables +not declared @code{volatile} may be clobbered. + +@item +In the preprocessor, comments convert to nothing at all, rather than +to a space. This allows traditional token concatenation. + +@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. + +@item +The predefined macro @code{__STDC__} is not defined when you use +@samp{-traditional}, but @code{__GNUC__} is (since the GNU extensions +which @code{__GNUC__} indicates are not affected by +@samp{-traditional}). If you need to write header files that work +differently depending on whether @samp{-traditional} 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. +@end itemize + +@item -O +Optimize. Optimizing compilation takes somewhat more time, and a lot +more memory for a large function. + +Without @samp{-O}, the compiler's goal is to reduce the cost of +compilation and to make debugging produce the expected results. +Statements are independent: if you stop the program with a breakpoint +between statements, you can then assign a new value to any variable or +change the program counter to any other statement in the function and +get exactly the results you would expect from the source code. + +Without @samp{-O}, only variables declared @code{register} are +allocated in registers. The resulting compiled code is a little worse +than produced by PCC without @samp{-O}. + +With @samp{-O}, the compiler tries to reduce code size and execution +time. + +Some of the @samp{-f} options described below turn specific kinds of +optimization on or off. + +@item -g +Produce debugging information in the operating system's native format +(for DBX or SDB). GDB also can work with this debugging information. + +Unlike most other C compilers, GNU CC allows you to use @samp{-g} with +@samp{-O}. 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. + +@item -gg +Produce debugging information in the old GDB format. This is obsolete. + +@item -w +Inhibit all warning messages. + +@item -W +Print extra warning messages for these events: + +@itemize @bullet +@item +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 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 +structures, unions or arrays, even when they are in registers. + +Note that there may be no warning about a variable that is used only +to compute a value that itself is never used, because such +computations may be deleted by data flow analysis before the warnings +are printed. + +These warnings are made optional because GNU CC 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 +@{ + int x; + switch (y) + @{ + case 1: x = 1; + break; + case 2: x = 4; + break; + case 3: x = 5; + @} + foo (x); +@} +@end example + +@noindent +If the value of @code{y} is always 1, 2 or 3, then @code{x} is +always initialized, but GNU CC doesn't know this. Here is +another common case: + +@example +@{ + int save_y; + if (change_y) save_y = y, y = new_y; + @dots{} + if (change_y) y = save_y; +@} +@end example + +@noindent +This has no bug because @code{save_y} is used only if it is set. + +Some spurious warnings can be avoided if you declare as +@code{volatile} all the functions you use that never return. +@xref{Function Attributes}. + +@item +A nonvolatile automatic variable might be changed by a call to +@code{longjmp}. These warnings as well are possible only in +optimizing compilation. + +The compiler sees only the calls to @code{setjmp}. It cannot know +where @code{longjmp} will be called; in fact, a signal handler could +call it at any point in the code. As a result, you may get a warning +even when there is in fact no problem because @code{longjmp} cannot +in fact be called at the place which would cause a problem. + +@item +A function can return either with or without a value. (Falling +off the end of the function body is considered returning without +a value.) For example, this function would evoke such a +warning: + +@example +foo (a) +@{ + if (a > 0) + return a; +@} +@end example + +Spurious warnings can occur because GNU CC does not realize that +certain functions (including @code{abort} and @code{longjmp}) +will never return. + +@item +An expression-statement contains no side effects. +@end itemize + +In the future, other useful warnings may also be enabled by this +option. + +@item -Wimplicit +Warn whenever a function is implicitly declared. + +@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 +return-value in a function whose return-type is not @code{void}. + +@item -Wunused +Warn whenever a local variable is unused aside from its declaration, +whenever a function is declared static but never defined, and whenever +a statement computes a result that is explicitly not used. + +@item -Wswitch +Warn whenever a @code{switch} statement has an index of enumeral type +and lacks a @code{case} for one or more of the named codes of that +enumeration. (The presence of a @code{default} label prevents this +warning.) @code{case} labels outside the enumeration range also +provoke warnings when this option is used. + +@item -Wcomment +Warn whenever a comment-start sequence @samp{/*} appears in a comment. + +@item -Wtrigraphs +Warn if any trigraphs are encountered (assuming they are enabled). + +@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. + +The other @samp{-W@dots{}} options below are not implied by @samp{-Wall} +because certain kinds of useful macros are almost impossible to write +without causing those warnings. + +@item -Wshadow +Warn whenever a local variable shadows another local variable. + +@item -Wid-clash-@var{len} +Warn whenever two distinct identifiers match in the first @var{len} +characters. This may help you prepare a program that will compile +with certain obsolete, brain-damaged compilers. + +@item -Wpointer-arith +Warn about anything that depends on the ``size of'' a function type or +of @code{void}. GNU C assigns these types a size of 1, for +convenience in calculations with @code{void *} pointers and pointers +to functions. + +@item -Wcast-qual +Warn whenever a pointer is cast so as to remove a type qualifier from +the target type. For example, warn if a @code{const char *} is cast +to an ordinary @code{char *}. + +@item -Wwrite-strings +Give string constants the type @code{const char[@var{length}]} so that +copying the address of one into a non-@code{const} @code{char *} +pointer will get a warning. These warnings will help you find at +compile time code that can try to write into a string constant, but +only if you have been very careful about using @code{const} in +declarations and prototypes. Otherwise, it will just be a nuisance; +this is why we did not make @samp{-Wall} request these warnings. + +@item -p +Generate extra code to write profile information suitable for the +analysis program @code{prof}. + +@item -pg +Generate extra code to write profile information suitable for the +analysis program @code{gprof}. + +@item -a +Generate extra code to write profile information for basic blocks, which +will record the number of times each basic block is executed. 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 -l@var{library} +Search a standard list of directories for a library named +@var{library}, which is actually a file named +@file{lib@var{library}.a}. The linker uses this file as if it +had been specified precisely by name. + +The directories searched include several standard system directories +plus any that you specify with @samp{-L}. + +Normally the files found this way are library files---archive files +whose members are object files. The linker handles an archive file by +scanning through it for members which define symbols that have so far +been referenced but not defined. But if the file that is found is an +ordinary object file, it is linked in the usual fashion. The only +difference between using an @samp{-l} option and specifying a file name +is that @samp{-l} searches several directories. + +@item -L@var{dir} +Add directory @var{dir} to the list of directories to be searched +for @samp{-l}. + +@item -nostdlib +Don't use the standard system libraries and startup files when linking. +Only the files you specify will be passed to the linker. + +@item -m@var{machinespec} +Machine-dependent option specifying something about the type of target +machine. These options are defined by the macro +@code{TARGET_SWITCHES} in the machine description. The default for +the options is also defined by that macro, which enables you to change +the defaults.@refill + +These are the @samp{-m} options defined in the 68000 machine +description: + +@table @samp +@item -m68020 +@itemx -mc68020 +Generate output for a 68020 (rather than a 68000). This is the +default if you use the unmodified sources. + +@item -m68000 +@item -mc68000 +Generate output for a 68000 (rather than a 68020). + +@item -m68881 +Generate output containing 68881 instructions for floating point. +This is the default if you use the unmodified sources. + +@item -mfpa +Generate output containing Sun FPA instructions for floating point. + +@item -msoft-float +Generate output containing library calls for floating point. + +@item -mshort +Consider type @code{int} to be 16 bits wide, like @code{short int}. + +@item -mnobitfield +Do not use the bit-field instructions. @samp{-m68000} implies +@samp{-mnobitfield}. + +@item -mbitfield +Do use the bit-field instructions. @samp{-m68020} implies +@samp{-mbitfield}. This is the default if you use the unmodified +sources. + +@item -mrtd +Use a different function-calling convention, in which functions +that take a fixed number of arguments return with the @code{rtd} +instruction, which pops their arguments while returning. This +saves one instruction in the caller since there is no need to pop +the arguments there. + +This calling convention is incompatible with the one normally +used on Unix, so you cannot use it if you need to call libraries +compiled with the Unix compiler. + +Also, you must provide function prototypes for all functions that +take variable numbers of arguments (including @code{printf}); +otherwise incorrect code will be generated for calls to those +functions. + +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. +@end table + +These @samp{-m} options are defined in the Vax machine description: + +@table @samp +@item -munix +Do not output certain jump instructions (@code{aobleq} and so on) +that the Unix assembler for the Vax cannot handle across long +ranges. + +@item -mgnu +Do output those jump instructions, on the assumption that you +will assemble with the GNU assembler. + +@item -mg +Output code for g-format floating point numbers instead of d-format. +@end table + +These @samp{-m} switches are supported on the Sparc: + +@table @samp +@item -mfpu +Generate output containing floating point instructions. This is the +default if you use the unmodified sources. + +@ignore +@item -msoft-float +Generate output containing library calls for floating point. + +@end ignore +@item -mno-epilogue +Generate separate return instructions for @code{return} statements. +This has both advantages and disadvantages; I don't recall what they +are. +@end table + +These @samp{-m} options are defined in the Convex machine description: + +@table @samp +@item -mc1 +Generate output for a C1. This is the default when the compiler is +configured for a C1. + +@item -mc2 +Generate output for a C2. This is the default when the compiler is +configured for a C2. + +@item -margcount +Generate code which puts an argument count in the word preceding each +argument list. Some nonportable Convex and Vax programs need this +word. (Debuggers don't; this info is in the symbol table.) + +@item -mnoargcount +Omit the argument count word. This is the default if you use the +unmodified sources. +@end table + +@item -f@var{flag} +Specify machine-independent flags. Most flags 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 @samp +@item -fpcc-struct-return +Use the same convention for returning @code{struct} and @code{union} +values that is used by the usual C compiler on your system. This +convention is less efficient for small structures, and on many +machines it fails to be reentrant; but it has the advantage of +allowing intercallability between GCC-compiled code and PCC-compiled +code. + +@item -ffloat-store +Do not store floating-point variables in registers. This +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. + +@item -fno-asm +Do not recognize @code{asm}, @code{inline} or @code{typeof} as a +keyword. These words may then be used as identifiers. You can +use @code{__asm__}, @code{__inline__} and @code{__typeof__} instead. + +@item -fno-defer-pop +Always pop the arguments to each function call as soon as that +function returns. Normally the compiler (when optimizing) lets +arguments accumulate on the stack for several function calls and +pops them all at once. + +@item -fstrength-reduce +Perform the optimizations of loop strength reduction and +elimination of iteration variables. + +@item -fcombine-regs +Allow the combine pass to combine an instruction that copies one +register into another. This might or might not produce better +code when used in addition to @samp{-O}. I am interested in +hearing about the difference this makes. + +@item -fforce-mem +Force memory operands to be copied into registers before doing +arithmetic on them. This may produce better code by making all +memory references potential common subexpressions. When they are +not common subexpressions, instruction combination should +eliminate the separate register-load. I am interested in hearing +about the difference this makes. + +@item -fforce-addr +Force memory address constants to be copied into registers before +doing arithmetic on them. This may produce better code just as +@samp{-fforce-mem} may. I am interested in hearing about the +difference this makes. + +@item -fomit-frame-pointer +Don't keep the frame pointer in a register for functions that +don't need one. This avoids the instructions to save, set up and +restore frame pointers; it also makes an extra register available +in many functions. @strong{It also makes debugging impossible.} + +On some machines, such as the Vax, this flag has no effect, +because the standard calling sequence automatically handles the +frame pointer and nothing is saved by pretending it doesn't +exist. The machine-description macro +@code{FRAME_POINTER_REQUIRED} controls whether a target machine +supports this flag. @xref{Registers}.@refill + +@item -finline-functions +Integrate all simple functions into their callers. The compiler +heuristically decides which functions are simple enough to be +worth integrating in this way. + +If all calls to a given function are integrated, and the function +is declared @code{static}, then the function is normally not +output as assembler code in its own right. + +@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 +registers around such calls. Such allocation is done only when it +seems to result in better code than would otherwise be produced. + +This option is enabled by default on certain machines, usually those +which have no call-preserved registers to use instead. + +@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. + +@item -fwritable-strings +Store string constants in the writable data segment and don't uniquize +them. This is for compatibility with old programs which assume they can +write into string constants. @samp{-traditional} also has this effect. + +Writing into string constants is a very bad idea; ``constants'' should +be constant. + +@item -fcond-mismatch +Allow conditional expressions with mismatched types in the second and +third arguments. The value of such an expression is void. + +@item -fno-function-cse +Do not put function addresses in registers; make each instruction +that calls a constant function contain the function's address +explicitly. + +This option results in less efficient code, but some strange +hacks that alter the assembler output may be confused by the +optimizations performed when this option is not used. + +@item -fvolatile +Consider all memory references through pointers to be volatile. + +@item -fshared-data +Requests that the data and non-@code{const} variables of this +compilation be shared data rather than private data. The distinction +makes sense only on certain operating systems, where shared data is +shared between processes running the same program, while private data +exists in one copy per process. + +@item -funsigned-char +Let the type @code{char} be the unsigned, like @code{unsigned char}. + +Each kind of machine has a default for what @code{char} should +be. It is either like @code{unsigned char} by default or like +@code{signed char} by default. (Actually, at present, the +default is always signed.) + +The type @code{char} is always a distinct type from either +@code{signed char} or @code{unsigned char}, even though its +behavior is always just like one of those two. + +Note that this is equivalent to @samp{-fno-signed-char}, which is the +negative form of @samp{-fsigned-char}. + +@item -fsigned-char +Let the type @code{char} be signed, like @code{signed char}. + +Note that this is equivalent to @samp{-fno-unsigned-char}, which is +the negative form of @samp{-funsigned-char}. + +@item -fdelayed-branch +If supported for the target machine, attempt to reorder instructions +to exploit instruction slots available after delayed branch +instructions. + +@item -ffixed-@var{reg} +Treat the register named @var{reg} as a fixed register; generated +code should never refer to it (except perhaps as a stack pointer, +frame pointer or in some other fixed role). + +@var{reg} must be the name of a register. The register names +accepted are machine-specific and are defined in the +@code{REGISTER_NAMES} macro in the machine description macro +file. + +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 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}. + +Use of this flag for a register that has a fixed pervasive role +in the machine's execution model, such as the stack pointer or +frame pointer, will produce disastrous results. + +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 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. + +Use of this flag for a register that has a fixed pervasive role +in the machine's execution model, such as the stack pointer or +frame pointer, will produce disastrous results. + +A different sort of disaster will result from the use of this +flag for a register in which function values may be returned. + +This flag does not have a negative form, because it specifies a +three-way choice. +@end table + +@item -d@var{letters} +Says to make debugging dumps at times specified by @var{letters}. +Here are the possible letters: + +@table @samp +@item r +Dump after RTL generation. +@item j +Dump after first jump optimization. +@item s +Dump after CSE (including the jump optimization that sometimes +follows CSE). +@item L +Dump after loop optimization. +@item f +Dump after flow analysis. +@item c +Dump after instruction combination. +@item l +Dump after local register allocation. +@item g +Dump after global register allocation. +@item d +Dump after delayed branch scheduling. +@item J +Dump after last jump optimization. +@item m +Print statistics on memory usage, at the end of the run. +@end table + +@item -pedantic +Issue all the warnings demanded by strict ANSI standard C; reject +all programs that use forbidden extensions. + +Valid ANSI standard 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. There is +no reason to @i{use} this option; it exists only to satisfy pedants. + +@samp{-pedantic} does not cause warning messages for use of the +alternate keywords whose names begin and end with @samp{__}. +@xref{Alternate Keywords}. + +@item -static +On Suns running version 4, this prevents linking with the shared +libraries. (@samp{-g} has the same effect.) +@end table + +These options control the C preprocessor, which is run on each C source +file before actual compilation. If you use the @samp{-E} option, nothing +is done except C preprocessing. Some of these options make sense only +together with @samp{-E} because they request preprocessor output that is +not suitable for actual compilation. + +@table @samp +@item -C +Tell the preprocessor not to discard comments. Used with the +@samp{-E} option. + +@item -I@var{dir} +Search directory @var{dir} for include files. + +@item -I- +Any directories specified with @samp{-I} options before the @samp{-I-} +option are searched only for the case of @samp{#include "@var{file}"}; +they are not searched for @samp{#include <@var{file}>}. + +If additional directories are specified with @samp{-I} options after +the @samp{-I-}, these directories are searched for all @samp{#include} +directives. (Ordinarily @emph{all} @samp{-I} directories are used +this way.) + +In addition, the @samp{-I-} option inhibits the use of the current +directory (where the current input file came from) as the first search +directory for @samp{#include "@var{file}"}. There is no way to override +this effect of @samp{-I-}. With @samp{-I.} you can specify searching +the directory which was current when the compiler was invoked. That is +not exactly the same as what the preprocessor does by default, but it is +often satisfactory. + +@samp{-I-} does not inhibit the use of the standard system directories +for header files. Thus, @samp{-I-} and @samp{-nostdinc} are +independent. + +@item -i @var{file} +Process @var{file} as input, discarding the resulting output, before +processing the regular input file. Because the output generated from +@var{file} is discarded, the only effect of @samp{-i @var{file}} is to +make the macros defined in @var{file} available for use in the main +input. + +@item -nostdinc +Do not search the standard system directories for header files. Only +the directories you have specified with @samp{-I} options (and the +current directory, if appropriate) are searched. + +Between @samp{-nostdinc} and @samp{-I-}, you can eliminate all +directories from the search path except those you specify. + +@item -M +Tell the preprocessor to output a rule suitable for @code{make} +describing the dependencies of each object file. For each source +file, the preprocessor outputs one @code{make}-rule whose target is +the object file name for that source file and whose dependencies are +all the files @samp{#include}d in it. This rule may be a single line +or may be continued with @samp{\}-newline if it is long. + +@samp{-M} implies @samp{-E}. + +@item -MM +Like @samp{-M} but the output mentions only the user-header files +included with @samp{#include "@var{file}"}. System header files +included with @samp{#include <@var{file}>} are omitted. + +@samp{-MM} implies @samp{-E}. + +@item -D@var{macro} +Define macro @var{macro} with the string @samp{1} as its definition. + +@item -D@var{macro}=@var{defn} +Define macro @var{macro} as @var{defn}. + +@item -U@var{macro} +Undefine macro @var{macro}. + +@item -trigraphs +Support ANSI C trigraphs. You don't want to know about this +brain-damage. The @samp{-ansi} option also has this effect. +@end table + +@node Installation, Trouble, Options, Top +@chapter Installing GNU CC + +Here is the procedure for installing GNU CC on a Unix system. + +@menu +* Other Dir:: Compiling in a separate directory (not where the source is). +* Sun Install:: See below for installation on the Sun. +* 3B1 Install:: See below for installation on the 3B1. +* SCO Install:: See below for installation on SCO System V 3.2. (Or ESIX.) +* VMS Install:: See below for installation on VMS. +* HPUX Install:: See below for installation on HPUX. +* Tower Install:: See below for installation on an NCR Tower. +@end menu +@iftex +See below for VMS systems, and modified procedures needed on Sun +systems, 3b1 machines and HPUX. The following section says how to +compile in a separate directory on Unix; here we assume you compile in +the same directory that contains the source files. +@end iftex + +@enumerate +@item +Edit @file{Makefile}. If you are using HPUX, or any form of system V, +you must make a few changes described in comments at the beginning of +the file. Genix requires changes also, and so does the Pyramid. + +@item +On a Sequent system, go to the Berkeley universe. + +@item +Choose configuration files. The easy way to do this is to run the +command file @file{config.gcc} with a single argument, which specifies +the type of machine (and in some cases which operating system). + +Here is a list of the possible arguments: + +@table @samp +@item vax +Vaxes running BSD. +@item vms +Vaxes running VMS. +@item vax-sysv +Vaxes running system V. +@item i386-sysv +Intel 386 PCs running system V. +@item i386-sysv-gas +Intel 386 PCs running system V, using the GNU assembler and GNU +linker. +@item sequent-i386 +Sequent with Intel 386 processors. +@item i386-aix +Intel 386 PCs or PS/2s running AIX. +@item sun2 +Sun 2 running system version 2 or 3. +@item sun3 +Sun 3 running system version 4, with 68881. +Note there we do not provide a configuration file to use an FPA +by default, because programs that establish signal handlers for +floating point traps inherently cannot work with the FPA. +@item sun3-nfp +Sun 3 running system version 4, without 68881. +@item sun4 +Sun 4 running system version 4. @xref{Incompatibilities}, +for calling convention incompatibilities on the Sun 4 (sparc). +@item sun2-os4 +Sun 2 running system version 4. +@item sun3-os3 +Sun 3 running system version 2 or 3, with 68881. +@item sun3-nfp-os3 +Sun 3 running system version 2 or 3, without 68881. +@item sun4-os3 +Sun 4 running system version 2 or 3. @xref{Incompatibilities}, +for calling convention incompatibilities on the Sun 4 (sparc). +@item sun386 +Sun 386 (``roadrunner''). +@item alliant +Alliant FX/8 computer. Note that the standard installed C compiler in +Concentrix 5.0 has a bug which prevent it from compiling GNU CC +correctly. You can patch the compiler bug as follows: + +@example +cp /bin/pcc ./pcc +adb -w ./pcc - << EOF +15f6?w 6610 +EOF +@end example + +Then you must use the @samp{-ip12} option when compiling GNU CC +with the patched compiler, as shown here: + +@example +make CC="./pcc -ip12" CFLAGS=-w +@end example + +Note also that Alliant's version of DBX does not manage to work with the +output from GNU CC. +@item tahoe +The tahoe computer (running BSD, and using DBX). +@item decstation +The DEC 3100 Mips machine (``pmax''). Note that GNU CC cannot generate +debugging information in the unusual format used on the Mips. +@item mips-sysv +The Mips computer, RS series, with the System V environment as default. +Note that GNU CC cannot generate debugging information in the unusual +format used on the Mips. +@item mips-bsd43 +The Mips computer, RS series, with the BSD 4.3 environment as default. +Note that GNU CC cannot generate debugging information in the unusual +format used on the Mips. +@item mips +The Mips computer, M series. Note that GNU CC cannot generate debugging +information in the unusual format used on the Mips. +@item iris +Another variant of the Mips computer, the Silicon Graphics Iris 4D. +Note that GNU CC cannot generate debugging information in the unusual +format used on the Mips. +@item convex-c1 +Convex C1 computer. With operating system version 9, use @samp{cc -pcc} +as the compilation command when building stage 1 of GNU CC. +@item convex-c2 +Convex C2 computer. With operating system version 9, use @samp{cc -pcc} +as the compilation command when building stage 1 of GNU CC. +@item pyramid +Pyramid computer. +@item hp9k320 +HP 9000 series 300 using HPUX assembler. Note there is no +support in GNU CC for HP's debugger; thus, @samp{-g} is not +available in this configuration. +@item hp9k320-gas +HP 9000 series 300 using GNU assembler, linker and debugger. +This requires the HP-adapt package, which is available along with +the GNU linker as part of the ``binutils'' distribution. +This is on the GNU CC distribution tape. +@item hp9k320-old +HP 9000 series 300 using HPUX assembler, in operating system versions +older than 6.5. Note there is no support in GNU CC for HP's debugger; +thus, @samp{-g} is not available in this configuration. +@item hp9k320-bsd +HP 9000 series 300 running BSD. +@item hp9k200-bsd +HP 9000 series 200 running BSD. Note that the C compiler that comes +with this system cannot compile GNU CC; contact @code{law@@super.org} to +get binaries of GNU CC for bootstrapping. Additionally, a minor patch +is necessary if you wish to build kernels with GNU CC; contact +@code{law@@super.org} to get a copy of the patch. +@item isi68 +ISI 68000 or 68020 system with a 68881. +@item isi68-nfp +ISI 68000 or 68020 system without a 68881. +@item news800 +Sony NEWS 68020 system. +@item next +NeXT system. +@item tower +NCR Tower 32 system. +@item altos +Altos 3068. Note that you must use the GNU assembler, linker and +debugger, with COFF-encapsulation. Also, you must fix a kernel +bug. Details in the file @file{ALTOS-README}. +@item 3b1 +AT&T 3b1, a.k.a. 7300 PC. Note that special procedures are needed +to compile GNU CC with this machine's standard C compiler, due to +bugs in that compiler. @xref{3b1 Install}. You can bootstrap it +more easily with previous versions of GNU CC if you have them. +@item 3b1-gas +AT&T 3b1 using the GNU assembler. +@item sequent-ns32k +Sequent containing ns32000 processors. +@item encore +Encore ns32000 system. +@item genix +National Semiconductor ns32000 system. +@item 88000 +Motorola 88000 processor. This port is not finished. +@end table + +Here we spell out what files need to be set up: + +@itemize @bullet +@item +Make a symbolic link named @file{config.h} to the top-level +config file for the machine you are using (@pxref{Config}). This +file is responsible for defining information about the host +machine. It includes @file{tm.h}. + +The file is located in the subdirectory @file{config}. Its name +should be @file{xm-@var{machine}.h}, with these exceptions: + +@table @file +@item xm-vms.h +for vaxen running VMS. +@item xm-vaxv.h +for vaxen running system V. +@item xm-i386v.h +for Intel 80386's running system V. +@item xm-sun386i.h +for Sun roadrunner running any version of the operating system. +@item xm-hp9k320.h +for the HP 9000 series 300. +@item xm-genix.h +for the ns32000 running Genix +@end table + +If your system does not support symbolic links, you might want to +set up @file{config.h} to contain a @samp{#include} command which +refers to the appropriate file. + +@item +Make a symbolic link named @file{tm.h} to the machine-description +macro file for your machine. It should be in the subdirectory +@file{config} and its name should be @file{tm-@var{machine}.h}. + +If your system is a 68000, don't use the file @file{tm-m68k.h} +directly. Instead, use one of these files: + +@table @file +@item tm-sun3.h +for Sun 3 machines with 68881. +@item tm-sun3-nfp.h +for Sun 3 machines with no hardware floating point. +@item tm-sun3os3.h +for Sun 3 machines with 68881, running Sunos version 3. +@item tm-sun3os3nf.h +for Sun 3 machines with no hardware floating point, running Sunos +version 3. +@item tm-sun2.h +for Sun 2 machines. +@item tm-3b1.h +for AT&T 3b1 (aka 7300 Unix PC). +@item tm-isi68.h +for Integrated Solutions systems. This file assumes you +use the GNU assembler. +@item tm-isi68-nfp.h +for Integrated Solutions systems without a 68881. This file assumes you +use the GNU assembler. +@item tm-news800.h +for Sony NEWS systems. +@item tm-hp9k320.h +for HPUX systems, if you are using GNU CC with the system's +assembler and linker. +@item tm-hp9k320g.h +for HPUX systems, if you are using the GNU assembler, linker and +other utilities. Not all of the pieces of GNU software needed +for this mode of operation are as yet in distribution; full +instructions will appear here in the future.@refill +@item tm-tower-as.h +for NCR Tower 32 systems, using the standard system assembler. +@end table + +For the vax, use @file{tm-vax.h} on BSD Unix, @file{tm-vaxv.h} on +system V, or @file{tm-vms.h} on VMS.@refill + +For the Motorola 88000, use @file{tm-m88k.h}. The support for the +88000 does not currently work; it requires extensive changes which +we hope to reconcile in version 2. + +For the 80386, don't use @file{tm-i386.h} directly. Use +@file{tm-i386v.h} if the target machine is running system V, +@file{tm-i386gas.h} if it is running system V but you are using the +GNU assembler and linker, @file{tm-seq386.h} for a Sequent 386 system, +or @file{tm-compaq.h} for a Compaq, or @file{tm-sun386i.h} for a Sun +386 system. + +For the Mips computer, there are five choices: @file{tm-mips.h} for the +M series, @file{tm-mips-bsd.h} for the RS series with BSD, +@file{tm-mips-sysv.h} for the RS series with System V, @file{tm-iris.h} +for the Iris version of the machine, and @file{tm-decstatn.h} for the +Decstation. + +For the 32000, use @file{tm-sequent.h} if you are using a Sequent +machine, or @file{tm-encore.h} for an Encore machine, or +@file{tm-genix.h} if you are using Genix version 3; otherwise, perhaps +@file{tm-ns32k.h} will work for you. + +Note that Genix has bugs in @code{alloca} and @code{malloc}; you must +get the compiled versions of these from GNU Emacs and edit GNU CC's +@file{Makefile} to use them. + +Note that Encore systems are supported only under BSD. + +For Sparc (Sun 4) machines, use @file{tm-sparc.h} with operating system +version 4, and @file{tm-sun4os3.h} with system version 3. + +For Convex systems before version 8.1, use @file{tm-conv1os7.h} or +@file{tm-conv2os7.h}. For versions 8.1 and greater, use @file{tm-convex1.h} +or @file{tm-convex2.h}. You should also bootstrap GCC with @code{pcc} +rather than @code{cc}; one way to do this is with the following commands. + +@example +ln -s /bin/pcc ./cc +set path = (. $path) +@end example + +@item +Make a symbolic link named @file{md} to the machine description +pattern file. It should be in the @file{config} subdirectory and its +name should be @file{@var{machine}.md}; but @var{machine} is often not +the same as the name used in the @file{tm.h} file because the +@file{md} files are more general. + +@item +Make a symbolic link named @file{aux-output.c} to the output +subroutine file for your machine. It should be in the @file{config} +subdirectory and its name should be @file{out-@var{machine}.c}. +@end itemize + +@item +Make sure the Bison parser generator is installed. (This is +unnecessary if the Bison output files @file{c-parse.tab.c} and +@file{cexp.c} are more recent than @file{c-parse.y} and @file{cexp.y} +and you do not plan to change the @samp{.y} files.) + +Bison versions older than Sept 8, 1988 will produce incorrect output +for @file{c-parse.tab.c}. + +@item +If you have a previous version of GCC installed, then chances are +you can compile the new version with that. Do the following: + +@example +make CC="gcc -O" +@end example + +@noindent +Since this produces an optimized executable right away, there is no need +to bootstrap the result with itself except to test it. Therefore, you can +skip directly to the @samp{make install} step below. + +@item +Build the compiler. Just type @samp{make} in the compiler directory. + +Ignore any warnings you may see about ``statement not reached'' in the +@file{insn-emit.c}; they are normal. Any other compilation errors may +represent bugs in the port to your machine or operating system, and +should be investigated and reported (@pxref{Bugs}). + +Some commercial compilers fail to compile GNU CC because they have bugs +or limitations. For example, the Microsoft compiler is said to run out +of macro space. Some Ultrix compilers run out of expression space; then +you need to break up the statement where the problem happens. + +@item +If you are using COFF-encapsulation, you must convert @file{gnulib} to +a GNU-format library at this point. See the file @file{README-ENCAP} +in the directory containing the GNU binary file utilities, for +directions. + +@item +Move the first-stage object files and executables into a subdirectory +with this command: + +@example +make stage1 +@end example + +The files are moved into a subdirectory named @file{stage1}. +Once installation is complete, you may wish to delete these files +with @code{rm -r stage1}. + +@item +Recompile the compiler with itself, with this command: + +@example +make CC=stage1/gcc CFLAGS="-g -O -Bstage1/" +@end example + +This is called making the stage 2 compiler. + +On a 68000 or 68020 system lacking floating point hardware, +unless you have selected a @file{tm.h} file that expects by default +that there is no such hardware, do this instead: + +@example +make CC=stage1/gcc CFLAGS="-g -O -Bstage1/ -msoft-float" +@end example + +@item +If you wish to test the compiler by compiling it with itself one more +time, do this (in C shell): + +@example +make stage2 +make CC=stage2/gcc CFLAGS="-g -O -Bstage2/" +foreach file (*.o) +cmp $file stage2/$file +end +@end example + +@noindent +This is called making the stage 3 compiler. Aside from the @samp{-B} +option, the options should be the same as when you made the stage 2 +compiler. + +The @code{foreach} command (written in C shell) will notify you if any of +these stage 3 object files differs from those of stage 2. On BSD systems, +any difference, no matter how innocuous, indicates that the stage 2 +compiler has compiled GNU CC incorrectly, and is therefore a potentially +serious bug which you should investigate and report (@pxref{Bugs}). + +On systems that use COFF object files, bytes 5 to 8 will always be +different, since it is a timestamp. On these systems, you can do the +comparison as follows (in Bourne shell): + +@example +for file in *.o; do +echo $file +tail +10c $file > foo1 +tail +10c stage2/$file > foo2 +cmp foo1 foo2 +done +@end example + +On MIPS machines, you should use the shell script @file{ecoff-cmp} +to compare two object files. + +@item +Install the compiler driver, the compiler's passes and run-time support. +You can use the following command: + +@example +make install +@end example + +@noindent +This copies the files @file{cc1}, @file{cpp} and @file{gnulib} to +files @file{gcc-cc1}, @file{gcc-cpp} and @file{gcc-gnulib} in +directory @file{/usr/local/lib}, which is where the compiler driver +program looks for them. It also copies the driver program @file{gcc} +into the directory @file{/usr/local/bin}, so that it appears in typical +execution search paths.@refill + +@strong{Warning: there is a bug in @code{alloca} in the Sun library. +To avoid this bug, install the binaries of GNU CC that were compiled +by GNU CC. They use @code{alloca} as a built-in function and never +the one in the library.} + +@strong{Warning: the GNU CPP may not work for @file{ioctl.h}, +@file{ttychars.h} and other system header files unless the +@samp{-traditional} option is used.} The bug is in the header files: +at least on some machines, they rely on behavior that is incompatible +with ANSI C. This behavior consists of substituting for macro +argument names when they appear inside of character constants. The +@samp{-traditional} option tells GNU CC to behave the way these +headers expect. + +Because of this problem, you might prefer to configure GNU CC to use +the system's own C preprocessor. To do so, make the file +@file{/usr/local/lib/gcc-cpp} a link to @file{/lib/cpp}. + +Alternatively, on Sun systems and 4.3BSD at least, you can correct the +include files by running the shell script @file{fixincludes}. This +installs modified, corrected copies of the files @file{ioctl.h}, +@file{ttychars.h} and many others, in a special directory where only +GNU CC will normally look for them. This script will work on various +systems because it chooses the files by searching all the system +headers for the problem cases that we know about. + +Use the following command to do this: + +@example +make includes +@end example + +@noindent +If you selected a different directory for GNU CC installation when you +installed it, by specifying the Make variable @code{prefix} or +@code{libdir}, specify it the same way in this command. + +Note that some systems are starting to come with ANSI C system header +files. On these systems, don't run @file{fixincludes}; it may not work, +and is certainly not necessary. + +@strong{Warning:} @file{fixincludes} does not work on many MIPS systems, +because those systems come with circular symbolic links which cause +@samp{ls -lR} to go into an infinite loop. +@end enumerate + +If you cannot install the compiler's passes and run-time support in +@file{/usr/local/lib}, you can alternatively use the @samp{-B} option to +specify a prefix by which they may be found. The compiler concatenates +the prefix with the names @file{cpp}, @file{cc1} and @file{gnulib}. +Thus, you can put the files in a directory @file{/usr/foo/gcc} and +specify @samp{-B/usr/foo/gcc/} when you run GNU CC. + +Also, you can specify an alternative default directory for these files +by setting the Make variable @code{libdir} when you make GNU CC. + +@node Other Dir, Sun Install, Installation, Installation +@section Compilation in a Separate Directory + +If you wish to build the object files and executables in a directory +other than the one containing the source files, here is what you must +do differently: + +@enumerate +@item +Go to that directory before running @file{config.gcc}: + +@example +mkdir gcc-sun3 +cd gcc-sun3 +@end example + +On systems that do not support symbolic links, this directory must be +on the same file system as the source code directory. + +@item +Specify where to find @file{config.gcc} when you run it: + +@example +../gcc-1.36/config.gcc @dots{} +@end example + +@item +Specify where to find the sources, as an argument to @file{config.gcc}: + +@example +../gcc-1.36/config.gcc -srcdir=../gcc-1.36 sun3 +@end example + +The @samp{-srcdir=@var{dir}} option is not needed when the source +directory is the parent of the current directory, because +@file{config.gcc} detects that case automatically. +@end enumerate + +Now, you can run @code{make} in that directory. You need not repeat the +configuration steps shown above, when ordinary source files change. You +must, however, run @code{config.gcc} again when the configuration files +change, if your system does not support symbolic links. + +@node Sun Install, 3b1 Install, Other Dir, Installation +@section Installing GNU CC on the Sun + +Make sure the environment variable @code{FLOAT_OPTION} is not set when +you compile @file{gnulib}. If this option were set to @code{f68881} +when @file{gnulib} is compiled, the resulting code would demand to be +linked with a special startup file and would not link properly without +special pains. + +There is a bug in @code{alloca} in certain versions of the Sun library. +To avoid this bug, install the binaries of GNU CC that were compiled by +GNU CC. They use @code{alloca} as a built-in function and never the one +in the library. + +Some versions of the Sun compiler crash when compiling GNU CC, with a +segmentation fault in cpp. This can sometimes be due to the bulk of +data in the environment variables. You may be able to avoid it by using +the following command to compile GNU CC with Sun CC: + +@example +make CC="TERMCAP=x OBJS=x LIBFUNCS=x STAGESTUFF=x cc" +@end example + +Another problem that often happens on Suns is that you get a crash when +building stage 2, when @code{genflags} is run. + +One reason for such as crash is if you configured GNU CC for the wrong +version of SunOS. Starting with version 1.38, configurations @code{sun3} +and @code{sun4} are for SunOS 4, so this problem should no longer happen. + +Another cause of the same symptom is having installed the GNU linker +with an earlier version of SunOS. The version that worked before +stopped working due to a change in the format of executables in SunOS +4.1. Many sites have installed the GNU linker as +@file{/usr/local/lib/gcc-ld}, often as part of installing GNU C++. So +if you get such crashes and you have used the proper configuration, try +deleting @file{/usr/local/lib/gcc-ld}. + +The current version of the GNU linker, found in the current binutils +release, does work with SunOS 4.1. + +@node 3b1 Install, SCO Install, Sun Install, Installation +@section Installing GNU CC on the 3b1 + +Installing GNU CC on the 3b1 is difficult if you do not already have +GNU CC running, due to bugs in the installed C compiler. However, +the following procedure might work. We are unable to test it. + +@enumerate +@item +Comment out the @samp{#include "config.h"} line on line 37 of +@file{cccp.c} and do @samp{make cpp}. This makes a preliminary version +of GNU cpp. + +@item +Save the old @file{/lib/cpp} and copy the preliminary GNU cpp to that +file name. + +@item +Undo your change in @file{cccp.c}, or reinstall the original version, +and do @samp{make cpp} again. + +@item +Copy this final version of GNU cpp into @file{/lib/cpp}. + +@item +Replace every occurrence of @code{obstack_free} in @file{tree.c} +with @code{_obstack_free}. + +@item +Run @code{make} to get the first-stage GNU CC. + +@item +Reinstall the original version of @file{/lib/cpp}. + +@item +Now you can compile GNU CC with itself and install it in the normal +fashion. +@end enumerate + +If you have installed an earlier version of GCC, you can compile the +newer version with that. However, you will run into trouble compiling +@file{gnulib}, since that is normally compiled with CC. To solve the +problem, uncomment this line in @file{Makefile}: + +@example +CCLIBFLAGS = -B/usr/local/lib/gcc- -tp -Wp,-traditional +@end example + +@node SCO Install, VMS Install, 3B1 Install, Installation +@section Installing GNU CC on SCO System V 3.2 +@cindex Installation on SCO systems + +The compiler that comes with this system does not work properly with +@samp{-O}. Therefore, you should redefine the Make variable +@code{CCLIBFLAGS} not to use @samp{-O}. + +You should also edit @file{Makefile} to enable the lines that set +@code{CLIB} to @code{-lPW}, and the ones specifically labeled as being +for SCO, that set @code{RANLIB}, and that set @code{CC} and @code{OLDCC} +to @code{rcc}. + +Also, edit the definition of @code{USER_H} to remove the file @file{limits.h}. + +Then you can run @samp{config.gcc i386-sco} and finish building GNU CC +normally. + +The same recipe should work on ESIX, but use @samp{config.gcc i386-esix} +instead. + +@node VMS Install, HPUX Install, SCO Install, Installation +@section Installing GNU CC on VMS + +The VMS version of GNU CC is distributed in a backup saveset containing +both source code and precompiled binaries. + +To install the @file{gcc} command so you can use the compiler easily, in +the same manner as you use the VMS C compiler, you must install the VMS CLD +file for GNU CC as follows: + +@enumerate +@item +Define the VMS logical names @samp{GNU_CC} and @samp{GNU_CC_INCLUDE} +to point to the directories where the GNU CC executables +(@file{gcc-cpp}, @file{gcc-cc1}, etc.) and the C include files are +kept. This should be done with the commands:@refill + +@example +$ assign /super /system disk:[gcc.] gnu_cc +$ assign /super /system disk:[gcc.include.] gnu_cc_include +@end example + +@noindent +with the appropriate disk and directory names. These commands can be +placed in your system startup file so they will be executed whenever +the machine is rebooted. You may, if you choose, do this via the +@file{GCC_INSTALL.COM} script in the @file{[GCC]} directory. + +@item +Install the @file{GCC} command with the command line: + +@example +$ set command /table=sys$library:dcltables gnu_cc:[000000]gcc +@end example + +@item +To install the help file, do the following: + +@example +$ lib/help sys$library:helplib.hlb gcc.hlp +@end example + +@noindent +Now you can invoke the compiler with a command like @samp{gcc /verbose +file.c}, which is equivalent to the command @samp{gcc -v -c file.c} in +Unix. +@end enumerate + +We try to put corresponding binaries and sources on the VMS distribution +tape. But sometimes the binaries will be from an older version that the +sources, because we don't always have time to update them. (Use the +@samp{/verbose} option to determine the version number of the binaries and +compare it with the source file @file{version.c} to tell whether this is +so.) In this case, you should use the binaries you get to recompile the +sources. If you must recompile, here is how: + +@enumerate +@item +Copy the file @file{tm-vms.h} to @file{tm.h}, @file{xm-vms.h} to +@file{config.h}, @file{vax.md} to @file{md.} and @file{out-vax.c} +to @file{aux-output.c}. The files to be copied are found in the +subdirectory named @file{config}; they should be copied to the +main directory of GNU CC.@refill + +@item +Setup the logical names and command tables as defined above. In +addition, define the vms logical name @samp{GNU_BISON} to point at the +to the directories where the Bison executable is kept. This should be +done with the command:@refill + +@example +$ assign /super /system disk:[bison.] gnu_bison +@end example + +You may, if you choose, use the @file{INSTALL_BISON.COM} script in the +@file{[BISON]} directory. + +@item +Install the @samp{BISON} command with the command line:@refill + +@example +$ set command /table=sys$library:dcltables gnu_bison:[000000]bison +@end example + +@item +Type @samp{@@make} to do recompile everything. + +If you are compiling with a version of GNU CC older than 1.33, specify +@samp{/DEFINE=("inline=")} as an option in all the compilations. This +requires editing all the @code{gcc} commands in @file{make-cc1.com}. +(The older versions had problems supporting @code{inline}.) Once you +have a working 1.33 or newer GNU CC, you can change this file back. +@end enumerate + +Due to the differences between the filesystems of Unix and VMS, the +preprocessor attempts to translate the names of include files into +something that VMS will understand. The basic strategy is to prepend a +prefix to the specification of the include file, convert the whole +filename to a VMS filename, and then try to open the file. The +preprocessor tries various prefixes until one of them succeeds. + +The first prefix is the @samp{GNU_CC_INCLUDE:} logical name: this is +where GNU_C header files are traditionally stored. If a header file is +not found there, @samp{SYS$SYSROOT:[SYSLIB.]} is tried next. If the +preprocessor is still unable to locate the file, it then assumes that +the include file specification is a valid VMS filename all by itself, +and it uses this filename to attempt to open the include file. If none +of these strategies succeeds, the preprocessor reports an error. + +If you wish to store header files in non-standard locations, then you +can assign the logical @samp{GNU_CC_INCLUDE} to be a search list, where +each element of the list is suitable for use with a rooted logical. + +With this version of GNU CC, @code{const} global variables now work +properly. Unless, however, the @code{const} modifier is also specified +in every external declaration of the variable in all of the source files +that use that variable, the linker will issue warnings about conflicting +attributes for the variable, since the linker does not know if the +variable should be read-only. The program will still work, but the +variable will be placed in writable storage. + +Due to an assembler bug, offsets to static constants are sometimes +incorrectly evaluated. This bug is present in GAS 1.38.1, and should be +fixed in the next version. + +Under previous versions of GNU CC, the generated code would occasionally +give strange results when linked to the sharable @file{VAXCRTL} library. +Now this should work. + +Even with this version, however, GNU CC itself should not be linked to the +sharable @file{VAXCRTL}. The @file{qsort} routine supplied with @file{VAXCRTL} +has a bug which can cause a compiler crash. + +Similarly, the preprocessor should not be linked to the sharable +@file{VAXCRTL}. The @code{strncat} routine supplied with @file{VAXCRTL} has a +bug which can cause the preprocessor to go into an infinite loop. + +It should be pointed out that if you attempt to link to the sharable +@file{VAXCRTL}, the VMS linker will strongly resist any effort to force +it to use the @code{qsort} and @code{strncat} routines from +@file{gcclib}. Until the bugs in @file{VAXCRTL} have been fixed, +linking any of the compiler components to the sharable VAXCRTL is not +recommended. (These routines can be bypassed by placing duplicate copies +of @code{qsort} and @code{strncat} in @file{gcclib} under different +names, and patching the compiler sources to use these routines). Both +of the bugs in @file{VAXCRTL} are still present in VMS version 5.4-1, +which is the most recent version as of this writing. + +The executables that are generated by @file{make-cc1.com} and +@file{make-cccp.com} use the non-shared version of @file{VAXCRTL} (and +thus use the @code{qsort} and @code{strncat} routines from +@file{gcclib.olb}). + +Note that GNU CC on VMS now generates debugging information to describe +the programs symbols to the VMS debugger. However, you need version 1.37 +or later of GAS in order to output them properly in the object file. + +The VMS linker does not distinguish between upper and lower case letters +in function and variable names. However, usual practice in C is to +distinguish case. Normally GNU C (by means of the assembler GAS) +implements usual C behavior by augmenting each name that is not all +lower-case. A name is augmented by truncating it to at most 23 +characters and then adding more characters at the end which encode the +case pattern the rest. + +Name augmentation yields bad results for programs that use precompiled +libraries (such as Xlib) which were generated by another compiler. Use +the compiler option @samp{/NOCASE_HACK} to inhibits augmentation; it +makes external C functions and variables case-independent as is usual on +VMS. Alternatively, you could write all references to the functions and +variables in such libraries using lower case; this will work on VMS, but +is not portable to other systems. In cases where you need to +selectively inhibit augmentation, you can define a macro for each mixed +case symbol for which you wish to inhibit augmentation, where the macro +expands into the lower case equivalent of the name. + +@node HPUX Install, Tower Install, VMS Install, Installation +@section Installing GNU CC on HPUX + +To install GNU CC on HPUX, you must start by editing the file +@file{Makefile}. Search for the string @samp{HPUX} to find comments +saying what to change. You need to change some variable definitions and +(if you are using GAS) some lines in the rule for the target +@samp{gnulib}. + +To avoid errors when linking programs with @samp{-g}, create an empty +library named @file{libg.a}. An easy way to do this is: + +@example +ar rc /usr/local/lib/libg.a +@end example + +To compile with the HPUX C compiler, you must specify get the file +@file{alloca.c} from GNU Emacs. Then, when you run @code{make}, use +this argument: + +@example +make ALLOCA=alloca.o +@end example + +When recompiling GNU CC with itself, do not define @code{ALLOCA}. +Instead, an @samp{-I} option needs to be added to @code{CFLAGS} as +follows: + +@example +make CC=stage1/gcc CFLAGS="-g -O -Bstage1/ -I../binutils/hp-include" +@end example + +@node Tower Install,, HPUX Install, Installation +@section Installing GNU CC on an NCR Tower + +On an NCR Tower model 4x0 or 6x0, you may have trouble because the +default maximum virtual address size of a process is just 1 Mb. Most +often you will find this problem while compiling GNU CC with itself. + +The only way to solve the problem is to reconfigure the kernel. +Add a line such as this to the configuration file: + +@example +MAXUMEM = 4096 +@end example + +@noindent +and then relink the kernel and reboot the machine. + + +@node Trouble, Service, Installation, Top +@chapter Known Causes of Trouble with GNU CC + +Here are some of the things that have caused trouble for people installing +or using GNU CC. + +@itemize @bullet +@item +On certain systems, defining certain environment variables such as +@code{CC} can interfere with the functioning of @code{make}. + +@item +Cross compilation can run into trouble for certain machines because +some target machines' assemblers require floating point numbers to be +written as @emph{integer} constants in certain contexts. + +The compiler writes these integer constants by examining the floating +point value as an integer and printing that integer, because this is +simple to write and independent of the details of the floating point +representation. But this does not work if the compiler is running on +a different machine with an incompatible floating point format, or +even a different byte-ordering. + +In addition, correct constant folding of floating point values +requires representing them in the target machine's format. +(The C standard does not quite require this, but in practice +it is the only way to win.) + +It is now possible to overcome these problems by defining macros such +as @code{REAL_VALUE_TYPE}. But doing so is a substantial amount of +work for each target machine. @xref{Cross-compilation}. + +@item +Users often think it is a bug when GNU CC reports an error for code +like this: + +@example +int foo (short); + +int foo (x) + short x; +@{@dots{}@} +@end example + +The error message is correct: this code really is erroneous, because the +old-style non-prototype definition passes subword integers in their +promoted types. In other words, the argument is really an @code{int}, +not a @code{short}. The correct prototype is this: + +@example +int foo (int); +@end example + +@item +Users often think it is a bug when GNU CC reports an error for code +like this: + +@example +int foo (struct mumble *); + +struct mumble @{ @dots{} @}; + +int foo (struct mumble *x) +@{ @dots{} @} +@end example + +This code really is erroneous, because the scope of @code{struct +mumble} the prototype is limited to the argument list containing it. +It does not refer to the @code{struct mumble} defined with file scope +immediately below---they are two unrelated types with similar names in +different scopes. + +But in the definition of @code{foo}, the file-scope type is used +because that is available to be inherited. Thus, the definition and +the prototype do not match, and you get an error. + +This behavior may seem silly, but it's what the ANSI standard +specifies. It is easy enough for you to make your code work by moving +the definition of @code{struct mumble} above the prototype. I don't +think it's worth being incompatible for. +@end itemize + +Additional problems are described in @ref{Incompatibilities}. + +@node Service, Incompatibilities, Trouble, Top +@chapter How To Get Help with GNU CC + +If you need help installing, using or changing GNU CC, there are two +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}. + +@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. +@end itemize + +@node Incompatibilities, Extensions, Service, Top +@chapter Incompatibilities of GNU CC + +There are several noteworthy incompatibilities between GNU C and most +existing (non-ANSI) versions of C. The @samp{-traditional} option +eliminates most of these incompatibilities, @emph{but not all}, by +telling GNU C to behave like older C compilers. + +@itemize @bullet +@item +GNU CC normally makes string constants read-only. If several +identical-looking string constants are used, GNU CC stores only one +copy of the string. + +One consequence is that you cannot call @code{mktemp} with a string +constant argument. The function @code{mktemp} always alters the +string its argument points to. + +Another consequence is that @code{sscanf} does not work on some +systems when passed a string constant as its format control string. +This is because @code{sscanf} incorrectly tries to write into the +string constant. Likewise @code{fscanf} and @code{scanf}. + +The best solution to these problems is to change the program to use +@code{char}-array variables with initialization strings for these +purposes instead of string constants. But if this is not possible, +you can use the @samp{-fwritable-strings} flag, which directs GNU CC +to handle string constants the same way most C compilers do. +@samp{-traditional} also has this effect, among others. + +@item +GNU CC does not substitute macro arguments when they appear inside of +string constants. For example, the following macro in GNU CC + +@example +#define foo(a) "a" +@end example + +@noindent +will produce output @code{"a"} regardless of what the argument @var{a} is. + +The @samp{-traditional} option directs GNU CC to handle such cases +(among others) in the old-fashioned (non-ANSI) fashion. + +@item +When you use @code{setjmp} and @code{longjmp}, the only automatic +variables guaranteed to remain valid are those declared +@code{volatile}. This is a consequence of automatic register +allocation. Consider this function: + +@example +jmp_buf j; + +foo () +@{ + int a, b; + + a = fun1 (); + if (setjmp (j)) + return a; + + a = fun2 (); + /* @r{@code{longjmp (j)} may be occur in @code{fun3}.} */ + return a + fun3 (); +@} +@end example + +Here @code{a} may or may not be restored to its first value when the +@code{longjmp} occurs. If @code{a} is allocated in a register, then +its first value is restored; otherwise, it keeps the last value stored +in it. + +If you use the @samp{-W} option with the @samp{-O} option, you will +get a warning when GNU CC thinks such a problem might be possible. + +The @samp{-traditional} option directs GNU C to put variables in +the stack by default, rather than in registers, in functions that +call @code{setjmp}. This results in the behavior found in +traditional C compilers. + +@item +Declarations of external variables and functions within a block apply +only to the block containing the declaration. In other words, they +have the same scope as any other declaration in the same place. + +In some other C compilers, a @code{extern} declaration affects all the +rest of the file even if it happens within a block. + +The @samp{-traditional} option directs GNU C to treat all @code{extern} +declarations as global, like traditional compilers. + +@item +In traditional C, you can combine @code{long}, etc., with a typedef name, +as shown here: + +@example +typedef int foo; +typedef long foo bar; +@end example + +In ANSI C, this is not allowed: @code{long} and other type modifiers +require an explicit @code{int}. Because this criterion is expressed +by Bison grammar rules rather than C code, the @samp{-traditional} +flag cannot alter it. + +@item +PCC allows typedef names to be used as function parameters. The +difficulty described immediately above applies here too. + +@item +PCC allows whitespace in the middle of compound assignment operators +such as @samp{+=}. GNU CC, following the ANSI standard, does not +allow this. The difficulty described immediately above applies here +too. + +@item +GNU CC will flag unterminated character constants inside of preprocessor +conditionals that fail. Some programs have English comments enclosed in +conditionals that are guaranteed to fail; if these comments contain +apostrophes, GNU CC will probably report an error. For example, +this code would produce an error: + +@example +#if 0 +You can't expect this to work. +#endif +@end example + +The best solution to such a problem is to put the text into an actual +C comment delimited by @samp{/*@dots{}*/}. However, +@samp{-traditional} suppresses these error messages. + +@item +When compiling functions that return @code{float}, PCC converts it to +a double. GNU CC actually returns a @code{float}. If you are concerned +with PCC compatibility, you should declare your functions to return +@code{double}; you might as well say what you mean. + +@item +When compiling functions that return structures or unions, GNU CC +output code normally uses a method different from that used on most +versions of Unix. As a result, code compiled with GNU CC cannot call +a structure-returning function compiled with PCC, and vice versa. + +The method used by GNU CC is as follows: a structure or union which is 1, +2, 4 or 8 bytes long is returned like a scalar. A structure or union +with any other size is stored into an address supplied by the caller +in a special, fixed register. + +PCC usually handles all sizes of structures and unions by returning +the address of a block of static storage containing the value. This +method is not used in GNU CC because it is slower and nonreentrant. + +You can tell GNU CC to use the PCC convention with the option +@samp{-fpcc-struct-return}. +@end itemize + +There are also system-specific incompatibilities. + +@itemize @bullet +@item +On the Sparc, GNU CC uses an incompatible calling convention for +structures. It passes them by including their contents in the argument +list, whereas the standard compiler passes them effectively by +reference. + +This really ought to be fixed, but such calling conventions are not +yet supported in GNU CC, so it isn't straightforward to fix it. +GNU CC version 2 will use a compatible calling convention. + +The convention for structure returning is also incompatible, and +@samp{-fpcc-struct-return} does not help. + +@item +The Sparc version of @code{setjmp} interacts badly with unexpected stack +adjustments. With rare exceptions, you cannot use @code{setjmp} in a +function which moves the stack pointer. + +In the current version of GNU CC, there are three ways that the stack +pointer can change value: (1) calls to @code{alloca}, (2) use of +variable-sized objects, and (3) calls to functions with parameters that +do not all fit in the argument-passing registers (e.g., more than 6 +parameters). You should avoid all three in functions that call +@code{setjmp}. + +The cause of the problem is the way that Sun implemented register +windows. The 64 bytes at addresses @code{%sp} through @code{%sp+63} +correspond to the register window save area. When a register window +must be spilled, its stack pointer is located, and the registers are +dumped starting at that address. Similarly, when a register window must +be restored, its stack pointer is located, and the registers are +restored from that address. + +When @code{setjmp} is called, the current register window's registers +are saved into the register save area, and when @code{longjmp} is +called, they are restored (actually, @emph{all} register windows are +restored from all valid register windows at the time @code{longjmp} is +called). If there is a change in the value of the stack pointer bewteen +the @code{setjmp} and @code{longjmp} calls, when the registers are +restored, they are restored with random values. + +@item +On Ultrix, the Fortran compiler expects registers 2 through 5 to be saved +by function calls. We have not been able to tell whether the C compiler +agrees with the Fortran compiler. Currently, GNU CC treats these registers +as temporaries on the Vax, which is compatible with BSD Unix. + +If we learn for certain that Ultrix has departed from the traditional +BSD calling convention, we will change GNU CC for Ultrix to fit. In the +mean time, you can use these options to produce code compatible with the +Fortran compiler: + +@example +-fcall-saved-r2 -fcall-saved-r3 -fcall-saved-r4 -fcall-saved-r5 +@end example + +@item +DBX rejects some files produced by GNU CC, though it accepts similar +constructs in output from PCC. Until someone can supply a coherent +description of what is valid DBX input and what is not, there is +nothing I can do about these problems. You are on your own. +@end itemize + +@node Extensions, Bugs, Incompatibilities, Top +@chapter GNU Extensions to the C Language + +GNU C provides several language features not found in ANSI standard C. +(The @samp{-pedantic} option directs GNU CC to print a warning message if +any of these features is used.) To test for the availability of these +features in conditional compilation, check for a predefined macro +@code{__GNUC__}, which is always defined under GNU CC. + +@menu +* Statement Exprs:: Putting statements and declarations inside expressions. +* Naming Types:: Giving a name to the type of some expression. +* Typeof:: @code{typeof}: referring to the type of an expression. +* Lvalues:: Using @samp{?:}, @samp{,} and casts in lvalues. +* Conditionals:: Omitting the middle operand of a @samp{?:} expression. +* Zero-Length:: Zero-length arrays. +* Variable-Length:: Arrays whose length is computed at run time. +* Subscripting:: Any array can be subscripted, even if not an lvalue. +* Pointer Arith:: Arithmetic on @code{void}-pointers and function pointers. +* Initializers:: Non-constant initializers. +* Constructors:: Constructor expressions give structures, unions + or arrays as values. +* Function Attributes:: Declaring that functions have no side effects, + or that they can never return. +* Dollar Signs:: Dollar sign is allowed in identifiers. +* Alignment:: Inquiring about the alignment of a type or variable. +* Inline:: Defining inline functions (as fast as macros). +* Extended Asm:: Assembler instructions with C expressions as operands. + (With them you can define ``built-in'' functions.) +* Asm Labels:: Specifying the assembler name to use for a C symbol. +* Explicit Reg Vars:: Defining variables residing in specified registers. +* Alternate Keywords:: @code{__const__}, @code{__asm__}, etc., for header files. +@end menu + +@node Statement Exprs, Naming Types, Extensions, Extensions +@section Statements and Declarations inside of Expressions + +A compound statement in parentheses may appear inside an expression in GNU +C. This allows you to declare variables within an expression. For +example: + +@example +(@{ int y = foo (); int z; + if (y > 0) z = y; + else z = - y; + z; @}) +@end example + +@noindent +is a valid (though slightly more complex than necessary) expression +for the absolute value of @code{foo ()}. + +This feature is especially useful in making macro definitions ``safe'' (so +that they evaluate each operand exactly once). For example, the +``maximum'' function is commonly defined as a macro in standard C as +follows: + +@example +#define max(a,b) ((a) > (b) ? (a) : (b)) +@end example + +@noindent +But this definition computes either @var{a} or @var{b} twice, with bad +results if the operand has side effects. In GNU C, if you know the +type of the operands (here let's assume @code{int}), you can define +the macro safely as follows: + +@example +#define maxint(a,b) \ + (@{int _a = (a), _b = (b); _a > _b ? _a : _b; @}) +@end example + +Embedded statements are not allowed in constant expressions, such as +the value of an enumeration constant, the width of a bit field, or +the initial value of a static variable. + +If you don't know the type of the operand, you can still do this, but you +must use @code{typeof} (@pxref{Typeof}) or type naming (@pxref{Naming +Types}). + +@node Naming Types, Typeof, Statement Exprs, Extensions +@section Naming an Expression's Type + +You can give a name to the type of an expression using a @code{typedef} +declaration with an initializer. Here is how to define @var{name} as a +type name for the type of @var{exp}: + +@example +typedef @var{name} = @var{exp}; +@end example + +This is useful in conjunction with the statements-within-expressions +feature. Here is how the two together can be used to define a safe +``maximum'' macro that operates on any arithmetic type: + +@example +#define max(a,b) \ + (@{typedef _ta = (a), _tb = (b); \ + _ta _a = (a); _tb _b = (b); \ + _a > _b ? _a : _b; @}) +@end example + +The reason for using names that start with underscores for the local +variables is to avoid conflicts with variable names that occur within the +expressions that are substituted for @code{a} and @code{b}. Eventually we +hope to design a new form of declaration syntax that allows you to declare +variables whose scopes start only after their initializers; this will be a +more reliable way to prevent such conflicts. + +@node Typeof, Lvalues, Naming Types, Extensions +@section Referring to a Type with @code{typeof} + +Another way to refer to the type of an expression is with @code{typeof}. +The syntax of using of this keyword looks like @code{sizeof}, but the +construct acts semantically like a type name defined with @code{typedef}. + +There are two ways of writing the argument to @code{typeof}: with an +expression or with a type. Here is an example with an expression: + +@example +typeof (x[0](1)) +@end example + +@noindent +This assumes that @code{x} is an array of functions; the type described +is that of the values of the functions. + +Here is an example with a typename as the argument: + +@example +typeof (int *) +@end example + +@noindent +Here the type described is that of pointers to @code{int}. + +If you are writing a header file that must work when included in ANSI C +programs, write @code{__typeof__} instead of @code{typeof}. +@xref{Alternate Keywords}. + +A @code{typeof}-construct can be used anywhere a typedef name could be +used. For example, you can use it in a declaration, in a cast, or inside +of @code{sizeof} or @code{typeof}. + +@itemize @bullet +@item +This declares @code{y} with the type of what @code{x} points to. + +@example +typeof (*x) y; +@end example + +@item +This declares @code{y} as an array of such values. + +@example +typeof (*x) y[4]; +@end example + +@item +This declares @code{y} as an array of pointers to characters: + +@example +typeof (typeof (char *)[4]) y; +@end example + +@noindent +It is equivalent to the following traditional C declaration: + +@example +char *y[4]; +@end example + +To see the meaning of the declaration using @code{typeof}, and why it +might be a useful way to write, let's rewrite it with these macros: + +@example +#define pointer(T) typeof(T *) +#define array(T, N) typeof(T [N]) +@end example + +@noindent +Now the declaration can be rewritten this way: + +@example +array (pointer (char), 4) y; +@end example + +@noindent +Thus, @code{array (pointer (char), 4)} is the type of arrays of 4 +pointers to @code{char}. +@end itemize + +@node Lvalues, Conditionals, Typeof, Extensions +@section Generalized Lvalues + +Compound expressions, conditional expressions and casts are allowed as +lvalues provided their operands are lvalues. This means that you can take +their addresses or store values into them. + +For example, a compound expression can be assigned, provided the last +expression in the sequence is an lvalue. These two expressions are +equivalent: + +@example +(a, b) += 5 +a, (b += 5) +@end example + +Similarly, the address of the compound expression can be taken. These two +expressions are equivalent: + +@example +&(a, b) +a, &b +@end example + +A conditional expression is a valid lvalue if its type is not void and the +true and false branches are both valid lvalues. For example, these two +expressions are equivalent: + +@example +(a ? b : c) = 5 +(a ? b = 5 : (c = 5)) +@end example + +A cast is a valid lvalue if its operand is valid. Taking the address of +the cast is the same as taking the address without a cast, except for the +type of the result. For example, these two expressions are equivalent (but +the second may be valid when the type of @code{a} does not permit a cast to +@code{int *}). + +@example +&(int *)a +(int **)&a +@end example + +A simple assignment whose left-hand side is a cast works by converting the +right-hand side first to the specified type, then to the type of the inner +left-hand side expression. After this is stored, the value is converter +back to the specified type to become the value of the assignment. Thus, if +@code{a} has type @code{char *}, the following two expressions are +equivalent: + +@example +(int)a = 5 +(int)(a = (char *)5) +@end example + +An assignment-with-arithmetic operation such as @samp{+=} applied to a cast +performs the arithmetic using the type resulting from the cast, and then +continues as in the previous case. Therefore, these two expressions are +equivalent: + +@example +(int)a += 5 +(int)(a = (char *) ((int)a + 5)) +@end example + +@node Conditionals, Zero-Length, Lvalues, Extensions +@section Conditional Expressions with Omitted Middle-Operands + +The middle operand in a conditional expression may be omitted. Then +if the first operand is nonzero, its value is the value of the conditional +expression. + +Therefore, the expression + +@example +x ? : y +@end example + +@noindent +has the value of @code{x} if that is nonzero; otherwise, the value of +@code{y}. + +This example is perfectly equivalent to + +@example +x ? x : y +@end example + +@noindent +In this simple case, the ability to omit the middle operand is not +especially useful. When it becomes useful is when the first operand does, +or may (if it is a macro argument), contain a side effect. Then repeating +the operand in the middle would perform the side effect twice. Omitting +the middle operand uses the value already computed without the undesirable +effects of recomputing it. + +@node Zero-Length, Variable-Length, Conditionals, Extensions +@section Arrays of Length Zero + +Zero-length arrays are allowed in GNU C. They are very useful as the last +element of a structure which is really a header for a variable-length +object: + +@example +struct line @{ + int length; + char contents[0]; +@}; + +@{ + struct line *thisline + = (struct line *) malloc (sizeof (struct line) + this_length); + thisline->length = this_length; +@} +@end example + +In standard C, you would have to give @code{contents} a length of 1, which +means either you waste space or complicate the argument to @code{malloc}. + +@node Variable-Length, Subscripting, Zero-Length, Extensions +@section Arrays of Variable Length + +Variable-length automatic arrays are allowed in GNU C. These arrays are +declared like any other automatic arrays, but with a length that is not a +constant expression. The storage is allocated at that time and +deallocated when the brace-level is exited. For example: + +@example +FILE *concat_fopen (char *s1, char *s2, char *mode) +@{ + char str[strlen (s1) + strlen (s2) + 1]; + strcpy (str, s1); + strcat (str, s2); + return fopen (str, mode); +@} +@end example + +You can also use variable-length arrays as arguments to functions: + +@example +struct entry +tester (int len, char data[len]) +@{ + @dots{} +@} +@end example + +The length of an array is computed on entry to the brace-level where the +array is declared and is remembered for the scope of the array in case you +access it with @code{sizeof}. + +Jumping or breaking out of the scope of the array name will also deallocate +the storage. Jumping into the scope is not allowed; you will get an error +message for it. + +You can use the function @code{alloca} to get an effect much like +variable-length arrays. The function @code{alloca} is available in +many other C implementations (but not in all). On the other hand, +variable-length arrays are more elegant. + +There are other differences between these two methods. Space allocated +with @code{alloca} exists until the containing @emph{function} returns. +The space for a variable-length array is deallocated as soon as the array +name's scope ends. (If you use both variable-length arrays and +@code{alloca} in the same function, deallocation of a variable-length array +will also deallocate anything more recently allocated with @code{alloca}.) + +@node Subscripting, Pointer Arith, Variable-Length, Extensions +@section Non-Lvalue Arrays May Have Subscripts + +Subscripting is allowed on arrays that are not lvalues, even though the +unary @samp{&} operator is not. For example, this is valid in GNU C though +not valid in other C dialects: + +@example +struct foo @{int a[4];@}; + +struct foo f(); + +bar (int index) +@{ + return f().a[index]; +@} +@end example + +@node Pointer Arith, Initializers, Subscripting, Extensions +@section Arithmetic on @code{void}-Pointers and Function Pointers + +In GNU C, addition and subtraction operations are supported on pointers to +@code{void} and on pointers to functions. This is done by treating the +size of a @code{void} or of a function as 1. + +A consequence of this is that @code{sizeof} is also allowed on @code{void} +and on function types, and returns 1. + +The option @samp{-Wpointer-arith} requests a warning if these extensions +are used. + +@node Initializers, Constructors, Pointer Arith, Extensions +@section Non-Constant Initializers + +The elements of an aggregate initializer for an automatic variable are +not required to be constant expressions in GNU C. Here is an example of +an initializer with run-time varying elements: + +@example +foo (float f, float g) +@{ + float beat_freqs[2] = @{ f-g, f+g @}; + @dots{} +@} +@end example + +@node Constructors, Function Attributes, Initializers, Extensions +@section Constructor Expressions + +GNU C supports constructor expressions. A constructor looks like a cast +containing an initializer. Its value is an object of the type specified in +the cast, containing the elements specified in the initializer. The type +must be a structure, union or array type. + +Assume that @code{struct foo} and @code{structure} are declared as shown: + +@example +struct foo @{int a; char b[2];@} structure; +@end example + +@noindent +Here is an example of constructing a @code{struct foo} with a constructor: + +@example +structure = ((struct foo) @{x + y, 'a', 0@}); +@end example + +@noindent +This is equivalent to writing the following: + +@example +@{ + struct foo temp = @{x + y, 'a', 0@}; + structure = temp; +@} +@end example + +You can also construct an array. If all the elements of the constructor +are (made up of) simple constant expressions, suitable for use in +initializers, then the constructor is an lvalue and can be coerced to a +pointer to its first element, as shown here: + +@example +char **foo = (char *[]) @{ "x", "y", "z" @}; +@end example + +Array constructors whose elements are not simple constants are not very +useful, because the constructor is not an lvalue. There are only two valid +ways to use it: to subscript it, or initialize an array variable with it. +The former is probably slower than a @code{switch} statement, while the +latter does the same thing an ordinary C initializer would do. + +@example +output = ((int[]) @{ 2, x, 28 @}) [input]; +@end example + +@node Function Attributes, Dollar Signs, Constructors, Extensions +@section Declaring Attributes of Functions + +In GNU C, you declare certain things about functions called in your program +which help the compiler optimize function calls. + +A few functions, such as @code{abort} and @code{exit}, cannot return. +These functions should be declared @code{volatile}. For example, + +@example +extern volatile void abort (); +@end example + +@noindent +tells the compiler that it can assume that @code{abort} will not return. +This makes slightly better code, but more importantly it helps avoid +spurious warnings of uninitialized variables. + +Many functions do not examine any values except their arguments, and +have no effects except the return value. Such a function can be subject +to common subexpression elimination and loop optimization just as an +arithmetic operator would be. These functions should be declared +@code{const}. For example, + +@example +extern const void square (); +@end example + +@noindent +says that the hypothetical function @code{square} is safe to call +fewer times than the program says. + +Note that a function that has pointer arguments and examines the data +pointed to must @emph{not} be declared @code{const}. Likewise, a +function that calls a non-@code{const} function usually must not be +@code{const}. + +Some people object to this feature, claiming that ANSI C's @code{#pragma} +should be used instead. There are two reasons I did not do this. + +@enumerate +@item +It is impossible to generate @code{#pragma} commands from a macro. + +@item +The @code{#pragma} command is just as likely as these keywords to mean +something else in another compiler. +@end enumerate + +These two reasons apply to @emph{any} application whatever: as far as +I can see, @code{#pragma} is never useful. + +@node Dollar Signs, Alignment, Function Attributes, Extensions +@section Dollar Signs in Identifier Names + +In GNU C, you may use dollar signs in identifier names. This is because +many traditional C implementations allow such identifiers. + +Dollar signs are allowed if you specify @samp{-traditional}; they are +not allowed if you specify @samp{-ansi}. Whether they are allowed by +default depends on the target machine; usually, they are not. + +@node Alignment, Inline, Dollar Signs, Extensions +@section Inquiring about the Alignment of a Type or Variable + +The keyword @code{__alignof__} allows you to inquire about how an object +is aligned, or the minimum alignment usually required by a type. Its +syntax is just like @code{sizeof}. + +For example, if the target machine requires a @code{double} value to be +aligned on an 8-byte boundary, then @code{__alignof__ (double)} is 8. +This is true on many RISC machines. On more traditional machine +designs, @code{__alignof__ (double)} is 4 or even 2. + +Some machines never actually require alignment; they allow reference to any +data type even at an odd addresses. For these machines, @code{__alignof__} +reports the @emph{recommended} alignment of a type. + +When the operand of @code{__alignof__} is an lvalue rather than a type, the +value is the largest alignment that the lvalue is known to have. It may +have this alignment as a result of its data type, or because it is part of +a structure and inherits alignment from that structure. For example, after +this declaration: + +@example +struct foo @{ int x; char y; @} foo1; +@end example + +@noindent +the value of @code{__alignof__ (foo1.y)} is probably 2 or 4, the same as +@code{__alignof__ (int)}, even though the data type of @code{foo1.y} +does not itself demand any alignment.@refill + +@node Inline, Extended Asm, Alignment, Extensions +@section An Inline Function is As Fast As a Macro + +By declaring a function @code{inline}, you can direct GNU CC to integrate +that function's code into the code for its callers. This makes execution +faster by eliminating the function-call overhead; in addition, if any of +the actual argument values are constant, their known values may permit +simplifications at compile time so that not all of the inline function's +code needs to be included. + +To declare a function inline, use the @code{inline} keyword in its +declaration, like this: + +@example +inline int +inc (int *a) +@{ + (*a)++; +@} +@end example + +(If you are writing a header file to be included in ANSI C programs, write +@code{__inline__} instead of @code{inline}. @xref{Alternate Keywords}.) + +You can also make all ``simple enough'' functions inline with the option +@samp{-finline-functions}. Note that certain usages in a function +definition can make it unsuitable for inline substitution. + +When a function is both inline and @code{static}, if all calls to the +function are integrated into the caller, and the function's address is +never used, then the function's own assembler code is never referenced. +In this case, GNU CC does not actually output assembler code for the +function, unless you specify the option @samp{-fkeep-inline-functions}. +Some calls cannot be integrated for various reasons (in particular, +calls that precede the function's definition cannot be integrated, and +neither can recursive calls within the definition). If there is a +nonintegrated call, then the function is compiled to assembler code as +usual. The function must also be compiled as usual if the program +refers to its address, because that can't be inlined. + +When an inline function is not @code{static}, then the compiler must assume +that there may be calls from other source files; since a global symbol can +be defined only once in any program, the function must not be defined in +the other source files, so the calls therein cannot be integrated. +Therefore, a non-@code{static} inline function is always compiled on its +own in the usual fashion. + +If you specify both @code{inline} and @code{extern} in the function +definition, then the definition is used only for inlining. In no case +is the function compiled on its own, not even if you refer to its +address explicitly. Such an address becomes an external reference, as +if you had only declared the function, and had not defined it. + +This combination of @code{inline} and @code{extern} has almost the +effect of a macro. The way to use it is to put a function definition in +a header file with these keywords, and put another copy of the +definition (lacking @code{inline} and @code{extern}) in a library file. +The definition in the header file will cause most calls to the function +to be inlined. If any uses of the function remain, they will refer to +the single copy in the library. + +@node Extended Asm, Asm Labels, Inline, Extensions +@section Assembler Instructions with C Expression Operands + +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 +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. + +For example, here is how to use the 68881's @code{fsinx} instruction: + +@example +asm ("fsinx %1,%0" : "=f" (result) : "f" (angle)); +@end example + +@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 the maximum number of +operands in any instruction pattern in the machine description. + +If there are no output operands, and there are input operands, then there +must be 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. + +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: + +@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. + +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: + +@example +asm ("combine %2,%0" : "=r" (foo) : "r" (foo), "g" (bar)); +@end example + +Various optimizations or reloading could cause operands 0 and 1 to be in +different registers; GNU CC knows no reason not to do so. For example, the +compiler might find a copy of the value of @code{foo} in one register and +use it for operand 1, but generate the output operand 0 in a different +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. + +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. +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}. + +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" + : /* no outputs */ + : "g" (from), "g" (to), "g" (count) + : "r0", "r1", "r2", "r3", "r4", "r5"); +@end example + +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: + +@example +asm ("movl %0,r9;movl %1,r10;call _foo" + : /* no outputs */ + : "g" (from), "g" (to) + : "r9", "r10"); +@end example + +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:" + : "g" (result) + : "g" (input)); +@end example + +@noindent +This assumes your assembler supports local labels, as the GNU assembler +and most Unix assemblers do. + +Usually the most convenient way to use these @code{asm} instructions is to +encapsulate them in macros that look like functions. For example, + +@example +#define sin(x) \ +(@{ double __value, __arg = (x); \ + asm ("fsinx %1,%0": "=f" (__value): "f" (__arg)); \ + __value; @}) +@end example + +@noindent +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 +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 +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. + +You can prevent an @code{asm} instruction from being deleted, moved 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 + +@noindent +(However, an instruction without output operands will not be deleted +or moved, regardless, unless it is unreachable.) + +It is a natural idea to look for a way to give access to the condition +code left by the assembler instruction. However, when we attempted to +implement this, we found no way to make it work reliably. The problem +is that output operands might need reloading, which would result in +additional following ``store'' instructions. On most machines, these +instructions would alter the condition code before there was time to +test it. This problem doesn't arise for ordinary ``test'' and +``compare'' instructions because they don't have any output operands. + +If you are writing a header file that should be includable in ANSI C +programs, write @code{__asm__} instead of @code{asm}. @xref{Alternate +Keywords}. + +@node Asm Labels, Explicit Reg Vars, Extended Asm, Extensions +@section Controlling Names Used in Assembler Code + +You can specify the name to be used in the assembler code for a C +function or variable by writing the @code{asm} (or @code{__asm__}) +keyword after the declarator as follows: + +@example +int foo asm ("myfoo") = 2; +@end example + +@noindent +This specifies that the name to be used for the variable @code{foo} in +the assembler code should be @samp{myfoo} rather than the usual +@samp{_foo}. + +On systems where an underscore is normally prepended to the name of a C +function or variable, this feature allows you to define names for the +linker that do not start with an underscore. + +You cannot use @code{asm} in this way in a function @emph{definition}; but +you can get the same effect by writing a declaration for the function +before its definition and putting @code{asm} there, like this: + +@example +extern func () asm ("FUNC"); + +func (x, y) + int x, y; +@dots{} +@end example + +It is up to you to make sure that the assembler names you choose do not +conflict with any other assembler symbols. Also, you must not use a +register name; that would produce completely invalid assembler code. GNU +CC does not as yet have the ability to store static variables in registers. +Perhaps that will be added. + +@node Explicit Reg Vars, Alternate Keywords, Asm Labels, Extensions +@section Variables in Specified Registers + +GNU C allows you to put a few global variables into specified hardware +registers. You can also specify the register in which an ordinary +register variable should be allocated. + +@itemize @bullet +@item +Global register variables reserve registers throughout the program. +This may be useful in programs such as programming language +interpreters which have a couple of global variables that are accessed +very often. + +@item +Local register variables in specific registers do not reserve the +registers. The compiler's data flow analysis is capable of +determining where the specified registers contain live values, and +where they are available for other uses. These local variables are +sometimes convenient for use with the extended @code{asm} feature +(@pxref{Extended Asm}). +@end itemize + +@menu +* Global Reg Vars:: +* Local Reg Vars:: +@end menu + +@node Global Reg Vars, Local Reg Vars, Explicit Reg Vars, Explicit Reg Vars +@subsection Defining Global Register Variables + +You can define a global register variable in GNU C like this: + +@example +register int *foo asm ("a5"); +@end example + +@noindent +Here @code{a5} is the name of the register which should be used. Choose a +register which is normally saved and restored by function calls on your +machine, so that library routines will not clobber it. + +Naturally the register name is cpu-dependent, so you would need to +conditionalize your program according to cpu type. The register +@code{a5} would be a good choice on a 68000 for a variable of pointer +type. On machines with register windows, be sure to choose a ``global'' +register that is not affected magically by the function call mechanism. + +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 a global register variable in a certain register reserves that +register entirely for this use, at least within the current compilation. +The register will not be allocated for any other purpose in the functions +in the current compilation. The register will not be saved and restored by +these functions. Stores into this register are never deleted even if they +would appear to be dead, but references may be deleted or moved or +simplified. + +It is not safe to access the global register variables from signal +handlers, or from more than one thread of control, because the system +library routines may temporarily use the register for other things (unless +you recompile them specially for the task at hand). + +It is not safe for one function that uses a global register variable to +call another such function @code{foo} by way of a third function +@code{lose} that was compiled without knowledge of this variable (i.e. in a +different source file in which the variable wasn't declared). This is +because @code{lose} might save the register and put some other value there. +For example, you can't expect a global register variable to be available in +the comparison-function that you pass to @code{qsort}, since @code{qsort} +might have put something else in that register. (If you are prepared to +recompile @code{qsort} with the same global register variable, you can +solve this problem.) + +If you want to recompile @code{qsort} or other source files which do not +actually use your global register variable, so that they will not use that +register for any other purpose, then it suffices to specify the compiler +option @samp{-ffixed-@var{reg}}. You need not actually add a global +register declaration to their source code. + +A function which can alter the value of a global register variable cannot +safely be called from a function compiled without this variable, because it +could clobber the value the caller expects to find there on return. +Therefore, the function which is the entry point into the part of the +program that uses the global register variable must explicitly save and +restore the value which belongs to its caller. + +On most machines, @code{longjmp} will restore to each global register +variable the value it had at the time of the @code{setjmp}. On some +machines, however, @code{longjmp} will not change the value of global +register variables. To be portable, the function that called @code{setjmp} +should make other arrangements to save the values of the global register +variables, and to restore them in a @code{longjmp}. This way, the same +thing will happen regardless of what @code{longjmp} does. + +All global register variable declarations must precede all function +definitions. If such a declaration could appear after function +definitions, the declaration would be too late to prevent the register from +being used for other purposes in the preceding functions. + +Global register variables may not have initial values, because an +executable file has no means to supply initial contents for a register. + +@node Local Reg Vars,, Global Reg Vars, Explicit Reg Vars +@subsection Specifying Registers for Local Variables + +You can define a local register variable with a specified register +like this: + +@example +register int *foo asm ("a5"); +@end example + +@noindent +Here @code{a5} is the name of the register which should be used. Note +that this is the same syntax used for defining global register +variables, but for a local variable it would appear within a function. + +Naturally the register name is cpu-dependent, but this is not a +problem, since specific registers are most often useful with explicit +assembler instructions (@pxref{Extended Asm}). Both of these things +generally require that you conditionalize your program according to +cpu type. + +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. + +@node Alternate Keywords,, Explicit Reg Vars, Extensions +@section Alternate Keywords + +The option @samp{-traditional} disables certain keywords; @samp{-ansi} +disables certain others. This causes trouble when you want to use GNU C +extensions, or ANSI C features, in a general-purpose header file that +should be usable by all programs, including ANSI C programs and traditional +ones. The keywords @code{asm}, @code{typeof} and @code{inline} cannot be +used since they won't work in a program compiled with @samp{-ansi}, while +the keywords @code{const}, @code{volatile}, @code{signed}, @code{typeof} +and @code{inline} won't work in a program compiled with +@samp{-traditional}.@refill + +The way to solve these problems is to put @samp{__} at the beginning and +end of each problematical keyword. For example, use @code{__asm__} +instead of @code{asm}, @code{__const__} instead of @code{const}, and +@code{__inline__} instead of @code{inline}. + +Other C compilers won't accept these alternative keywords; if you want to +compile with another compiler, you can define the alternate keywords as +macros to replace them with the customary keywords. It looks like this: + +@example +#ifndef __GNUC__ +#define __asm__ asm +#endif +@end example + +@node Bugs, Portability, Extensions, Top +@chapter Reporting Bugs + +Your bug reports play an essential role in making GNU CC reliable. + +When you encounter a problem, the first thing to do is to see if it is +already known. @xref{Trouble}. Also look in @ref{Incompatibilities}. +If it isn't known, then you should report the problem. + +Reporting a bug may help you by bringing a solution to your problem, or +it may 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 CC +work better. Bug reports are your contribution to the maintenance of +GNU CC. + +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? +* Reporting: Bug Reporting. How to report a bug effectively. +@end menu + +@node Bug Criteria, Bug Reporting, Bugs, Bugs +@section Have You Found a Bug? + +If you are not sure whether you have found a bug, here are some guidelines: + +@itemize @bullet +@item +If the compiler gets a fatal signal, for any input whatever, that is a +compiler bug. Reliable compilers never crash. + +@item +If the compiler produces invalid assembly code, for any input whatever +(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. + +@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 may have run +into an incompatibility between GNU C and traditional C +(@pxref{Incompatibilities}). These incompatibilities might be considered +bugs, but they are inescapable consequences of valuable features. + +Or you may have a program whose behavior is undefined, which happened +by chance to give the desired results with another C compiler. + +For example, in many nonoptimizing compilers, you can write @samp{x;} +at the end of a function instead of @samp{return x;}, with the same +results. But the value of the function is undefined if @code{return} +is omitted; it is not a bug when GNU CC produces different results. + +Problems often result from expressions with two increment operators, +as in @code{f (*p++, *p++)}. Your previous compiler might have +interpreted that expression the way you intended; GNU CC might +interpret it another way. Neither compiler is wrong. The bug is +in your code. + +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. + +@item +If the compiler produces an error message for valid input, that is a +compiler bug. + +Note that the following is not valid input, and the error message for +it is not a bug: + +@example +int foo (char); + +int +foo (x) + char x; +@{ @dots{} @} +@end example + +@noindent +The prototype says to pass a @code{char}, while the definition says to +pass an @code{int} and treat the value as a @code{char}. This is what +the ANSI standard says, and it makes sense. + +@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 my idea of ``an extension'' or ``support +for traditional practice''. + +@item +If you are an experienced user of C compilers, your suggestions +for improvement of GNU CC are welcome in any case. +@end itemize + +@node Bug Reporting,, Bug Criteria, Bugs +@section How to Report Bugs + +Send bug reports for GNU C to one of these addresses: + +@example +bug-gcc@@prep.ai.mit.edu +@{ucbvax|mit-eddie|uunet@}!prep.ai.mit.edu!bug-gcc +@end example + +@strong{Do not send bug reports to @samp{help-gcc}, 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}. + +The mailing list @samp{bug-gcc} has a newsgroup which serves as a +repeater. The mailing list and the newsgroup carry exactly the same +messages. 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 crucial: a newsgroup posting does not contain a mail path +back to the sender. Thus, if I need to ask for more information, I +may be unable to reach you. For this reason, it is better to send bug +reports to the mailing list. + +As a last resort, send bug reports on paper to: + +@example +GNU Compiler Bugs +Free Software Foundation +675 Mass Ave +Cambridge, MA 02139 +@end example + +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 me 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?'' Those bug reports are useless, and I urge everyone to +@emph{refuse to respond to them} except to chide the sender to report +bugs properly. + +To enable me to fix the bug, you should include all these things: + +@itemize @bullet +@item +The version of GNU CC. You can get this by running it with the +@samp{-v} option. + +Without this, I won't know whether there is any point in looking for +the bug in the current version of GNU CC. + +@item +A complete input file that will reproduce the bug. If the bug is in +the C preprocessor, send me a source file and any header files that it +requires. If the bug is in the compiler proper (@file{cc1}), run your +source file through the C preprocessor by doing @samp{gcc -E +@var{sourcefile} > @var{outfile}}, then include the contents of +@var{outfile} in the bug report. (Any @samp{-I}, @samp{-D} or +@samp{-U} options that you used in actual compilation should also be +used when doing this.) + +A single statement is not enough of an example. In order to compile +it, it must be embedded in a function definition; and the bug might +depend on the details of how this is done. + +Without a real example I can compile, all I 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 +The command arguments you gave GNU CC to compile that example and +observe the bug. For example, did you use @samp{-O}? To guarantee +you won't omit something important, list them all. + +If I were to try to guess the arguments, I would probably guess wrong +and then I would not encounter the bug. + +@item +The names of the files that you used for @file{tm.h} and @file{md} +when you installed the compiler. + +@item +The type of machine you are using, and the operating system name and +version number. + +@item +A description of what behavior you observe that you believe is +incorrect. For example, ``It gets a fatal signal,'' or, ``There is an +incorrect assembler instruction in the output.'' + +Of course, if the bug is that the compiler gets a fatal signal, then I +will certainly notice it. But if the bug is incorrect output, I might +not notice unless it is glaringly wrong. I won't study all the +assembler code from a 50-line C program just on the off chance that it +might be wrong. + +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 mine would not. If you @i{told} me to expect a crash, +then when mine fails to crash, I would know that the bug was not +happening for me. If you had not told me to expect a crash, then I +would not be able to draw any conclusion from my observations. + +Often the observed symptom is incorrect output when your program is run. +Sad to say, this is not enough information for me unless the program is +short and simple. If you send me a large program, I don't have time 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 me which +source line it is, and what incorrect result happens when that line is +executed. A person who understands the test program can find this as +easily as a bug in the program itself. + +@item +If you send me examples of output from GNU CC, 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 suggest changes to the GNU CC source, send me context +diffs. If you even discuss something in the GNU CC source, refer to +it by context, not by line number. + +The line numbers in my development sources don't match those in your +sources. Your line numbers would convey no useful information to me. + +@item +Additional information from a debugger might enable me to find +a problem on a machine which I do not have available myself. +However, you need to think when you collect this information if +you want it to have any chance of being useful. + +For example, many people send just a backtrace, but that is never +useful by itself. A simple backtrace with arguments conveys little +about GNU CC 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. + +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. + +In addition, include a debugging dump from just before the pass +in which the crash happens. Most bugs involve a series of insns, +not just one. +@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 I +will find the bug is by running a single example under the debugger +with breakpoints, not by pure deduction from a series of examples. +I recommend that you 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 for me. Errors in the +output will be easier to spot, running under the debugger will take +less time, etc. Most GNU CC 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 may +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 me the entire test case you used. + +@item +A patch for the bug. + +A patch for the bug does help me 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 I need. I might see problems with your patch and decide +to fix the problem another way, or I might not understand it at all. + +Sometimes with a program as complicated as GNU CC 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 me the example, I won't be able +to construct one, so I won't be able to verify that the bug is fixed. + +And if I can't understand what bug you are trying to fix, or why your +patch should be an improvement, I won't install it. A test case will +help me to understand. + +@item +A guess about what the bug is or what it depends on. + +Such guesses are usually wrong. Even I can't guess right about such +things without first using the debugger to find the facts. +@end itemize + +@node Portability, Interface, Bugs, Top +@chapter GNU CC and Portability + +The main goal of GNU CC was to make a good, fast compiler for machines in +the class that the GNU system aims to run on: 32-bit machines that address +8-bit bytes and have several general registers. Elegance, theoretical +power and simplicity are only secondary. + +GNU CC gets most of the information about the target machine from a machine +description which gives an algebraic formula for each of the machine's +instructions. This is a very clean way to describe the target. But when +the compiler needs information that is difficult to express in this +fashion, I have not hesitated to define an ad-hoc parameter to the machine +description. The purpose of portability is to reduce the total work needed +on the compiler; it was not of interest for its own sake. + +GNU CC does not contain machine dependent code, but it does contain code +that depends on machine parameters such as endianness (whether the most +significant byte has the highest or lowest address of the bytes in a word) +and the availability of autoincrement addressing. In the RTL-generation +pass, it is often necessary to have multiple strategies for generating code +for a particular kind of syntax tree, strategies that are usable for different +combinations of parameters. Often I have not tried to address all possible +cases, but only the common ones or only the ones that I have encountered. +As a result, a new target may require additional strategies. You will know +if this happens because the compiler will call @code{abort}. Fortunately, +the new strategies can be added in a machine-independent fashion, and will +affect only the target machines that need them. + +@node Interface, Passes, Portability, Top +@chapter Interfacing to GNU CC Output + +GNU CC is normally configured to use the same function calling convention +normally in use on the target system. This is done with the +machine-description macros described (@pxref{Machine Macros}). + +However, returning of structure and union values is done differently on +some target machines. As a result, functions compiled with PCC +returning such types cannot be called from code compiled with GNU CC, +and vice versa. This does not cause trouble often because few Unix +library routines return structures or unions. + +GNU CC code returns structures and unions that are 1, 2, 4 or 8 bytes +long in the same registers used for @code{int} or @code{double} return +values. (GNU CC typically allocates variables of such types in +registers also.) Structures and unions of other sizes are returned by +storing them into an address passed by the caller (usually in a +register). The machine-description macros @code{STRUCT_VALUE} and +@code{STRUCT_INCOMING_VALUE} tell GNU CC where to pass this address. + +By contrast, PCC on most target machines returns structures and unions +of any size by copying the data into an area of static storage, and then +returning the address of that storage as if it were a pointer value. +The caller must copy the data from that memory area to the place where +the value is wanted. This is slower than the method used by GNU CC, and +fails to be reentrant. + +On some target machines, such as RISC machines and the 80386, the +standard system convention is to pass to the subroutine the address of +where to return the value. On these machines, GNU CC has been +configured to be compatible with the standard compiler, when this method +is used. It may not be compatible for structures of 1, 2, 4 or 8 bytes. + +GNU CC uses the system's standard convention for passing arguments. On +some machines, the first few arguments are passed in registers; in +others, all are passed on the stack. It would be possible to use +registers for argument passing on any machine, and this would probably +result in a significant speedup. But the result would be complete +incompatibility with code that follows the standard convention. So this +change is practical only if you are switching to GNU CC as the sole C +compiler for the system. We may implement register argument passing on +certain machines once we have a complete GNU system so that we can +compile the libraries with GNU CC. + +If you use @code{longjmp}, beware of automatic variables. ANSI C says that +automatic variables that are not declared @code{volatile} have undefined +values after a @code{longjmp}. And this is all GNU CC promises to do, +because it is very difficult to restore register variables correctly, and +one of GNU CC's features is that it can put variables in registers without +your asking it to. + +If you want a variable to be unaltered by @code{longjmp}, and you don't +want to write @code{volatile} because old C compilers don't accept it, +just take the address of the variable. If a variable's address is ever +taken, even if just to compute it and ignore it, then the variable cannot +go in a register: + +@example +@{ + int careful; + &careful; + @dots{} +@} +@end example + +Code compiled with GNU CC may call certain library routines. Most of +them handle arithmetic for which there are no instructions. This +includes multiply and divide on some machines, and floating point +operations on any machine for which floating point support is disabled +with @samp{-msoft-float}. Some standard parts of the C library, such as +@code{bcopy} or @code{memcpy}, are also called automatically. The usual +function call interface is used for calling the library routines. + +These library routines should be defined in the library @file{gnulib}, +which GNU CC automatically searches whenever it links a program. On +machines that have multiply and divide instructions, if hardware +floating point is in use, normally @file{gnulib} is not needed, but it +is searched just in case. + +Each arithmetic function is defined in @file{gnulib.c} to use the +corresponding C arithmetic operator. As long as the file is compiled +with another C compiler, which supports all the C arithmetic operators, +this file will work portably. However, @file{gnulib.c} does not work if +compiled with GNU CC, because each arithmetic function would compile +into a call to itself! + +@node Passes, RTL, Interface, Top +@chapter Passes and Files of the Compiler + +The overall control structure of the compiler is in @file{toplev.c}. This +file is responsible for initialization, decoding arguments, opening and +closing files, and sequencing the passes. + +The parsing pass is invoked only once, to parse the entire input. The RTL +intermediate code for a function is generated as the function is parsed, a +statement at a time. Each statement is read in as a syntax tree and then +converted to RTL; then the storage for the tree for the statement is +reclaimed. Storage for types (and the expressions for their sizes), +declarations, and a representation of the binding contours and how they nest, +remains until the function is finished being compiled; these are all needed +to output the debugging information. + +Each time the parsing pass reads a complete function definition or +top-level declaration, it calls the function +@code{rest_of_compilation} or @code{rest_of_decl_compilation} in +@file{toplev.c}, which are responsible for all further processing +necessary, ending with output of the assembler language. All other +compiler passes run, in sequence, within @code{rest_of_compilation}. +When that function returns from compiling a function definition, the +storage used for that function definition's compilation is entirely +freed, unless it is an inline function (@pxref{Inline}). + +Here is a list of all the passes of the compiler and their source files. +Also included is a description of where debugging dumps can be requested +with @samp{-d} options. + +@itemize @bullet +@item +Parsing. This pass reads the entire text of a function definition, +constructing partial syntax trees. This and RTL generation are no longer +truly separate passes (formerly they were), but it is easier to think +of them as separate. + +The tree representation does not entirely follow C syntax, because it is +intended to support other languages as well. + +C data type analysis is also done in this pass, and every tree node +that represents an expression has a data type attached. Variables are +represented as declaration nodes. + +Constant folding and associative-law simplifications are also done +during this pass. + +The source files for parsing are @file{c-parse.y}, @file{c-decl.c}, +@file{c-typeck.c}, @file{c-convert.c}, @file{stor-layout.c}, +@file{fold-const.c}, and @file{tree.c}. The last three files are +intended to be language-independent. There are also header files +@file{c-parse.h}, @file{c-tree.h}, @file{tree.h} and @file{tree.def}. +The last two define the format of the tree representation.@refill + +@item +RTL generation. This is the conversion of syntax tree into RTL code. +It is actually done statement-by-statement during parsing, but for +most purposes it can be thought of as a separate pass. + +This is where the bulk of target-parameter-dependent code is found, +since often it is necessary for strategies to apply only when certain +standard kinds of instructions are available. The purpose of named +instruction patterns is to provide this information to the RTL +generation pass. + +Optimization is done in this pass for @code{if}-conditions that are +comparisons, boolean operations or conditional expressions. Tail +recursion is detected at this time also. Decisions are made about how +best to arrange loops and how to output @code{switch} statements. + +The source files for RTL generation are @file{stmt.c}, @file{expr.c}, +@file{explow.c}, @file{expmed.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 files +@file{expr.h} is used for communication within this pass.@refill + +The header files @file{insn-flags.h} and @file{insn-codes.h}, +generated from the machine description by the programs @code{genflags} +and @code{gencodes}, tell this pass which standard names are available +for use and which patterns correspond to them.@refill + +Aside from debugging information output, none of the following passes +refers to the tree structure representation of the function (only +part of which is saved). + +The decision of whether the function can and should be expanded inline +in its subsequent callers is made at the end of rtl generation. The +function must meet certain criteria, currently related to the size of +the function and the types and number of parameters it has. Note that +this function may contain loops, recursive calls to itself +(tail-recursive functions can be inlined!), gotos, in short, all +constructs supported by GNU CC. + +The option @samp{-dr} causes a debugging dump of the RTL code after +this pass. This dump file's name is made by appending @samp{.rtl} to +the input file name. + +@item +Jump optimization. This pass simplifies jumps to the following +instruction, jumps across jumps, and jumps to jumps. It deletes +unreferenced labels and unreachable code, except that unreachable code +that contains a loop is not recognized as unreachable in this pass. +(Such loops are deleted later in the basic block analysis.) + +Jump optimization is performed two or three times. The first time is +immediately following RTL generation. The second time is after CSE, +but only if CSE says repeated jump optimization is needed. The +last time is right before the final pass. That time, cross-jumping +and deletion of no-op move instructions are done together with the +optimizations described above. + +The source file of this pass is @file{jump.c}. + +The option @samp{-dj} causes a debugging dump of the RTL code after +this pass is run for the first time. This dump file's name is made by +appending @samp{.jump} to the input file name. + +@item +Register scan. This pass finds the first and last use of each +register, as a guide for common subexpression elimination. Its source +is in @file{regclass.c}. + +@item +Common subexpression elimination. This pass also does constant +propagation. Its source file is @file{cse.c}. If constant +propagation causes conditional jumps to become unconditional or to +become no-ops, jump optimization is run again when CSE is finished. + +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. + +@item +Loop optimization. This pass moves constant expressions out of loops, +and optionally does strength-reduction as well. Its source file is +@file{loop.c}. + +The option @samp{-dL} causes a debugging dump of the RTL code after +this pass. This dump file's name is made by appending @samp{.loop} to +the input file name. + +@item +Stupid register allocation is performed at this point in a +nonoptimizing compilation. It does a little data flow analysis as +well. When stupid register allocation is in use, the next pass +executed is the reloading pass; the others in between are skipped. +The source file is @file{stupid.c}. + +@item +Data flow analysis (@file{flow.c}). This pass divides the program +into basic blocks (and in the process deletes unreachable loops); then +it computes which pseudo-registers are live at each point in the +program, and makes the first instruction that uses a value point at +the instruction that computed the value. + +This pass also deletes computations whose results are never used, and +combines memory references with add or subtract instructions to make +autoincrement or autodecrement addressing. + +The option @samp{-df} causes a debugging dump of the RTL code after +this pass. This dump file's name is made by appending @samp{.flow} to +the input file name. If stupid register allocation is in use, this +dump file reflects the full results of such allocation. + +@item +Instruction combination (@file{combine.c}). This pass attempts to +combine groups of two or three instructions that are related by data +flow into single instructions. It combines the RTL expressions for +the instructions by substitution, simplifies the result using algebra, +and then attempts to match the result against the machine description. + +The option @samp{-dc} causes a debugging dump of the RTL code after +this pass. This dump file's name is made by appending @samp{.combine} +to the input file name. + +@item +Register class preferencing. The RTL code is scanned to find out +which register class is best for each pseudo register. The source +file is @file{regclass.c}. + +@item +Local register allocation (@file{local-alloc.c}). This pass allocates +hard registers to pseudo registers that are used only within one basic +block. Because the basic block is linear, it can use fast and +powerful techniques to do a very good job. + +The option @samp{-dl} causes a debugging dump of the RTL code after +this pass. This dump file's name is made by appending @samp{.lreg} to +the input file name. + +@item +Global register allocation (@file{global-alloc.c}). This pass +allocates hard registers for the remaining pseudo registers (those +whose life spans are not contained in one basic block). + +@item +Reloading. This pass renumbers pseudo registers with the hardware +registers numbers they were allocated. Pseudo registers that did not +get hard registers are replaced with stack slots. Then it finds +instructions that are invalid because a value has failed to end up in +a register, or has ended up in a register of the wrong kind. It fixes +up these instructions by reloading the problematical values +temporarily into registers. Additional instructions are generated to +do the copying. + +Source files are @file{reload.c} and @file{reload1.c}, plus the header +@file{reload.h} used for communication between them. + +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{.greg} to +the input file name. + +@item +Jump optimization is repeated, this time including cross-jumping +and deletion of no-op move instructions. + +The option @samp{-dJ} causes a debugging dump of the RTL code after +this pass. This dump file's name is made by appending @samp{.jump2} +to the input file name. + +@item +Delayed branch scheduling may be done at this point. The source file +name is @file{dbranch.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} +to the input file name. + +@item +Final. This pass outputs the assembler code for the function. It is +also responsible for identifying spurious test and compare +instructions. Machine-specific peephole optimizations are performed +at the same time. The function entry and exit sequences are generated +directly as assembler code in this pass; they never exist as RTL. + +The source files are @file{final.c} plus @file{insn-output.c}; the +latter is generated automatically from the machine description by the +tool @file{genoutput}. The header file @file{conditions.h} is used +for communication between these files. + +@item +Debugging information output. This is run after final because it must +output the stack slot offsets for pseudo registers that did not get +hard registers. Source files are @file{dbxout.c} for DBX symbol table +format and @file{symout.c} for GDB's own symbol table format. +@end itemize + +Some additional files are used by all or many passes: + +@itemize @bullet +@item +Every pass uses @file{machmode.def}, which defines the machine modes. + +@item +All the passes that work with RTL use the header files @file{rtl.h} +and @file{rtl.def}, and subroutines in file @file{rtl.c}. The tools +@code{gen*} also use these files to read and work with the machine +description RTL. + +@item +Several passes refer to the header file @file{insn-config.h} which +contains a few parameters (C macro definitions) generated +automatically from the machine description RTL by the tool +@code{genconfig}. + +@item +Several passes use the instruction recognizer, which consists of +@file{recog.c} and @file{recog.h}, plus the files @file{insn-recog.c} +and @file{insn-extract.c} that are generated automatically from the +machine description by the tools @file{genrecog} and +@file{genextract}.@refill + +@item +Several passes use the header files @file{regs.h} which defines the +information recorded about pseudo register usage, and @file{basic-block.h} +which defines the information recorded about basic blocks. + +@item +@file{hard-reg-set.h} defines the type @code{HARD_REG_SET}, a bit-vector +with a bit for each hard register, and some macros to manipulate it. +This type is just @code{int} if the machine has few enough hard registers; +otherwise it is an array of @code{int} and some of the macros expand +into loops. +@end itemize + +@node RTL, Machine Desc, Passes, Top +@chapter RTL Representation + +Most of the work of the compiler is done on an intermediate representation +called register transfer language. In this language, the instructions to be +output are described, pretty much one by one, in an algebraic form that +describes what the instruction does. + +RTL is inspired by Lisp lists. It has both an internal form, made up of +structures that point at other structures, and a textual form that is used +in the machine description and in printed debugging dumps. The textual +form uses nested parentheses to indicate the pointers in the internal form. + +@menu +* RTL Objects:: Expressions vs vectors vs strings vs integers. +* Accessors:: Macros to access expression operands or vector elts. +* Flags:: Other flags in an RTL expression. +* Machine Modes:: Describing the size and format of a datum. +* Constants:: Expressions with constant values. +* Regs and Memory:: Expressions representing register contents or memory. +* Arithmetic:: Expressions representing arithmetic on other expressions. +* Comparisons:: Expressions representing comparison of expressions. +* Bit Fields:: Expressions representing bit-fields in memory or reg. +* Conversions:: Extending, truncating, floating or fixing. +* RTL Declarations:: Declaring volatility, constancy, etc. +* Side Effects:: Expressions for storing in registers, etc. +* Incdec:: Embedded side-effects for autoincrement addressing. +* Assembler:: Representing @code{asm} with operands. +* Insns:: Expression types for entire insns. +* Calls:: RTL representation of function call insns. +* Sharing:: Some expressions are unique; others *must* be copied. +@end menu + +@node RTL Objects, Accessors, RTL, RTL +@section RTL Object Types + +RTL uses four kinds of objects: expressions, integers, strings and vectors. +Expressions are the most important ones. An RTL expression (``RTX'', for +short) is a C structure, but it is usually referred to with a pointer; a +type that is given the typedef name @code{rtx}. + +An integer is simply an @code{int}, and a string is a @code{char *}. +Within RTL code, strings appear only inside @code{symbol_ref} expressions, +but they appear in other contexts in the RTL expressions that make up +machine descriptions. Their written form uses decimal digits. + +A string is a sequence of characters. In core it is represented as a +@code{char *} in usual C fashion, and it is written in C syntax as well. +However, strings in RTL may never be null. If you write an empty string in +a machine description, it is represented in core as a null pointer rather +than as a pointer to a null character. In certain contexts, these null +pointers instead of strings are valid. + +A vector contains an arbitrary, specified number of pointers to +expressions. The number of elements in the vector is explicitly present in +the vector. The written form of a vector consists of square brackets +(@samp{[@dots{}]}) surrounding the elements, in sequence and with +whitespace separating them. Vectors of length zero are not created; null +pointers are used instead. + +Expressions are classified by @dfn{expression codes} (also called RTX +codes). The expression code is a name defined in @file{rtl.def}, which is +also (in upper case) a C enumeration constant. The possible expression +codes and their meanings are machine-independent. The code of an RTX can +be extracted with the macro @code{GET_CODE (@var{x})} and altered with +@code{PUT_CODE (@var{x}, @var{newcode})}. + +The expression code determines how many operands the expression contains, +and what kinds of objects they are. In RTL, unlike Lisp, you cannot tell +by looking at an operand what kind of object it is. Instead, you must know +from its context---from the expression code of the containing expression. +For example, in an expression of code @code{subreg}, the first operand is +to be regarded as an expression and the second operand as an integer. In +an expression of code @code{plus}, there are two operands, both of which +are to be regarded as expressions. In a @code{symbol_ref} expression, +there is one operand, which is to be regarded as a string. + +Expressions are written as parentheses containing the name of the +expression type, its flags and machine mode if any, and then the operands +of the expression (separated by spaces). + +Expression code names in the @samp{md} file are written in lower case, +but when they appear in C code they are written in upper case. In this +manual, they are shown as follows: @code{const_int}. + +In a few contexts a null pointer is valid where an expression is normally +wanted. The written form of this is @code{(nil)}. + +@node Accessors, Flags, RTL Objects, RTL +@section Access to Operands + +For each expression type @file{rtl.def} specifies the number of contained +objects and their kinds, with four possibilities: @samp{e} for expression +(actually a pointer to an expression), @samp{i} for integer, @samp{s} for +string, and @samp{E} for vector of expressions. The sequence of letters +for an expression code is called its @dfn{format}. Thus, the format of +@code{subreg} is @samp{ei}.@refill + +Two other format characters are used occasionally: @samp{u} and @samp{0}. +@samp{u} is equivalent to @samp{e} except that it is printed differently in +debugging dumps, and @samp{0} means a slot whose contents do not fit any +normal category. @samp{0} slots are not printed at all in dumps, and are +often used in special ways by small parts of the compiler.@refill + +There are macros to get the number of operands and the format of an +expression code: + +@table @code +@item GET_RTX_LENGTH (@var{code}) +Number of operands of an RTX of code @var{code}. + +@item GET_RTX_FORMAT (@var{code}) +The format of an RTX of code @var{code}, as a C string. +@end table + +Operands of expressions are accessed using the macros @code{XEXP}, +@code{XINT} and @code{XSTR}. Each of these macros takes two arguments: an +expression-pointer (RTX) and an operand number (counting from zero). +Thus,@refill + +@example +XEXP (@var{x}, 2) +@end example + +@noindent +accesses operand 2 of expression @var{x}, as an expression. + +@example +XINT (@var{x}, 2) +@end example + +@noindent +accesses the same operand as an integer. @code{XSTR}, used in the same +fashion, would access it as a string. + +Any operand can be accessed as an integer, as an expression or as a string. +You must choose the correct method of access for the kind of value actually +stored in the operand. You would do this based on the expression code of +the containing expression. That is also how you would know how many +operands there are. + +For example, if @var{x} is a @code{subreg} expression, you know that it has +two operands which can be correctly accessed as @code{XEXP (@var{x}, 0)} +and @code{XINT (@var{x}, 1)}. If you did @code{XINT (@var{x}, 0)}, you +would get the address of the expression operand but cast as an integer; +that might occasionally be useful, but it would be cleaner to write +@code{(int) XEXP (@var{x}, 0)}. @code{XEXP (@var{x}, 1)} would also +compile without error, and would return the second, integer operand cast as +an expression pointer, which would probably result in a crash when +accessed. Nothing stops you from writing @code{XEXP (@var{x}, 28)} either, +but this will access memory past the end of the expression with +unpredictable results.@refill + +Access to operands which are vectors is more complicated. You can use the +macro @code{XVEC} to get the vector-pointer itself, or the macros +@code{XVECEXP} and @code{XVECLEN} to access the elements and length of a +vector. + +@table @code +@item XVEC (@var{exp}, @var{idx}) +Access the vector-pointer which is operand number @var{idx} in @var{exp}. + +@item XVECLEN (@var{exp}, @var{idx}) +Access the length (number of elements) in the vector which is +in operand number @var{idx} in @var{exp}. This value is an @code{int}. + +@item XVECEXP (@var{exp}, @var{idx}, @var{eltnum}) +Access element number @var{eltnum} in the vector which is +in operand number @var{idx} in @var{exp}. This value is an RTX. + +It is up to you to make sure that @var{eltnum} is not negative +and is less than @code{XVECLEN (@var{exp}, @var{idx})}. +@end table + +All the macros defined in this section expand into lvalues and therefore +can be used to assign the operands, lengths and vector elements as well as +to access them. + +@node Flags, Machine Modes, Accessors, RTL +@section Flags in an RTL Expression + +RTL expressions contain several flags (one-bit bit-fields) that are used +in certain types of expression. Most often they are accessed with the +following macros: + +@table @code +@item EXTERNAL_SYMBOL_P (@var{x}) +In a @code{symbol_ref} expression, nonzero if it corresponds to a variable +declared extern in the users code. Zero for all other variables. Stored in +the @code{volatil} field and printed as @samp{/v}. + +@item MEM_VOLATILE_P (@var{x}) +In @code{mem} expressions, nonzero for volatile memory references. +Stored in the @code{volatil} field and printed as @samp{/v}. + +@item MEM_IN_STRUCT_P (@var{x}) +In @code{mem} expressions, nonzero for reference to an entire +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}. + +@item REG_USER_VAR_P (@var{x}) +In a @code{reg}, nonzero if it corresponds to a variable present in +the user's source code. Zero for temporaries generated internally by +the compiler. Stored in the @code{volatil} field and printed as +@samp{/v}. + +@item REG_FUNCTION_VALUE_P (@var{x}) +Nonzero in a @code{reg} if it is the place in which this function's +value is going to be returned. (This happens only in a hard +register.) Stored in the @code{integrated} field and printed as +@samp{/i}. + +The same hard register may be used also for collecting the values of +functions called by this one, but @code{REG_FUNCTION_VALUE_P} is zero +in this kind of use. + +@item RTX_UNCHANGING_P (@var{x}) +Nonzero in a @code{reg} or @code{mem} if the value is not changed +explicitly by the current function. (If it is a memory reference then +it may be changed by other functions or by aliasing.) Stored in the +@code{unchanging} field and printed as @samp{/u}. + +@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. + +@item INSN_DELETED_P (@var{insn}) +In an insn, nonzero if the insn has been deleted. Stored in the +@code{volatil} field and printed as @samp{/v}. + +@item CONSTANT_POOL_ADDRESS_P (@var{x}) +Nonzero in a @code{symbol_ref} if it refers to part of the current +function's ``constants pool''. These are addresses close to the +beginning of the function, and GNU CC assumes they can be addressed +directly (perhaps with the help of base registers). Stored in the +@code{unchanging} field and printed as @samp{/u}. +@end table + +These are the fields which the above macros refer to: + +@table @code +@item used +This flag is used only momentarily, at the end of RTL generation for a +function, to count the number of times an expression appears in insns. +Expressions that appear more than once are copied, according to the +rules for shared structure (@pxref{Sharing}). + +@item volatil +This flag is used in @code{mem},@code{symbol_ref} and @code{reg} expressions +and in insns. In RTL dump files, it is printed as @samp{/v}. + +In a @code{mem} expression, it is 1 if the memory reference is volatile. +Volatile memory references may not be deleted, reordered or combined. + +In a @code{reg} expression, it is 1 if the value is a user-level variable. +0 indicates an internal compiler temporary. + +In a @code{symbol_ref} expression, it is 1 if the symbol is declared +@code{extern}. + +In an insn, 1 means the insn has been deleted. + +@item in_struct +This flag is used in @code{mem} expressions. It is 1 if the memory +datum referred to is all or part of a structure or array; 0 if it is (or +might be) a scalar variable. A reference through a C pointer has 0 +because the pointer might point to a scalar variable. + +This information allows the compiler to determine something about possible +cases of aliasing. + +In an RTL dump, this flag is represented as @samp{/s}. + +@item unchanging +This flag is used in @code{reg} and @code{mem} expressions. 1 means +that the value of the expression never changes (at least within the +current function). + +In an RTL dump, this flag is represented as @samp{/u}. + +@item integrated +In some kinds of expressions, including insns, this flag means the +rtl was produced by procedure integration. + +In a @code{reg} expression, this flag indicates the register +containing the value to be returned by the current function. On +machines that pass parameters in registers, the same register number +may be used for parameters as well, but this flag is not set on such +uses. +@end table + +@node Machine Modes, Constants, Flags, RTL +@section Machine Modes + +A machine mode describes a size of data object and the representation used +for it. In the C code, machine modes are represented by an enumeration +type, @code{enum machine_mode}, defined in @file{machmode.def}. Each RTL +expression has room for a machine mode and so do certain kinds of tree +expressions (declarations and types, to be precise). + +In debugging dumps and machine descriptions, the machine mode of an RTL +expression is written after the expression code with a colon to separate +them. The letters @samp{mode} which appear at the end of each machine mode +name are omitted. For example, @code{(reg:SI 38)} is a @code{reg} +expression with machine mode @code{SImode}. If the mode is +@code{VOIDmode}, it is not written at all. + +Here is a table of machine modes. + +@table @code +@item QImode +``Quarter-Integer'' mode represents a single byte treated as an integer. + +@item HImode +``Half-Integer'' mode represents a two-byte integer. + +@item PSImode +``Partial Single Integer'' mode represents an integer which occupies +four bytes but which doesn't really use all four. On some machines, +this is the right mode to use for pointers. + +@item SImode +``Single Integer'' mode represents a four-byte integer. + +@item PDImode +``Partial Double Integer'' mode represents an integer which occupies +eight bytes but which doesn't really use all eight. On some machines, +this is the right mode to use for certain pointers. + +@item DImode +``Double Integer'' mode represents an eight-byte integer. + +@item TImode +``Tetra Integer'' (?) mode represents a sixteen-byte integer. + +@item SFmode +``Single Floating'' mode represents a single-precision (four byte) floating +point number. + +@item DFmode +``Double Floating'' mode represents a double-precision (eight byte) floating +point number. + +@item XFmode +``Extended Floating'' mode represents a triple-precision (twelve byte) +floating point number. This mode is used for IEEE extended floating +point. + +@item TFmode +``Tetra Floating'' mode represents a quadruple-precision (sixteen byte) +floating point number. + +@item BLKmode +``Block'' mode represents values that are aggregates to which none of +the other modes apply. In RTL, only memory references can have this mode, +and only if they appear in string-move or vector instructions. On machines +which have no such instructions, @code{BLKmode} will not appear in RTL. + +@item VOIDmode +Void mode means the absence of a mode or an unspecified mode. +For example, RTL expressions of code @code{const_int} have mode +@code{VOIDmode} because they can be taken to have whatever mode the context +requires. In debugging dumps of RTL, @code{VOIDmode} is expressed by +the absence of any mode. + +@item EPmode +``Entry Pointer'' mode is intended to be used for function variables in +Pascal and other block structured languages. Such values contain +both a function address and a static chain pointer for access to +automatic variables of outer levels. This mode is only partially +implemented since C does not use it. + +@item CSImode@r{, @dots{}} +``Complex Single Integer'' mode stands for a complex number represented +as a pair of @code{SImode} integers. Any of the integer and floating modes +may have @samp{C} prefixed to its name to obtain a complex number mode. +For example, there are @code{CQImode}, @code{CSFmode}, and @code{CDFmode}. +Since C does not support complex numbers, these machine modes are only +partially implemented. + +@item BImode +This is the machine mode of a bit-field in a structure. It is used +only in the syntax tree, never in RTL, and in the syntax tree it appears +only in declaration nodes. In C, it appears only in @code{FIELD_DECL} +nodes for structure fields defined with a bit size. +@end table + +The machine description defines @code{Pmode} as a C macro which expands +into the machine mode used for addresses. Normally this is @code{SImode}. + +The only modes which a machine description @i{must} support are +@code{QImode}, @code{SImode}, @code{SFmode} and @code{DFmode}. The +compiler will attempt to use @code{DImode} for two-word structures and +unions, but this can be prevented by overriding the definition of +@code{MAX_FIXED_MODE_SIZE}. Likewise, you can arrange for the C type +@code{short int} to avoid using @code{HImode}. In the long term it +might be desirable to make the set of available machine modes +machine-dependent and eliminate all assumptions about specific machine +modes or their uses from the machine-independent code of the compiler. + +To help begin this process, the machine modes are divided into mode +classes. These are represented by the enumeration type @code{enum +mode_class} defined in @file{rtl.h}. The possible mode classes are: + +@table @code +@item MODE_INT +Integer modes. By default these are @code{QImode}, @code{HImode}, +@code{SImode}, @code{DImode}, @code{TImode}, and also @code{BImode}. + +@item MODE_FLOAT +Floating-point modes. By default these are @code{QFmode}, +@code{HFmode}, @code{SFmode}, @code{DFmode} and @code{TFmode}, but the +MC68881 also defines @code{XFmode} to be an 80-bit extended-precision +floating-point mode. + +@item MODE_COMPLEX_INT +Complex integer modes. By default these are @code{CQImode}, +@code{CHImode}, @code{CSImode}, @code{CDImode} and @code{CTImode}. + +@item MODE_COMPLEX_FLOAT +Complex floating-point modes. By default these are @code{CQFmode}, +@code{CHFmode}, @code{CSFmode}, @code{CDFmode} and @code{CTFmode}, + +@item MODE_FUNCTION +Algol or Pascal function variables including a static chain. +(These are not currently implemented). + +@item MODE_RANDOM +This is a catchall mode class for modes which don't fit into the above +classes. Currently @code{VOIDmode}, @code{BLKmode} and @code{EPmode} +are in @code{MODE_RANDOM}. +@end table + +Here are some C macros that relate to machine modes: + +@table @code +@item GET_MODE (@var{x}) +Returns the machine mode of the RTX @var{x}. + +@item PUT_MODE (@var{x}, @var{newmode}) +Alters the machine mode of the RTX @var{x} to be @var{newmode}. + +@item NUM_MACHINE_MODES +Stands for the number of machine modes available on the target +machine. This is one greater than the largest numeric value of any +machine mode. + +@item GET_MODE_NAME (@var{m}) +Returns the name of mode @var{m} as a string. + +@item GET_MODE_CLASS (@var{m}) +Returns the mode class of mode @var{m}. + +@item GET_MODE_SIZE (@var{m}) +Returns the size in bytes of a datum of mode @var{m}. + +@item GET_MODE_BITSIZE (@var{m}) +Returns the size in bits of a datum of mode @var{m}. + +@item GET_MODE_UNIT_SIZE (@var{m}) +Returns the size in bits of the subunits of a datum of mode @var{m}. +This is the same as @code{GET_MODE_SIZE} except in the case of +complex modes and @code{EPmode}. For them, the unit size is the +size of the real or imaginary part, or the size of the function +pointer or the context pointer. +@end table + +@node Constants, Regs and Memory, Machine Modes, RTL +@section Constant Expression Types + +The simplest RTL expressions are those that represent constant values. + +@table @code +@item (const_int @var{i}) +This type of expression represents the integer value @var{i}. @var{i} +is customarily accessed with the macro @code{INTVAL} as in +@code{INTVAL (@var{exp})}, which is equivalent to @code{XINT (@var{exp}, 0)}. + +There is only one expression object for the integer value zero; +it is the value of the variable @code{const0_rtx}. Likewise, the +only expression for integer value one is found in @code{const1_rtx}. +Any attempt to create an expression of code @code{const_int} and +value zero or one will return @code{const0_rtx} or @code{const1_rtx} +as appropriate. + +@item (const_double:@var{m} @var{i0} @var{i1}) +Represents a 64-bit constant of mode @var{m}. All floating point +constants are represented in this way, and so are 64-bit @code{DImode} +integer constants. + +The two integers @var{i0} and @var{i1} together contain the bits of +the value. If the constant is floating point (either single or double +precision), then they represent a @code{double}. To convert them to a +@code{double}, do + +@example +union @{ double d; int i[2];@} u; +u.i[0] = CONST_DOUBLE_LOW(x); +u.i[1] = CONST_DOUBLE_HIGH(x); +@end example + +@noindent +and then refer to @code{u.d}. + +The global variables @code{dconst0_rtx} and @code{fconst0_rtx} hold +@code{const_double} expressions with value 0, in modes @code{DFmode} +and @code{SFmode}, respectively. The macro @code{CONST0_RTX +(@var{mode})} refers to a @code{const_double} expression with value 0 +in mode @var{mode}. The mode @var{mode} must be of mode class +@code{MODE_FLOAT}. + +@item (symbol_ref @var{symbol}) +Represents the value of an assembler label for data. @var{symbol} is +a string that describes the name of the assembler label. If it starts +with a @samp{*}, the label is the rest of @var{symbol} not including +the @samp{*}. Otherwise, the label is @var{symbol}, prefixed with +@samp{_}. + +@item (label_ref @var{label}) +Represents the value of an assembler label for code. It contains one +operand, an expression, which must be a @code{code_label} that appears +in the instruction sequence to identify the place where the label +should go. + +The reason for using a distinct expression type for code label +references is so that jump optimization can distinguish them. + +@item (const @var{exp}) +Represents a constant that is the result of an assembly-time +arithmetic computation. The operand, @var{exp}, is an expression that +contains only constants (@code{const_int}, @code{symbol_ref} and +@code{label_ref} expressions) combined with @code{plus} and +@code{minus}. However, not all combinations are valid, since the +assembler cannot do arbitrary arithmetic on relocatable symbols. +@end table + +@node Regs and Memory, Arithmetic, Constants, RTL +@section Registers and Memory + +Here are the RTL expression types for describing access to machine +registers and to main memory. + +@table @code +@item (reg:@var{m} @var{n}) +For small values of the integer @var{n} (less than +@code{FIRST_PSEUDO_REGISTER}), this stands for a reference to machine +register number @var{n}: a @dfn{hard register}. For larger values of +@var{n}, it stands for a temporary value or @dfn{pseudo register}. +The compiler's strategy is to generate code assuming an unlimited +number of such pseudo registers, and later convert them into hard +registers or into memory references. + +The symbol @code{FIRST_PSEUDO_REGISTER} is defined by the machine +description, since the number of hard registers on the machine is an +invariant characteristic of the machine. Note, however, that not +all of the machine registers must be general registers. All the +machine registers that can be used for storage of data are given +hard register numbers, even those that can be used only in certain +instructions or can hold only certain types of data. + +Each pseudo register number used in a function's RTL code is +represented by a unique @code{reg} expression. + +@var{m} is the machine mode of the reference. It is necessary because +machines can generally refer to each register in more than one mode. +For example, a register may contain a full word but there may be +instructions to refer to it as a half word or as a single byte, as +well as instructions to refer to it as a floating point number of +various precisions. + +Even for a register that the machine can access in only one mode, +the mode must always be specified. + +A hard register may be accessed in various modes throughout one +function, but each pseudo register is given a natural mode +and is accessed only in that mode. When it is necessary to describe +an access to a pseudo register using a nonnatural mode, a @code{subreg} +expression is used. + +A @code{reg} expression with a machine mode that specifies more than +one word of data may actually stand for several consecutive registers. +If in addition the register number specifies a hardware register, then +it actually represents several consecutive hardware registers starting +with the specified one. + +Such multi-word hardware register @code{reg} expressions must not be live +across the boundary of a basic block. The lifetime analysis pass does not +know how to record properly that several consecutive registers are +actually live there, and therefore register allocation would be confused. +The CSE pass must go out of its way to make sure the situation does +not arise. + +@item (subreg:@var{m} @var{reg} @var{wordnum}) +@code{subreg} expressions are used to refer to a register in a machine +mode other than its natural one, or to refer to one register of +a multi-word @code{reg} that actually refers to several registers. + +Each pseudo-register has a natural mode. If it is necessary to +operate on it in a different mode---for example, to perform a fullword +move instruction on a pseudo-register that contains a single +byte---the pseudo-register must be enclosed in a @code{subreg}. In +such a case, @var{wordnum} is zero. + +The other use of @code{subreg} is to extract the individual registers +of a multi-register value. Machine modes such as @code{DImode} and +@code{EPmode} indicate values longer than a word, values which usually +require two consecutive registers. To access one of the registers, +use a @code{subreg} with mode @code{SImode} and a @var{wordnum} that +says which register. + +The compilation parameter @code{WORDS_BIG_ENDIAN}, if defined, says +that word number zero is the most significant part; otherwise, it is +the least significant part. + +Between the combiner pass and the reload pass, it is possible to have +a @code{subreg} which contains a @code{mem} instead of a @code{reg} as +its first operand. The reload pass eliminates these cases by +reloading the @code{mem} into a suitable register. + +Note that it is not valid to access a @code{DFmode} value in @code{SFmode} +using a @code{subreg}. On some machines the most significant part of a +@code{DFmode} value does not have the same format as a single-precision +floating value. + +@item (cc0) +This refers to the machine's condition code register. It has no +operands and may not have a machine mode. There are two ways to use it: + +@itemize @bullet +@item +To stand for a complete set of condition code flags. This is best on +most machines, where each comparison sets the entire series of flags. + +With this technique, @code{(cc0)} may be validly used in only two +contexts: as the destination of an assignment (in test and compare +instructions) and in comparison operators comparing against zero +(@code{const_int} with value zero; that is to say, @code{const0_rtx}). + +@item +To stand for a single flag that is the result of a single condition. +This is useful on machines that have only a single flag bit, and in +which comparison instructions must specify the condition to test. + +With this technique, @code{(cc0)} may be validly used in only two +contexts: as the destination of an assignment (in test and compare +instructions) where the source is a comparison operator, and as the +first operand of @code{if_then_else} (in a conditional branch). +@end itemize + +There is only one expression object of code @code{cc0}; it is the +value of the variable @code{cc0_rtx}. Any attempt to create an +expression of code @code{cc0} will return @code{cc0_rtx}. + +One special thing about the condition code register is that +instructions can set it implicitly. On many machines, nearly all +instructions set the condition code based on the value that they +compute or store. It is not necessary to record these actions +explicitly in the RTL because the machine description includes a +prescription for recognizing the instructions that do so (by means of +the macro @code{NOTICE_UPDATE_CC}). Only instructions whose sole +purpose is to set the condition code, and instructions that use the +condition code, need mention @code{(cc0)}. + +In some cases, better code may result from recognizing combinations or +peepholes that include instructions that set the condition codes, even +in cases where some reloading is inevitable. For examples, search for +@samp{addcc} and @samp{andcc} in @file{sparc.md}. + +@item (pc) +This represents the machine's program counter. It has no operands and +may not have a machine mode. @code{(pc)} may be validly used only in +certain specific contexts in jump instructions. + +There is only one expression object of code @code{pc}; it is the value +of the variable @code{pc_rtx}. Any attempt to create an expression of +code @code{pc} will return @code{pc_rtx}. + +All instructions that do not jump alter the program counter implicitly +by incrementing it, but there is no need to mention this in the RTL. + +@item (mem:@var{m} @var{addr}) +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. +@end table + +@node Arithmetic, Comparisons, Regs and Memory, RTL +@section RTL Expressions for Arithmetic + +@table @code +@item (plus:@var{m} @var{x} @var{y}) +Represents the sum of the values represented by @var{x} and @var{y} +carried out in machine mode @var{m}. This is valid only if +@var{x} and @var{y} both are valid for mode @var{m}. + +@item (minus:@var{m} @var{x} @var{y}) +Like @code{plus} but represents subtraction. + +@item (compare @var{x} @var{y}) +Represents the result of subtracting @var{y} from @var{x} +for purposes of comparison. The absence of a machine mode +in the @code{compare} expression indicates that the result is +computed without overflow, as if with infinite precision. + +Of course, machines can't really subtract with infinite precision. +However, they can pretend to do so when only the sign of the +result will be used, which is the case when the result is stored +in @code{(cc0)}. And that is the only way this kind of expression +may validly be used: as a value to be stored in the condition codes. + +@item (neg:@var{m} @var{x}) +Represents the negation (subtraction from zero) of the value +represented by @var{x}, carried out in mode @var{m}. @var{x} must be +valid for mode @var{m}. + +@item (mult:@var{m} @var{x} @var{y}) +Represents the signed product of the values represented by @var{x} and +@var{y} carried out in machine mode @var{m}. If +@var{x} and @var{y} are both valid for mode @var{m}, this is ordinary +size-preserving multiplication. Alternatively, both @var{x} and @var{y} +may be valid for a different, narrower mode. This represents the +kind of multiplication that generates a product wider than the operands. +Widening multiplication and same-size multiplication are completely +distinct and supported by different machine instructions; machines may +support one but not the other.@refill + +@code{mult} may be used for floating point multiplication as well. +Then @var{m} is a floating point machine mode. + +@item (umult:@var{m} @var{x} @var{y}) +Like @code{mult} but represents unsigned multiplication. It may be +used in both same-size and widening forms, like @code{mult}. +@code{umult} is used only for fixed-point multiplication. + +@item (div:@var{m} @var{x} @var{y}) +Represents the quotient in signed division of @var{x} by @var{y}, +carried out in machine mode @var{m}. If @var{m} is a floating-point +mode, it represents the exact quotient; otherwise, the integerized +quotient. If @var{x} and @var{y} are both valid for mode @var{m}, +this is ordinary size-preserving division. Some machines have +division instructions in which the operands and quotient widths are +not all the same; such instructions are represented by @code{div} +expressions in which the machine modes are not all the same. + +@item (udiv:@var{m} @var{x} @var{y}) +Like @code{div} but represents unsigned division. + +@item (mod:@var{m} @var{x} @var{y}) +@itemx (umod:@var{m} @var{x} @var{y}) +Like @code{div} and @code{udiv} but represent the remainder instead of +the quotient. + +@item (not:@var{m} @var{x}) +Represents the bitwise complement of the value represented by @var{x}, +carried out in mode @var{m}, which must be a fixed-point machine mode. +@var{x} must be valid for mode @var{m}, which must be a fixed-point mode. + +@item (and:@var{m} @var{x} @var{y}) +Represents the bitwise logical-and of the values represented by +@var{x} and @var{y}, carried out in machine mode @var{m}. This is +valid only if @var{x} and @var{y} both are valid for mode @var{m}, +which must be a fixed-point mode. + +@item (ior:@var{m} @var{x} @var{y}) +Represents the bitwise inclusive-or of the values represented by +@var{x} and @var{y}, carried out in machine mode @var{m}. This is +valid only if @var{x} and @var{y} both are valid for mode @var{m}, +which must be a fixed-point mode. + +@item (xor:@var{m} @var{x} @var{y}) +Represents the bitwise exclusive-or of the values represented by +@var{x} and @var{y}, carried out in machine mode @var{m}. This is +valid only if @var{x} and @var{y} both are valid for mode @var{m}, +which must be a fixed-point mode. + +@item (lshift:@var{m} @var{x} @var{c}) +Represents the result of logically shifting @var{x} left by @var{c} +places. @var{x} must be valid for the mode @var{m}, a fixed-point +machine mode. @var{c} must be valid for a fixed-point mode; +which mode is determined by the mode called for in the machine +description entry for the left-shift instruction. For example, +on the Vax, the mode of @var{c} is @code{QImode} regardless of @var{m}. + +On some machines, negative values of @var{c} may be meaningful; this +is why logical left shift and arithmetic left shift are distinguished. +For example, Vaxes have no right-shift instructions, and right shifts +are represented as left-shift instructions whose counts happen +to be negative constants or else computed (in a previous instruction) +by negation. + +@item (ashift:@var{m} @var{x} @var{c}) +Like @code{lshift} but for arithmetic left shift. + +@item (lshiftrt:@var{m} @var{x} @var{c}) +@itemx (ashiftrt:@var{m} @var{x} @var{c}) +Like @code{lshift} and @code{ashift} but for right shift. + +@item (rotate:@var{m} @var{x} @var{c}) +@itemx (rotatert:@var{m} @var{x} @var{c}) +Similar but represent left and right rotate. + +@item (abs:@var{m} @var{x}) +Represents the absolute value of @var{x}, computed in mode @var{m}. +@var{x} must be valid for @var{m}. + +@item (sqrt:@var{m} @var{x}) +Represents the square root of @var{x}, computed in mode @var{m}. +@var{x} must be valid for @var{m}. Most often @var{m} will be +a floating point mode. + +@item (ffs:@var{m} @var{x}) +Represents one plus the index of the least significant 1-bit in +@var{x}, represented as an integer of mode @var{m}. (The value is +zero if @var{x} is zero.) The mode of @var{x} need not be @var{m}; +depending on the target machine, various mode combinations may be +valid. +@end table + +@node Comparisons, Bit Fields, Arithmetic, RTL +@section Comparison Operations + +Comparison operators test a relation on two operands and are considered +to represent a machine-dependent nonzero value (@code{STORE_FLAG_VALUE}) +if the relation holds, or zero if it does not. The mode of the +comparison is determined by the operands; they must both be valid for a +common machine mode. A comparison with both operands constant would be +invalid as the machine mode could not be deduced from it, but such a +comparison should never exist in RTL due to constant folding. + +Inequality comparisons come in two flavors, signed and unsigned. Thus, +there are distinct expression codes @code{gt} and @code{gtu} for signed and +unsigned greater-than. These can produce different results for the same +pair of integer values: for example, 1 is signed greater-than -1 but not +unsigned greater-than, because -1 when regarded as unsigned is actually +@code{0xffffffff} which is greater than 1. + +The signed comparisons are also used for floating point values. Floating +point comparisons are distinguished by the machine modes of the operands. + +The comparison operators may be used to compare the condition codes +@code{(cc0)} against zero, as in @code{(eq (cc0) (const_int 0))}. Such a +construct actually refers to the result of the preceding instruction in +which the condition codes were set. The above example stands for 1 if the +condition codes were set to say ``zero'' or ``equal'', 0 otherwise. +Although the same comparison operators are used for this as may be used in +other contexts on actual data, no confusion can result since the machine +description would never allow both kinds of uses in the same context. + +@table @code +@item (eq @var{x} @var{y}) +1 if the values represented by @var{x} and @var{y} are equal, +otherwise 0. + +@item (ne @var{x} @var{y}) +1 if the values represented by @var{x} and @var{y} are not equal, +otherwise 0. + +@item (gt @var{x} @var{y}) +1 if the @var{x} is greater than @var{y}. If they are fixed-point, +the comparison is done in a signed sense. + +@item (gtu @var{x} @var{y}) +Like @code{gt} but does unsigned comparison, on fixed-point numbers only. + +@item (lt @var{x} @var{y}) +@item (ltu @var{x} @var{y}) +Like @code{gt} and @code{gtu} but test for ``less than''. + +@item (ge @var{x} @var{y}) +@item (geu @var{x} @var{y}) +Like @code{gt} and @code{gtu} but test for ``greater than or equal''. + +@item (le @var{x} @var{y}) +@item (leu @var{x} @var{y}) +Like @code{gt} and @code{gtu} but test for ``less than or equal''. + +@item (if_then_else @var{cond} @var{then} @var{else}) +This is not a comparison operation but is listed here because it is +always used in conjunction with a comparison operation. To be +precise, @var{cond} is a comparison expression. This expression +represents a choice, according to @var{cond}, between the value +represented by @var{then} and the one represented by @var{else}. + +On most machines, @code{if_then_else} expressions are valid only +to express conditional jumps. +@end table + +@node Bit Fields, Conversions, Comparisons, RTL +@section Bit-fields + +Special expression codes exist to represent bit-field instructions. +These types of expressions are lvalues in RTL; they may appear +on the left side of an assignment, indicating insertion of a value +into the specified bit field. + +@table @code +@item (sign_extract:SI @var{loc} @var{size} @var{pos}) +This represents a reference to a sign-extended bit-field contained or +starting in @var{loc} (a memory or register reference). The bit field +is @var{size} bits wide and starts at bit @var{pos}. The compilation +option @code{BITS_BIG_ENDIAN} says which end of the memory unit +@var{pos} counts from. + +Which machine modes are valid for @var{loc} depends on the machine, +but typically @var{loc} should be a single byte when in memory +or a full word in a register. + +@item (zero_extract:SI @var{loc} @var{size} @var{pos}) +Like @code{sign_extract} but refers to an unsigned or zero-extended +bit field. The same sequence of bits are extracted, but they +are filled to an entire word with zeros instead of by sign-extension. +@end table + +@node Conversions, RTL Declarations, Bit Fields, RTL +@section Conversions + +All conversions between machine modes must be represented by +explicit conversion operations. For example, an expression +which is the sum of a byte and a full word cannot be written as +@code{(plus:SI (reg:QI 34) (reg:SI 80))} because the @code{plus} +operation requires two operands of the same machine mode. +Therefore, the byte-sized operand is enclosed in a conversion +operation, as in + +@example +(plus:SI (sign_extend:SI (reg:QI 34)) (reg:SI 80)) +@end example + +The conversion operation is not a mere placeholder, because there +may be more than one way of converting from a given starting mode +to the desired final mode. The conversion operation code says how +to do it. + +@table @code +@item (sign_extend:@var{m} @var{x}) +Represents the result of sign-extending the value @var{x} +to machine mode @var{m}. @var{m} must be a fixed-point mode +and @var{x} a fixed-point value of a mode narrower than @var{m}. + +@item (zero_extend:@var{m} @var{x}) +Represents the result of zero-extending the value @var{x} +to machine mode @var{m}. @var{m} must be a fixed-point mode +and @var{x} a fixed-point value of a mode narrower than @var{m}. + +@item (float_extend:@var{m} @var{x}) +Represents the result of extending the value @var{x} +to machine mode @var{m}. @var{m} must be a floating point mode +and @var{x} a floating point value of a mode narrower than @var{m}. + +@item (truncate:@var{m} @var{x}) +Represents the result of truncating the value @var{x} +to machine mode @var{m}. @var{m} must be a fixed-point mode +and @var{x} a fixed-point value of a mode wider than @var{m}. + +@item (float_truncate:@var{m} @var{x}) +Represents the result of truncating the value @var{x} +to machine mode @var{m}. @var{m} must be a floating point mode +and @var{x} a floating point value of a mode wider than @var{m}. + +@item (float:@var{m} @var{x}) +Represents the result of converting fixed point value @var{x}, +regarded as signed, to floating point mode @var{m}. + +@item (unsigned_float:@var{m} @var{x}) +Represents the result of converting fixed point value @var{x}, +regarded as unsigned, to floating point mode @var{m}. + +@item (fix:@var{m} @var{x}) +When @var{m} is a fixed point mode, represents the result of +converting floating point value @var{x} to mode @var{m}, regarded as +signed. How rounding is done is not specified, so this operation may +be used validly in compiling C code only for integer-valued operands. + +@item (unsigned_fix:@var{m} @var{x}) +Represents the result of converting floating point value @var{x} to +fixed point mode @var{m}, regarded as unsigned. How rounding is done +is not specified. + +@item (fix:@var{m} @var{x}) +When @var{m} is a floating point mode, represents the result of +converting floating point value @var{x} (valid for mode @var{m}) to an +integer, still represented in floating point mode @var{m}, by rounding +towards zero. +@end table + +@node RTL Declarations, Side Effects, Conversions, RTL +@section Declarations + +Declaration expression codes do not represent arithmetic operations +but rather state assertions about their operands. + +@table @code +@item (strict_low_part (subreg:@var{m} (reg:@var{n} @var{r}) 0)) +This expression code is used in only one context: operand 0 of a +@code{set} expression. In addition, the operand of this expression +must be a @code{subreg} expression. + +The presence of @code{strict_low_part} says that the part of the +register which is meaningful in mode @var{n}, but is not part of +mode @var{m}, is not to be altered. Normally, an assignment to such +a subreg is allowed to have undefined effects on the rest of the +register when @var{m} is less than a word. +@end table + +@node Side Effects, Incdec, RTL Declarations, RTL +@section Side Effect Expressions + +The expression codes described so far represent values, not actions. +But machine instructions never produce values; they are meaningful +only for their side effects on the state of the machine. Special +expression codes are used to represent side effects. + +The body of an instruction is always one of these side effect codes; +the codes described above, which represent values, appear only as +the operands of these. + +@table @code +@item (set @var{lval} @var{x}) +Represents the action of storing the value of @var{x} into the place +represented by @var{lval}. @var{lval} must be an expression +representing a place that can be stored in: @code{reg} (or +@code{subreg} or @code{strict_low_part}), @code{mem}, @code{pc} or +@code{cc0}.@refill + +If @var{lval} is a @code{reg}, @code{subreg} or @code{mem}, it has a +machine mode; then @var{x} must be valid for that mode.@refill + +If @var{lval} is a @code{reg} whose machine mode is less than the full +width of the register, then it means that the part of the register +specified by the machine mode is given the specified value and the +rest of the register receives an undefined value. Likewise, if +@var{lval} is a @code{subreg} whose machine mode is narrower than +@code{SImode}, the rest of the register can be changed in an undefined way. + +If @var{lval} is a @code{strict_low_part} of a @code{subreg}, then the +part of the register specified by the machine mode of the +@code{subreg} is given the value @var{x} and the rest of the register +is not changed.@refill + +If @var{lval} is @code{(cc0)}, it has no machine mode, and @var{x} may +have any mode. This represents a ``test'' or ``compare'' instruction.@refill + +If @var{lval} is @code{(pc)}, we have a jump instruction, and the +possibilities for @var{x} are very limited. It may be a +@code{label_ref} expression (unconditional jump). It may be an +@code{if_then_else} (conditional jump), in which case either the +second or the third operand must be @code{(pc)} (for the case which +does not jump) and the other of the two must be a @code{label_ref} +(for the case which does jump). @var{x} may also be a @code{mem} or +@code{(plus:SI (pc) @var{y})}, where @var{y} may be a @code{reg} or a +@code{mem}; these unusual patterns are used to represent jumps through +branch tables.@refill + +@item (return) +Represents a return from the current function, on machines where this +can be done with one instruction, such as Vaxes. On machines where a +multi-instruction ``epilogue'' must be executed in order to return +from the function, returning is done by jumping to a label which +precedes the epilogue, and the @code{return} expression code is never +used. + +@item (call @var{function} @var{nargs}) +Represents a function call. @var{function} is a @code{mem} expression +whose address is the address of the function to be called. +@var{nargs} is an expression which can be used for two purposes: on +some machines it represents the number of bytes of stack argument; on +others, it represents the number of argument registers. + +Each machine has a standard machine mode which @var{function} must +have. The machine description defines macro @code{FUNCTION_MODE} to +expand into the requisite mode name. The purpose of this mode is to +specify what kind of addressing is allowed, on machines where the +allowed kinds of addressing depend on the machine mode being +addressed. + +@item (clobber @var{x}) +Represents the storing or possible storing of an unpredictable, +undescribed value into @var{x}, which must be a @code{reg} or +@code{mem} expression. + +One place this is used is in string instructions that store standard +values into particular hard registers. It may not be worth the +trouble to describe the values that are stored, but it is essential to +inform the compiler that the registers will be altered, lest it +attempt to keep data in them across the string instruction. + +@var{x} may also be null---a null C pointer, no expression at all. +Such a @code{(clobber (null))} expression means that all memory +locations must be presumed clobbered. + +Note that the machine description classifies certain hard registers as +``call-clobbered''. All function call instructions are assumed by +default to clobber these registers, so there is no need to use +@code{clobber} expressions to indicate this fact. Also, each function +call is assumed to have the potential to alter any memory location, +unless the function is declared @code{const}. + +When a @code{clobber} expression for a register appears inside a +@code{parallel} with other side effects, GNU CC guarantees that the +register is unoccupied both before and after that insn. Therefore, it +is safe for the assembler code produced by the insn to use the +register as a temporary. You can clobber either a specific hard +register or a pseudo register; in the latter case, GNU CC will +allocate a hard register that is available there for use as a +temporary. + +If you clobber a pseudo register in this way, use a pseudo register +which appears nowhere else---generate a new one each time. Otherwise, +you may confuse CSE. + +There is one other known use for clobbering a pseudo register in a +@code{parallel}: when one of the input operands of the insn is also +clobbered by the insn. In this case, using the same pseudo register in +the clobber and elsewhere in the insn produces the expected results. + +@item (use @var{x}) +Represents the use of the value of @var{x}. It indicates that the +value in @var{x} at this point in the program is needed, even though +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. + +@item (parallel [@var{x0} @var{x1} @dots{}]) +Represents several side effects performed in parallel. The square +brackets stand for a vector; the operand of @code{parallel} is a +vector of expressions. @var{x0}, @var{x1} and so on are individual +side effect expressions---expressions of code @code{set}, @code{call}, +@code{return}, @code{clobber} or @code{use}.@refill + +``In parallel'' means that first all the values used in the individual +side-effects are computed, and second all the actual side-effects are +performed. For example, + +@example +(parallel [(set (reg:SI 1) (mem:SI (reg:SI 1))) + (set (mem:SI (reg:SI 1)) (reg:SI 1))]) +@end example + +@noindent +says unambiguously that the values of hard register 1 and the memory +location addressed by it are interchanged. In both places where +@code{(reg:SI 1)} appears as a memory address it refers to the value +in register 1 @emph{before} the execution of the insn. + +It follows that it is @emph{incorrect} to use @code{parallel} and +expect the result of one @code{set} to be available for the next one. +For example, people sometimes attempt to represent a jump-if-zero +instruction this way: + +@example +(parallel [(set (cc0) (reg:SI 34)) + (set (pc) (if_then_else + (eq (cc0) (const_int 0)) + (label_ref @dots{}) + (pc)))]) +@end example + +@noindent +But this is incorrect, because it says that the jump condition depends +on the condition code value @emph{before} this instruction, not on the +new value that is set by this instruction. + +Peephole optimization, which takes place in together with final assembly +code output, can produce insns whose patterns consist of a @code{parallel} +whose elements are the operands needed to output the resulting +assembler code---often @code{reg}, @code{mem} or constant expressions. +This would not be well-formed RTL at any other stage in compilation, +but it is ok then because no further optimization remains to be done. +However, the definition of the macro @code{NOTICE_UPDATE_CC} must +deal with such insns if you define any peephole optimizations. + +@item (sequence [@var{insns} @dots{}]) +Represents a sequence of insns. Each of the @var{insns} that appears +in the vector is suitable for appearing in the chain of insns, so it +must be an @code{insn}, @code{jump_insn}, @code{call_insn}, +@code{code_label}, @code{barrier} or @code{note}. + +A @code{sequence} RTX never appears in an actual insn. It represents +the sequence of insns that result from a @code{define_expand} +@emph{before} those insns are passed to @code{emit_insn} to insert +them in the chain of insns. When actually inserted, the individual +sub-insns are separated out and the @code{sequence} is forgotten. +@end table + +Three expression codes appear in place of a side effect, as the body of an +insn, though strictly speaking they do not describe side effects as such: + +@table @code +@item (asm_input @var{s}) +Represents literal assembler code as described by the string @var{s}. + +@item (addr_vec:@var{m} [@var{lr0} @var{lr1} @dots{}]) +Represents a table of jump addresses. The vector elements @var{lr0}, +etc., are @code{label_ref} expressions. The mode @var{m} specifies +how much space is given to each address; normally @var{m} would be +@code{Pmode}. + +@item (addr_diff_vec:@var{m} @var{base} [@var{lr0} @var{lr1} @dots{}]) +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 +@end table + +@node Incdec, Assembler, Side Effects, RTL +@section Embedded Side-Effects on Addresses + +Four special side-effect expression codes appear as memory addresses. + +@table @code +@item (pre_dec:@var{m} @var{x}) +Represents the side effect of decrementing @var{x} by a standard +amount and represents also the value that @var{x} has after being +decremented. @var{x} must be a @code{reg} or @code{mem}, but most +machines allow only a @code{reg}. @var{m} must be the machine mode +for pointers on the machine in use. The amount @var{x} is decremented +by is the length in bytes of the machine mode of the containing memory +reference of which this expression serves as the address. Here is an +example of its use:@refill + +@example +(mem:DF (pre_dec:SI (reg:SI 39))) +@end example + +@noindent +This says to decrement pseudo register 39 by the length of a @code{DFmode} +value and use the result to address a @code{DFmode} value. + +@item (pre_inc:@var{m} @var{x}) +Similar, but specifies incrementing @var{x} instead of decrementing it. + +@item (post_dec:@var{m} @var{x}) +Represents the same side effect as @code{pre_dec} but a different +value. The value represented here is the value @var{x} has @i{before} +being decremented. + +@item (post_inc:@var{m} @var{x}) +Similar, but specifies incrementing @var{x} instead of decrementing it. +@end table + +These embedded side effect expressions must be used with care. Instruction +patterns may not use them. Until the @samp{flow} pass of the compiler, +they may occur only to represent pushes onto the stack. The @samp{flow} +pass finds cases where registers are incremented or decremented in one +instruction and used as an address shortly before or after; these cases are +then transformed to use pre- or post-increment or -decrement. + +Explicit popping of the stack could be represented with these embedded +side effect operators, but that would not be safe; the instruction +combination pass could move the popping past pushes, thus changing +the meaning of the code. + +An instruction that can be represented with an embedded side effect +could also be represented using @code{parallel} containing an additional +@code{set} to describe how the address register is altered. This is not +done because machines that allow these operations at all typically +allow them wherever a memory address is called for. Describing them as +additional parallel stores would require doubling the number of entries +in the machine description. + +@node Assembler, Insns, IncDec, RTL +@section Assembler Instructions as Expressions + +The RTX code @code{asm_operands} represents a value produced by a +user-specified assembler instruction. It is used to represent +an @code{asm} statement with arguments. An @code{asm} statement with +a single output operand, like this: + +@example +asm ("foo %1,%2,%0" : "=a" (outputvar) : "g" (x + y), "di" (*z)); +@end example + +@noindent +is represented using a single @code{asm_operands} RTX which represents +the value that is stored in @code{outputvar}: + +@example +(set @var{rtx-for-outputvar} + (asm_operands "foo %1,%2,%0" "a" 0 + [@var{rtx-for-addition-result} @var{rtx-for-*z}] + [(asm_input:@var{m1} "g") + (asm_input:@var{m2} "di")])) +@end example + +@noindent +Here the operands of the @code{asm_operands} RTX are the assembler +template string, the output-operand's constraint, the index-number of the +output operand among the output operands specified, a vector of input +operand RTX's, and a vector of input-operand modes and constraints. The +mode @var{m1} is the mode of the sum @code{x+y}; @var{m2} is that of +@code{*z}. + +When an @code{asm} statement has multiple output values, its insn has +several such @code{set} RTX's inside of a @code{parallel}. Each @code{set} +contains a @code{asm_operands}; all of these share the same assembler +template and vectors, but each contains the constraint for the respective +output operand. They are also distinguished by the output-operand index +number, which is 0, 1, @dots{} for successive output operands. + +@node Insns, Calls, Assembler, RTL +@section Insns + +The RTL representation of the code for a function is a doubly-linked +chain of objects called @dfn{insns}. Insns are expressions with +special codes that are used for no other purpose. Some insns are +actual instructions; others represent dispatch tables for @code{switch} +statements; others represent labels to jump to or various sorts of +declarative information. + +In addition to its own specific data, each insn must have a unique id-number +that distinguishes it from all other insns in the current function, and +chain pointers to the preceding and following insns. These three fields +occupy the same position in every insn, independent of the expression code +of the insn. They could be accessed with @code{XEXP} and @code{XINT}, +but instead three special macros are always used: + +@table @code +@item INSN_UID (@var{i}) +Accesses the unique id of insn @var{i}. + +@item PREV_INSN (@var{i}) +Accesses the chain pointer to the insn preceding @var{i}. +If @var{i} is the first insn, this is a null pointer. + +@item NEXT_INSN (@var{i}) +Accesses the chain pointer to the insn following @var{i}. +If @var{i} is the last insn, this is a null pointer. +@end table + +The @code{NEXT_INSN} and @code{PREV_INSN} pointers must always +correspond: if @var{insn} is not the first insn, + +@example +NEXT_INSN (PREV_INSN (@var{insn})) == @var{insn} +@end example + +@noindent +is always true. + +Every insn has one of the following six expression codes: + +@table @code +@item insn +The expression code @code{insn} is used for instructions that do not jump +and do not do function calls. Insns with code @code{insn} have four +additional fields beyond the three mandatory ones listed above. +These four are described in a table below. + +@item jump_insn +The expression code @code{jump_insn} is used for instructions that may jump +(or, more generally, may contain @code{label_ref} expressions). +@code{jump_insn} insns have the same extra fields as @code{insn} insns, +accessed in the same way. If there is an instruction to return from the +current function, it is recorded as a @code{jump_insn}. + +@item call_insn +The expression code @code{call_insn} is used for instructions that may do +function calls. It is important to distinguish these instructions because +they imply that certain registers and memory locations may be altered +unpredictably. + +@code{call_insn} insns have the same extra fields as @code{insn} insns, +accessed in the same way. + +@item code_label +A @code{code_label} insn represents a label that a jump insn can jump to. +It contains one special field of data in addition to the three standard ones. +It is used to hold the @dfn{label number}, a number that identifies this +label uniquely among all the labels in the compilation (not just in the +current function). Ultimately, the label is represented in the assembler +output as an assembler label @samp{L@var{n}} where @var{n} is the label number. + +@item barrier +Barriers are placed in the instruction stream after unconditional +jump instructions to indicate that the jumps are unconditional. +They contain no information beyond the three standard fields. + +@item note +@code{note} insns are used to represent additional debugging and +declarative information. They contain two nonstandard fields, an +integer which is accessed with the macro @code{NOTE_LINE_NUMBER} and a +string accessed with @code{NOTE_SOURCE_FILE}. + +If @code{NOTE_LINE_NUMBER} is positive, the note represents the +position of a source line and @code{NOTE_SOURCE_FILE} is the source file name +that the line came from. These notes control generation of line +number data in the assembler output. + +Otherwise, @code{NOTE_LINE_NUMBER} is not really a line number but a +code with one of the following values (and @code{NOTE_SOURCE_FILE} +must contain a null pointer): + +@table @code +@item NOTE_INSN_DELETED +Such a note is completely ignorable. Some passes of the compiler +delete insns by altering them into notes of this kind. + +@item NOTE_INSN_BLOCK_BEG +@itemx NOTE_INSN_BLOCK_END +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. + +@item NOTE_INSN_LOOP_BEG +@itemx NOTE_INSN_LOOP_END +These types of notes indicate the position of the beginning and end +of a @code{while} or @code{for} loop. They enable the loop optimizer +to find loops quickly. +@item NOTE_INSN_FUNCTION_END +Appears near the end of the function body, just before the label that +@code{return} statements jump to (on machine where a single instruction +does not suffice for returning). This note may be deleted by jump +optimization. +@item NOTE_INSN_SETJMP +Appears following each call to @code{setjmp} or a related function. + +@item NOTE_INSN_LOOP_CONT +Appears at the place in a loop that @code{continue} statements jump to. +@end table + +These codes are printed symbolically when they appear in debugging dumps. +@end table + +The machine mode of an insn is normally zero (@code{VOIDmode}), but the +reload pass sets it to @code{QImode} if the insn needs reloading. + +Here is a table of the extra fields of @code{insn}, @code{jump_insn} +and @code{call_insn} insns: + +@table @code +@item PATTERN (@var{i}) +An expression for the side effect performed by this insn. + +@item INSN_CODE (@var{i}) +An integer that says which pattern in the machine description matches +this insn, or -1 if the matching has not yet been attempted. + +Such matching is never attempted and this field is not used on an insn +whose pattern consists of a single @code{use}, @code{clobber}, +@code{asm}, @code{addr_vec} or @code{addr_diff_vec} expression. + +@item LOG_LINKS (@var{i}) +A list (chain of @code{insn_list} expressions) of previous ``related'' +insns: insns which store into registers values that are used for the +first time in this insn. (An additional constraint is that neither a +jump nor a label may come between the related insns). This list is +set up by the flow analysis pass; it is a null pointer until then. + +@item REG_NOTES (@var{i}) +A list (chain of @code{expr_list} expressions) giving information +about the usage of registers in this insn. This list is set up by the +flow analysis pass; it is a null pointer until then. +@end table + +The @code{LOG_LINKS} field of an insn is a chain of @code{insn_list} +expressions. Each of these has two operands: the first is an insn, +and the second is another @code{insn_list} expression (the next one in +the chain). The last @code{insn_list} in the chain has a null pointer +as second operand. The significant thing about the chain is which +insns appear in it (as first operands of @code{insn_list} +expressions). Their order is not significant. + +The @code{REG_NOTES} field of an insn is a similar chain but of +@code{expr_list} expressions instead of @code{insn_list}. There are +several kinds of register notes, which are distinguished by the machine +mode of the @code{expr_list}, which in a register note is really +understood as being an @code{enum reg_note}. The first operand @var{op} +of the @code{expr_list} is data whose meaning depends on the kind of +note. Here are the kinds of register note: + +@table @code +@item REG_DEAD +The register @var{op} dies in this insn; that is to say, altering the +value immediately after this insn would not affect the future behavior +of the program. + +@item REG_INC +The register @var{op} is incremented (or decremented; at this level +there is no distinction) by an embedded side effect inside this insn. +This means it appears in a @code{post_inc}, @code{pre_inc}, +@code{post_dec} or @code{pre_dec} RTX. + +@item REG_EQUIV +The register that is set by this insn will be equal to @var{op} at run +time, and could validly be replaced in all its occurrences by +@var{op}. (``Validly'' here refers to the data flow of the program; +simple replacement may make some insns invalid.) + +The value which the insn explicitly copies into the register may look +different from @var{op}, but they will be equal at run time. + +For example, when a constant is loaded into a register that is never +assigned any other value, this kind of note is used. + +When a parameter is copied into a pseudo-register at entry to a function, +a note of this kind records that the register is equivalent to the stack +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. + +@item 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). + +The RTX @var{op} is typically an arithmetic expression. For example, +when a sequence of insns such as a library call is used to perform an +arithmetic operation, this kind of note is attached to the insn that +produces or copies the final value. It tells the CSE pass how to +think of that value. + +@item REG_RETVAL +This insn copies the value of a library call, and @var{op} is the +first insn that was generated to set up the arguments for the library +call. + +Flow analysis uses this note to delete all of a library call whose +result is dead. + +@item REG_WAS_0 +The register @var{op} contained zero before this insn. You can rely +on this note if it is present; its absence implies nothing. + +@item REG_LIBCALL +This is the inverse of @code{REG_RETVAL}: it is placed on the first +insn of a library call, and it points to the last one. + +Loop optimization uses this note to move an entire library call out +of a loop when its value is constant. + +@item REG_NONNEG +The register @var{op} is known to have nonnegative value when this +insn is reached. +@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. + +The only difference between the expression codes @code{insn_list} and +@code{expr_list} is that the first operand of an @code{insn_list} is +assumed to be an insn and is printed in debugging dumps as the insn's +unique id; the first operand of an @code{expr_list} is printed in the +ordinary way as an expression. + +@node Calls, Sharing, Insns, RTL +@section RTL Representation of Function-Call Insns + +Insns that call subroutines have the RTL expression code @code{call_insn}. +These insns must satisfy special rules, and their bodies must use a special +RTL expression code, @code{call}. + +A @code{call} expression has two operands, as follows: + +@example +(call (mem:@var{fm} @var{addr}) @var{nbytes}) +@end example + +@noindent +Here @var{nbytes} is an operand that represents the number of bytes of +argument data being passed to the subroutine, @var{fm} is a machine mode +(which must equal as the definition of the @code{FUNCTION_MODE} macro in +the machine description) and @var{addr} represents the address of the +subroutine. + +For a subroutine that returns no value, the @code{call} RTX as shown above +is the entire body of the insn. + +For a subroutine that returns a value whose mode is not @code{BLKmode}, +the value is returned in a hard register. If this register's number is +@var{r}, then the body of the call insn looks like this: + +@example +(set (reg:@var{m} @var{r}) + (call (mem:@var{fm} @var{addr}) @var{nbytes})) +@end example + +@noindent +This RTL expression makes it clear (to the optimizer passes) that the +appropriate register receives a useful value in this insn. + +Immediately after RTL generation, if the value of the subroutine is +actually used, this call insn is always followed closely by an insn which +refers to the register @var{r}. This remains true through all the +optimizer passes until cross jumping occurs. + +The following insn has one of two forms. Either it copies the value into a +pseudo-register, like this: + +@example +(set (reg:@var{m} @var{p}) (reg:@var{m} @var{r})) +@end example + +@noindent +or (in the case where the calling function will simply return whatever +value the call produced, and no operation is needed to do this): + +@example +(use (reg:@var{m} @var{r})) +@end example + +@noindent +Between the call insn and this following insn there may intervene only a +stack-adjustment insn (and perhaps some @code{note} insns). + +When a subroutine returns a @code{BLKmode} value, it is handled by +passing to the subroutine the address of a place to store the value. +So the call insn itself does not ``return'' any value, and it has the +same RTL form as a call that returns nothing. + +@node Sharing,, Calls, RTL +@section Structure Sharing Assumptions + +The compiler assumes that certain kinds of RTL expressions are unique; +there do not exist two distinct objects representing the same value. +In other cases, it makes an opposite assumption: that no RTL expression +object of a certain kind appears in more than one place in the +containing structure. + +These assumptions refer to a single function; except for the RTL +objects that describe global variables and external functions, +no RTL objects are common to two functions. + +@itemize @bullet +@item +Each pseudo-register has only a single @code{reg} object to represent it, +and therefore only a single machine mode. + +@item +For any symbolic label, there is only one @code{symbol_ref} object +referring to it. + +@item +There is only one @code{const_int} expression with value zero, +and only one with value one. + +@item +There is only one @code{pc} expression. + +@item +There is only one @code{cc0} expression. + +@item +There is only one @code{const_double} expression with mode +@code{SFmode} and value zero, and only one with mode @code{DFmode} and +value zero. + +@item +No @code{label_ref} appears in more than one place in the RTL +structure; in other words, it is safe to do a tree-walk of all the +insns in the function and assume that each time a @code{label_ref} is +seen it is distinct from all others that are seen. + +@item +Only one @code{mem} object is normally created for each static +variable or stack slot, so these objects are frequently shared in all +the places they appear. However, separate but equal objects for these +variables are occasionally made. + +@item +When a single @code{asm} statement has multiple output operands, +a distinct @code{asm_operands} RTX is made for each output operand. +However, these all share the vector which contains the sequence of +input operands. Because this sharing is used later on to test whether +two @code{asm_operands} RTX's come from the same statement, the sharing +must be guaranteed to be preserved. + +@item +No RTL object appears in more than one place in the RTL structure +except as described above. Many passes of the compiler rely on this +by assuming that they can modify RTL objects in place without unwanted +side-effects on other insns. + +@item +During initial RTL generation, shared structure is freely introduced. +After all the RTL for a function has been generated, all shared +structure is copied by @code{unshare_all_rtl} in @file{emit-rtl.c}, +after which the above rules are guaranteed to be followed. + +@item +During the combiner pass, shared structure with an insn can exist +temporarily. However, the shared structure is copied before the +combiner is finished with the insn. This is done by +@code{copy_substitutions} in @file{combine.c}. +@end itemize + +@node Machine Desc, Machine Macros, RTL, Top +@chapter Machine Descriptions + +A machine description has two parts: a file of instruction patterns +(@file{.md} file) and a C header file of macro definitions. + +The @file{.md} file for a target machine contains a pattern for each +instruction that the target machine supports (or at least each instruction +that is worth telling the compiler about). It may also contain comments. +A semicolon causes the rest of the line to be a comment, unless the semicolon +is inside a quoted string. + +See the next chapter for information on the C header file. + +@menu +* Patterns:: How to write instruction patterns. +* Example:: An explained example of a @code{define_insn} pattern. +* RTL Template:: The RTL template defines what insns match a pattern. +* Output Template:: The output template says how to make assembler code + from such an insn. +* Output Statement:: For more generality, write C code to output + the assembler code. +* Constraints:: When not all operands are general operands. +* Standard Names:: Names mark patterns to use for code generation. +* Pattern Ordering:: When the order of patterns makes a difference. +* Dependent Patterns:: Having one pattern may make you need another. +* Jump Patterns:: Special considerations for patterns for jump insns. +* Peephole Definitions::Defining machine-specific peephole optimizations. +* Expander Definitions::Generating a sequence of several RTL insns + for a standard operation. +@end menu + +@node Patterns, Example, Machine Desc, Machine Desc +@section Everything about Instruction Patterns + +Each instruction pattern contains an incomplete RTL expression, with pieces +to be filled in later, operand constraints that restrict how the pieces can +be filled in, and an output pattern or C code to generate the assembler +output, all wrapped up in a @code{define_insn} expression. + +A @code{define_insn} is an RTL expression containing four or five operands: + +@enumerate +@item +An optional name. The presence of a name indicate that this instruction +pattern can perform a certain standard job for the RTL-generation +pass of the compiler. This pass knows certain names and will use +the instruction patterns with those names, if the names are defined +in the machine description. + +The absence of a name is indicated by writing an empty string +where the name should go. Nameless instruction patterns are never +used for generating RTL code, but they may permit several simpler insns +to be combined later on. + +Names that are not thus known and used in RTL-generation have no +effect; they are equivalent to no name at all. + +@item +The @dfn{RTL template} (@pxref{RTL Template}) is a vector of +incomplete RTL expressions which show what the instruction should look +like. It is incomplete because it may contain @code{match_operand} +and @code{match_dup} expressions that stand for operands of the +instruction. + +If the vector has only one element, that element is the template for the +instruction pattern. If the vector has multiple elements, then the +instruction pattern is a @code{parallel} expression containing the +elements described. + +@item +A condition. This is a string which contains a C expression that is +the final test to decide whether an insn body matches this pattern. + +For a named pattern, the condition (if present) may not depend on +the data in the insn being matched, but only the target-machine-type +flags. The compiler needs to test these conditions during +initialization in order to learn exactly which named instructions are +available in a particular run. + +For nameless patterns, the condition is applied only when matching an +individual insn, and only after the insn has matched the pattern's +recognition template. The insn's operands may be found in the vector +@code{operands}. + +@item +The @dfn{output template}: a string that says how to output matching +insns as assembler code. @samp{%} in this string specifies where +to substitute the value of an operand. @xref{Output Template}. + +When simple substitution isn't general enough, you can specify a piece +of C code to compute the output. @xref{Output Statement}. + +@item +Optionally, some @dfn{machine-specific information}. The meaning +of this information is defined only by an individual machine description; +typically it might say whether this insn alters the condition codes, +or how many bytes of output it generates. + +This operand is written as a string containing a C initializer +(complete with braces) for the structure type @code{INSN_MACHINE_INFO}, +whose definition is up to you (@pxref{Misc}). +@end enumerate + +@node Example, RTL Template, Patterns, Machine Desc +@section Example of @code{define_insn} + +Here is an actual example of an instruction pattern, for the 68000/68020. + +@example +(define_insn "tstsi" + [(set (cc0) + (match_operand:SI 0 "general_operand" "rm"))] + "" + "* +@{ if (TARGET_68020 || ! ADDRESS_REG_P (operands[0])) + return \"tstl %0\"; + return \"cmpl #0,%0\"; @}") +@end example + +This is an instruction that sets the condition codes based on the value of +a general operand. It has no condition, so any insn whose RTL description +has the form shown may be handled according to this pattern. The name +@samp{tstsi} means ``test a @code{SImode} value'' and tells the RTL generation +pass that, when it is necessary to test such a value, an insn to do so +can be constructed using this pattern. + +The output control string is a piece of C code which chooses which +output template to return based on the kind of operand and the specific +type of CPU for which code is being generated. + +@samp{"rm"} is an operand constraint. Its meaning is explained below. + +@node RTL Template, Output Template, Example, Machine Desc +@section RTL Template for Generating and Recognizing Insns + +The RTL template is used to define which insns match the particular pattern +and how to find their operands. For named patterns, the RTL template also +says how to construct an insn from specified operands. + +Construction involves substituting specified operands into a copy of the +template. Matching involves determining the values that serve as the +operands in the insn being matched. Both of these activities are +controlled by special expression types that direct matching and +substitution of the operands. + +@table @code +@item (match_operand:@var{m} @var{n} @var{pred} @var{constraint}) +This expression is a placeholder for operand number @var{n} of +the insn. When constructing an insn, operand number @var{n} +will be substituted at this point. When matching an insn, whatever +appears at this position in the insn will be taken as operand +number @var{n}; but it must satisfy @var{pred} or this instruction +pattern will not match at all. + +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. + +@var{pred} is a string that is the name of a C function that accepts +two arguments, an expression and a machine mode. During matching, the +function will be called with the putative operand as the expression +and @var{m} as the mode argument. If it returns zero, this +instruction pattern fails to match. @var{pred} may be an empty +string; then it means no test is to be done on the operand, +so anything which occurs in this position is valid. + +@var{constraint} controls reloading and the choice of the best register +class to use for a value, as explained later (@pxref{Constraints}). + +People are often unclear on the difference between the constraint and the +predicate. The predicate helps decide whether a given insn matches the +pattern. The constraint plays no role in this decision; instead, it +controls various decisions in the case of an insn which does match. + +Most often, @var{pred} is @code{"general_operand"}. This function checks +that the putative operand is either a constant, a register or a memory +reference, and that it is valid for mode @var{m}. + +For an operand that must be a register, @var{pred} should be +@code{"register_operand"}. It would be valid to use +@code{"general_operand"}, since the reload pass would copy any +non-register operands through registers, but this would make GNU CC do +extra work, and it would prevent the register allocator from doing the +best possible job. + +For an operand that must be a constant, either @var{pred} should be +@code{"immediate_operand"}, or the instruction pattern's extra +condition should check for constants, or both. You cannot expect the +constraints to do this work! If the constraints allow only constants, +but the predicate allows something else, the compiler will crash when +that case arises. + +@item (match_dup @var{n}) +This expression is also a placeholder for operand number @var{n}. +It is used when the operand needs to appear more than once in the +insn. + +In construction, @code{match_dup} behaves exactly like +@code{match_operand}: the operand is substituted into the insn being +constructed. But in matching, @code{match_dup} behaves differently. +It assumes that operand number @var{n} has already been determined by +a @code{match_operand} appearing earlier in the recognition template, +and it matches only an identical-looking expression. + +@item (match_operator:@var{m} @var{n} "@var{predicate}" [@var{operands}@dots{}]) +This pattern is a kind of placeholder for a variable RTL expression +code. + +When constructing an insn, it stands for an RTL expression whose +expression code is taken from that of operand @var{n}, and whose +operands are constructed from the patterns @var{operands}. + +When matching an expression, it matches an expression if the function +@var{predicate} returns nonzero on that expression @emph{and} the +patterns @var{operands} match the operands of the expression. + +Suppose that the function @code{commutative_operator} is defined as +follows, to match any expression whose operator is one of the six +commutative arithmetic operators of RTL and whose mode is @var{mode}: + +@example +int +commutative_operator (x, mode) + rtx x; + enum machine_mode mode; +@{ + enum rtx_code code = GET_CODE (x); + if (GET_MODE (x) != mode) + return 0; + return (code == PLUS || code == MULT || code == UMULT + || code == AND || code == IOR || code == XOR); +@} +@end example + +Then the following pattern will match any RTL expression consisting +of a commutative operator applied to two general operands: + +@example +(match_operator:SI 2 "commutative_operator" + [(match_operand:SI 3 "general_operand" "g") + (match_operand:SI 4 "general_operand" "g")]) +@end example + +Here the vector @code{[@var{operands}@dots{}]} contains two patterns +because the expressions to be matched all contain two operands. + +When this pattern does match, the two operands of the commutative +operator are recorded as operands 3 and 4 of the insn. (This is done +by the two instances of @code{match_operand}.) Operand 2 of the insn +will be the entire commutative expression: use @code{GET_CODE +(operands[2])} to see which commutative operator was used. + +The machine mode @var{m} of @code{match_operator} 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. + +When constructing an insn, argument 2 of the gen-function will specify +the operation (i.e. the expression code) for the expression to be +made. It should be an RTL expression, whose expression code is copied +into a new expression whose operands are arguments 3 and 4 of the +gen-function. The subexpressions of argument 2 are not used; +only its expression code matters. + +There is no way to specify constraints in @code{match_operator}. The +operand of the insn which corresponds to the @code{match_operator} +never has any constraints because it is never reloaded as a whole. +However, if parts of its @var{operands} are matched by +@code{match_operand} patterns, those parts may have constraints of +their own. + +@item (address (match_operand:@var{m} @var{n} "address_operand" "")) +This complex of expressions is a placeholder for an operand number +@var{n} in a ``load address'' instruction: an operand which specifies +a memory location in the usual way, but for which the actual operand +value used is the address of the location, not the contents of the +location. + +@code{address} expressions never appear in RTL code, only in machine +descriptions. And they are used only in machine descriptions that do +not use the operand constraint feature. When operand constraints are +in use, the letter @samp{p} in the constraint serves this purpose. + +@var{m} is the machine mode of the @emph{memory location being +addressed}, not the machine mode of the address itself. That mode is +always the same on a given target machine (it is @code{Pmode}, which +normally is @code{SImode}), so there is no point in mentioning it; +thus, no machine mode is written in the @code{address} expression. If +some day support is added for machines in which addresses of different +kinds of objects appear differently or are used differently (such as +the PDP-10), different formats would perhaps need different machine +modes and these modes might be written in the @code{address} +expression. +@end table + +@node Output Template, Output Statement, RTL Template, Machine Desc +@section Output Templates and Operand Substitution + +The @dfn{output template} is a string which specifies how to output the +assembler code for an instruction pattern. Most of the template is a +fixed string which is output literally. The character @samp{%} is used +to specify where to substitute an operand; it can also be used to +identify places where different variants of the assembler require +different syntax. + +In the simplest case, a @samp{%} followed by a digit @var{n} says to output +operand @var{n} at that point in the string. + +@samp{%} followed by a letter and a digit says to output an operand in an +alternate fashion. Four letters have standard, built-in meanings described +below. The machine description macro @code{PRINT_OPERAND} can define +additional letters with nonstandard meanings. + +@samp{%c@var{digit}} can be used to substitute an operand that is a +constant value without the syntax that normally indicates an immediate +operand. + +@samp{%n@var{digit}} is like @samp{%c@var{digit}} except that the value of +the constant is negated before printing. + +@samp{%a@var{digit}} can be used to substitute an operand as if it were a +memory reference, with the actual operand treated as the address. This may +be useful when outputting a ``load address'' instruction, because often the +assembler syntax for such an instruction requires you to write the operand +as if it were a memory reference. + +@samp{%l@var{digit}} is used to substitute a @code{label_ref} into a jump +instruction. + +@samp{%} followed by a punctuation character specifies a substitution that +does not use an operand. Only one case is standard: @samp{%%} outputs a +@samp{%} into the assembler code. Other nonstandard cases can be +defined in the @code{PRINT_OPERAND} macro. You must also define +which punctuation characters are valid with the +@code{PRINT_OPERAND_PUNCT_VALID_P} macro. + +The template may generate multiple assembler instructions. Write the text +for the instructions, with @samp{\;} between them. + +When the RTL contains two operands which are required by constraint to match +each other, the output template must refer only to the lower-numbered operand. +Matching operands are not always identical, and the rest of the compiler +arranges to put the proper RTL expression for printing into the lower-numbered +operand. + +One use of nonstandard letters or punctuation following @samp{%} is to +distinguish between different assembler languages for the same machine; for +example, Motorola syntax versus MIT syntax for the 68000. Motorola syntax +requires periods in most opcode names, while MIT syntax does not. For +example, the opcode @samp{movel} in MIT syntax is @samp{move.l} in Motorola +syntax. The same file of patterns is used for both kinds of output syntax, +but the character sequence @samp{%.} is used in each place where Motorola +syntax wants a period. The @code{PRINT_OPERAND} macro for Motorola syntax +defines the sequence to output a period; the macro for MIT syntax defines +it to do nothing. + +@node Output Statement, Constraints, Output Template, Machine Desc +@section C Statements for Generating Assembler Output + +Often a single fixed template string cannot produce correct and efficient +assembler code for all the cases that are recognized by a single +instruction pattern. For example, the opcodes may depend on the kinds of +operands; or some unfortunate combinations of operands may require extra +machine instructions. + +If the output control string starts with a @samp{*}, then it is not an +output template but rather a piece of C program that should compute a +template. It should execute a @code{return} statement to return the +template-string you want. Most such templates use C string literals, which +require doublequote characters to delimit them. To include these +doublequote characters in the string, prefix each one with @samp{\}. + +The operands may be found in the array @code{operands}, whose C data type +is @code{rtx []}. + +It is possible to output an assembler instruction and then go on to output +or compute more of them, using the subroutine @code{output_asm_insn}. This +receives two arguments: a template-string and a vector of operands. The +vector may be @code{operands}, or it may be another array of @code{rtx} +that you declare locally and initialize yourself. + +When an insn pattern has multiple alternatives in its constraints, often +the appearance of the assembler code is determined mostly by which alternative +was matched. When this is so, the C code can test the variable +@code{which_alternative}, which is the ordinal number of the alternative +that was actually satisfied (0 for the first, 1 for the second alternative, +etc.). + +For example, suppose there are two opcodes for storing zero, @samp{clrreg} +for registers and @samp{clrmem} for memory locations. Here is how +a pattern could use @code{which_alternative} to choose between them: + +@example +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "r,m") + (const_int 0))] + "" + "* + return (which_alternative == 0 + ? \"clrreg %0\" : \"clrmem %0\"); + ") +@end example + +@node Constraints, Standard Names, Output Statement, Machine Desc +@section Operand Constraints + +Each @code{match_operand} in an instruction pattern can specify a +constraint for the type of operands allowed. Constraints can say whether +an operand may be in a register, and which kinds of register; whether the +operand can be a memory reference, and which kinds of address; whether the +operand may be an immediate constant, and which possible values it may +have. Constraints can also require two operands to match. + +@menu +* Simple Constraints:: Basic use of constraints. +* Multi-Alternative:: When an insn has two alternative constraint-patterns. +* Class Preferences:: Constraints guide which hard register to put things in. +* Modifiers:: More precise control over effects of constraints. +* No Constraints:: Describing a clean machine without constraints. +@end menu + +@node Simple Constraints, Multi-Alternative, Constraints, Constraints +@subsection Simple Constraints + +The simplest kind of constraint is a string full of letters, each of +which describes one kind of operand that is permitted. Here are +the letters that are allowed: + +@table @asis +@item @samp{m} +A memory operand is allowed, with any kind of address that the machine +supports in general. + +@item @samp{o} +A memory operand is allowed, but only if the address is +@dfn{offsettable}. This means that adding a small integer (actually, +the width in bytes of the operand, as determined by its machine mode) +may be added to the address and the result is also a valid memory +address. + +For example, an address which is constant is offsettable; so is an +address that is the sum of a register and a constant (as long as a +slightly larger constant is also within the range of address-offsets +supported by the machine); but an autoincrement or autodecrement +address is not offsettable. More complicated indirect/indexed +addresses may or may not be offsettable depending on the other +addressing modes that the machine supports. + +Note that in an output operand which can be matched by another +operand, the constraint letter @samp{o} is valid only when accompanied +by both @samp{<} (if the target machine has predecrement addressing) +and @samp{>} (if the target machine has preincrement addressing). + +When the constraint letter @samp{o} is used, the reload pass may +generate instructions which copy a nonoffsettable address into an index +register. The idea is that the register can be used as a replacement +offsettable address. But this method requires that there be patterns +to copy any kind of address into a register. Auto-increment +and auto-decrement addresses are an exception; there need not be an +instruction that can copy such an address into a register, because +reload handles these cases specially. + +Most older machine designs have ``load address'' instructions which do +just what is needed here. Some RISC machines do not advertise such +instructions, but the possible addresses on these machines are very +limited, so it is easy to fake them. + +@item @samp{<} +A memory operand with autodecrement addressing (either predecrement or +postdecrement) is allowed. + +@item @samp{>} +A memory operand with autoincrement addressing (either preincrement or +postincrement) is allowed. + +@item @samp{r} +A register operand is allowed provided that it is in a general +register. + +@item @samp{d}, @samp{a}, @samp{f}, @dots{} +Other letters can be defined in machine-dependent fashion to stand for +particular classes of registers. @samp{d}, @samp{a} and @samp{f} are +defined on the 68000/68020 to stand for data, address and floating +point registers. + +@item @samp{i} +An immediate integer operand (one with constant value) is allowed. +This includes symbolic constants whose values will be known only at +assembly time. + +@item @samp{n} +An immediate integer operand with a known numeric value is allowed. +Many systems cannot support assembly-time constants for operands less +than a word wide. Constraints for these operands should use @samp{n} +rather than @samp{i}. + +@item @samp{I}, @samp{J}, @samp{K}, @dots{} +Other letters in the range @samp{I} through @samp{M} may be defined in +a machine-dependent fashion to permit immediate integer operands with +explicit integer values in specified ranges. For example, on the +68000, @samp{I} is defined to stand for the range of values 1 to 8. +This is the range permitted as a shift count in the shift +instructions. + +@item @samp{F} +An immediate floating operand (expression code @code{const_double}) is +allowed. + +@item @samp{G}, @samp{H} +@samp{G} and @samp{H} may be defined in a machine-dependent fashion to +permit immediate floating operands in particular ranges of values. + +@item @samp{s} +An immediate integer operand whose value is not an explicit integer is +allowed. + +This might appear strange; if an insn allows a constant operand with a +value not known at compile time, it certainly must allow any known +value. So why use @samp{s} instead of @samp{i}? Sometimes it allows +better code to be generated. + +For example, on the 68000 in a fullword instruction it is possible to +use an immediate operand; but if the immediate value is between -128 +and 127, better code results from loading the value into a register and +using the register. This is because the load into the register can be +done with a @samp{moveq} instruction. We arrange for this to happen +by defining the letter @samp{K} to mean ``any integer outside the +range -128 to 127'', and then specifying @samp{Ks} in the operand +constraints. + +@item @samp{g} +Any register, memory or immediate integer operand is allowed, except for +registers that are not general registers. + +@item @samp{@var{n}} (a digit) +An operand that matches operand number @var{n} is allowed. +If a digit is used together with letters, the digit should come last. + +This is called a @dfn{matching constraint} and what it really means is +that the assembler has only a single operand that fills two roles +considered separate in the RTL insn. For example, an add insn has two +input operands and one output operand in the RTL, but on most machines +an add instruction really has only two operands, one of them an +input-output operand. + +Matching constraints work only in circumstances like that add insn. +More precisely, the matching constraint must appear in an input-only +operand and the operand that it matches must be an output-only operand +with a lower number. Thus, operand @var{n} must have @samp{=} in its +constraint. + +For operands to match in a particular case usually means that they +are identical-looking RTL expressions. But in a few special cases +specific kinds of dissimilarity are allowed. For example, @code{*x} +as an input operand will match @code{*x++} as an output operand. +For proper results in such cases, the output template should always +use the output-operand's number when printing the operand. + +@item @samp{p} +An operand that is a valid memory address is allowed. This is +for ``load address'' and ``push address'' instructions. + +@samp{p} in the constraint must be accompanies by @code{address_operand} +as the predicate in the @code{match_operand}. +@end table + +In order to have valid assembler code, each operand must satisfy +its constraint. But a failure to do so does not prevent the pattern +from applying to an insn. Instead, it directs the compiler to modify +the code so that the constraint will be satisfied. Usually this is +done by copying an operand into a register. + +Contrast, therefore, the two instruction patterns that follow: + +@example +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "r") + (plus:SI (match_dup 0) + (match_operand:SI 1 "general_operand" "r")))] + "" + "@dots{}") +@end example + +@noindent +which has two operands, one of which must appear in two places, and + +@example +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "r") + (plus:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "r")))] + "" + "@dots{}") +@end example + +@noindent +which has three operands, two of which are required by a constraint to be +identical. If we are considering an insn of the form + +@example +(insn @var{n} @var{prev} @var{next} + (set (reg:SI 3) + (plus:SI (reg:SI 6) (reg:SI 109))) + @dots{}) +@end example + +@noindent +the first pattern would not apply at all, because this insn does not +contain two identical subexpressions in the right place. The pattern would +say, ``That does not look like an add instruction; try other patterns.'' +The second pattern would say, ``Yes, that's an add instruction, but there +is something wrong with it.'' It would direct the reload pass of the +compiler to generate additional insns to make the constraint true. The +results might look like this: + +@example +(insn @var{n2} @var{prev} @var{n} + (set (reg:SI 3) (reg:SI 6)) + @dots{}) + +(insn @var{n} @var{n2} @var{next} + (set (reg:SI 3) + (plus:SI (reg:SI 3) (reg:SI 109))) + @dots{}) +@end example + +It is up to you to make sure that each operand, in each pattern, has +constraints that can handle any RTL expression that could be present for +that operand. (When multiple alternatives are in use, each pattern must, +for each possible combination of operand expressions, have at least one +alternative which can handle that combination of operands.) The +constraints don't need to @emph{allow} any possible operand---when this is +the case, they do not constrain---but they must at least point the way to +reloading any possible operand so that it will fit. + +@itemize @bullet +@item +If the constraint accepts whatever operands the predicate permits, +there is no problem: reloading is never necessary for this operand. + +For example, an operand whose constraints permit everything except +registers is safe provided its predicate rejects registers. + +An operand whose predicate accepts only constant values is safe +provided its constraints include the letter @samp{i}. If any possible +constant value is accepted, then nothing less than @samp{i} will do; +if the predicate is more selective, then the constraints may also be +more selective. + +@item +Any operand expression can be reloaded by copying it into a register. +So if an operand's constraints allow some kind of register, it is +certain to be safe. It need not permit all classes of registers; the +compiler knows how to copy a register into another register of the +proper class in order to make an instruction valid. + +@item +A nonoffsettable memory reference can be reloaded by copying the +address into a register. So if the constraint uses the letter +@samp{o}, all memory references are taken care of. + +@item +A constant operand can be reloaded by allocating space in memory to +hold it as preinitialized data. Then the memory reference can be used +in place of the constant. So if the constraint uses the letters +@samp{o} or @samp{m}, constant operands are not a problem. +@end itemize + +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. + +@node Multi-Alternative, Class Preferences, Simple Constraints, Constraints +@subsection Multiple Alternative Constraints + +Sometimes a single instruction has multiple alternative sets of possible +operands. For example, on the 68000, a logical-or instruction can combine +register or an immediate value into memory, or it can combine any kind of +operand into a register; but it cannot combine one memory location into +another. + +These constraints are represented as multiple alternatives. An alternative +can be described by a series of letters for each operand. The overall +constraint for an operand is made from the letters for this operand +from the first alternative, a comma, the letters for this operand from +the second alternative, a comma, and so on until the last alternative. +Here is how it is done for fullword logical-or on the 68000: + +@example +(define_insn "iorsi3" + [(set (match_operand:SI 0 "general_operand" "=m,d") + (ior:SI (match_operand:SI 1 "general_operand" "%0,0") + (match_operand:SI 2 "general_operand" "dKs,dmKs")))] + @dots{}) +@end example + +The first alternative has @samp{m} (memory) for operand 0, @samp{0} for +operand 1 (meaning it must match operand 0), and @samp{dKs} for operand +2. The second alternative has @samp{d} (data register) for operand 0, +@samp{0} for operand 1, and @samp{dmKs} for operand 2. The @samp{=} and +@samp{%} in the constraints apply to all the alternatives; their meaning +is explained in the next section. + +If all the operands fit any one alternative, the instruction is valid. +Otherwise, for each alternative, the compiler counts how many instructions +must be added to copy the operands so that that alternative applies. +The alternative requiring the least copying is chosen. If two alternatives +need the same amount of copying, the one that comes first is chosen. +These choices can be altered with the @samp{?} and @samp{!} characters: + +@table @samp +@item ? +Disparage slightly the alternative that the @samp{?} appears in, +as a choice when no alternative applies exactly. The compiler regards +this alternative as one unit more costly for each @samp{?} that appears +in it. + +@item ! +Disparage severely the alternative that the @samp{!} appears in. +When operands must be copied into registers, the compiler will +never choose this alternative as the one to strive for. +@end table + +When an insn pattern has multiple alternatives in its constraints, often +the appearance of the assembler code is determined mostly by which +alternative was matched. When this is so, the C code for writing the +assembler code can use the variable @code{which_alternative}, which is +the ordinal number of the alternative that was actually satisfied (0 for +the first, 1 for the second alternative, etc.). For example: + +@example +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "r,m") + (const_int 0))] + "" + "* + return (which_alternative == 0 + ? \"clrreg %0\" : \"clrmem %0\"); + ") +@end example + +@node Class Preferences, Modifiers, Multi-Alternative, Constraints +@subsection Register Class Preferences + +The operand constraints have another function: they enable the compiler +to decide which kind of hardware register a pseudo register is best +allocated to. The compiler examines the constraints that apply to the +insns that use the pseudo register, looking for the machine-dependent +letters such as @samp{d} and @samp{a} that specify classes of registers. +The pseudo register is put in whichever class gets the most ``votes''. +The constraint letters @samp{g} and @samp{r} also vote: they vote in +favor of a general register. The machine description says which registers +are considered general. + +Of course, on some machines all registers are equivalent, and no register +classes are defined. Then none of this complexity is relevant. + +@node Modifiers, No Constraints, Class Preferences, Constraints +@subsection Constraint Modifier Characters + +@table @samp +@item = +Means that this operand is write-only for this instruction: the previous +value is discarded and replaced by output data. + +@item + +Means that this operand is both read and written by the instruction. + +When the compiler fixes up the operands to satisfy the constraints, +it needs to know which operands are inputs to the instruction and +which are outputs from it. @samp{=} identifies an output; @samp{+} +identifies an operand that is both input and output; all other operands +are assumed to be input only. + +@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. + +@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. + +@samp{&} does not obviate the need to write @samp{=}. + +@item % +Declares the instruction to be commutative for this operand and the +following operand. This means that the compiler may interchange the +two operands if that is the cheapest way to make all operands fit the +constraints. This is often used in patterns for addition instructions +that really have only two operands: the result must go in one of the +arguments. Here for example, is how the 68000 halfword-add +instruction is defined: + +@example +(define_insn "addhi3" + [(set (match_operand:HI 0 "general_operand" "=m,r") + (plus:HI (match_operand:HI 1 "general_operand" "%0,0") + (match_operand:HI 2 "general_operand" "di,g")))] + @dots{}) +@end example + +Note that in previous versions of GNU CC the @samp{%} constraint +modifier always applied to operands 1 and 2 regardless of which +operand it was written in. The usual custom was to write it in +operand 0. Now it must be in operand 1 if the operands to be +exchanged are 1 and 2. + +@item # +Says that all following characters, up to the next comma, are to be +ignored as a constraint. They are significant only for choosing +register preferences. + +@item * +Says that the following character should be ignored when choosing +register preferences. @samp{*} has no effect on the meaning of the +constraint as a constraint. + +Here is an example: the 68000 has an instruction to sign-extend a +halfword in a data register, and can also sign-extend a value by +copying it into an address register. While either kind of register is +acceptable, the constraints on an address-register destination are +less strict, so it is best if register allocation makes an address +register its goal. Therefore, @samp{*} is used so that the @samp{d} +constraint letter (for data register) is ignored when computing +register preferences. + +@example +(define_insn "extendhisi2" + [(set (match_operand:SI 0 "general_operand" "=*d,a") + (sign_extend:SI + (match_operand:HI 1 "general_operand" "0,g")))] + @dots{}) +@end example +@end table + +@node No Constraints,, Modifiers, Constraints +@subsection Not Using Constraints + +Some machines are so clean that operand constraints are not required. For +example, on the Vax, an operand valid in one context is valid in any other +context. On such a machine, every operand constraint would be @samp{g}, +excepting only operands of ``load address'' instructions which are +written as if they referred to a memory location's contents but actual +refer to its address. They would have constraint @samp{p}. + +For such machines, instead of writing @samp{g} and @samp{p} for all +the constraints, you can choose to write a description with empty constraints. +Then you write @samp{""} for the constraint in every @code{match_operand}. +Address operands are identified by writing an @code{address} expression +around the @code{match_operand}, not by their constraints. + +When the machine description has just empty constraints, certain parts +of compilation are skipped, making the compiler faster. However, +few machines actually do not need constraints; all machine descriptions +now in existence use constraints. + +@node Standard Names, Pattern Ordering, Constraints, Machine Desc +@section Standard Names for Patterns Used in Generation + +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. + +@table @asis +@item @samp{mov@var{m}} +Here @var{m} stands for a two-letter machine mode name, in lower case. +This instruction pattern moves data with that machine mode from operand +1 to operand 0. For example, @samp{movsi} moves full-word data. + +If operand 0 is a @code{subreg} with mode @var{m} of a register whose +own mode is wider than @var{m}, the effect of this instruction is +to store the specified value in the part of the register that corresponds +to mode @var{m}. The effect on the rest of the register is undefined. + +This class of patterns is special in several ways. First of all, each +of these names @emph{must} be defined, because there is no other way +to copy a datum from one place to another. + +Second, these patterns are not used solely in the RTL generation pass. +Even the reload pass can generate move insns to copy values from stack +slots into temporary registers. When it does so, one of the operands is +a hard register and the other is an operand that can need to be reloaded +into a register. + +Therefore, when given such a pair of operands, the pattern must generate +RTL which needs no reloading and needs no temporary registers---no +registers other than the operands. For example, if you support the +pattern with a @code{define_expand}, then in such a case the +@code{define_expand} mustn't call @code{force_reg} or any other such +function which might generate new pseudo registers. + +This requirement exists even for subword modes on a RISC machine where +fetching those modes from memory normally requires several insns and +some temporary registers. Look in @file{spur.md} to see how the +requirement can be satisfied. + +The variety of operands that have reloads depends on the rest of the +machine description, but typically on a RISC machine these can only be +pseudo registers that did not get hard registers, while on other +machines explicit memory references will get optional reloads. + +The constraints on a @samp{move@var{m}} must allow any hard register to +be moved to any other hard register (provided that +@code{HARD_REGNO_MODE_OK} permits mode @var{m} in both registers). + +It is obligatory to support floating point @samp{move@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}} +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 +reload into a floating point register. + +@item @samp{movstrict@var{m}} +Like @samp{mov@var{m}} except that if operand 0 is a @code{subreg} +with mode @var{m} of a register whose natural mode is wider, +the @samp{movstrict@var{m}} instruction is guaranteed not to alter +any of the register except the part which belongs to mode @var{m}. + +@item @samp{add@var{m}3} +Add operand 2 and operand 1, storing the result in operand 0. All operands +must have mode @var{m}. This can be used even on two-address machines, by +means of constraints requiring operands 1 and 0 to be the same location. + +@item @samp{sub@var{m}3}, @samp{mul@var{m}3}, @samp{umul@var{m}3}, @samp{div@var{m}3}, @samp{udiv@var{m}3}, @samp{mod@var{m}3}, @samp{umod@var{m}3}, @samp{and@var{m}3}, @samp{ior@var{m}3}, @samp{xor@var{m}3} +Similar, for other arithmetic operations. + +There are special considerations for register classes for logical-and +instructions, affecting also the macro @code{PREFERRED_RELOAD_CLASS}. +They apply not only to the patterns with these standard names, but to +any patterns that will match such an instruction. @xref{Register +Classes}. + +@item @samp{mulhisi3} +Multiply operands 1 and 2, which have mode @code{HImode}, and store +a @code{SImode} product in operand 0. + +@item @samp{mulqihi3}, @samp{mulsidi3} +Similar widening-multiplication instructions of other widths. + +@item @samp{umulqihi3}, @samp{umulhisi3}, @samp{umulsidi3} +Similar widening-multiplication instructions that do unsigned +multiplication. + +@item @samp{divmod@var{m}4} +Signed division that produces both a quotient and a remainder. +Operand 1 is divided by operand 2 to produce a quotient stored +in operand 0 and a remainder stored in operand 3. + +@item @samp{udivmod@var{m}4} +Similar, but does unsigned division. + +@item @samp{ashl@var{m}3} +Arithmetic-shift operand 1 left by a number of bits specified by +operand 2, and store the result in operand 0. Operand 2 has +mode @code{SImode}, not mode @var{m}. + +@item @samp{ashr@var{m}3}, @samp{lshl@var{m}3}, @samp{lshr@var{m}3}, @samp{rotl@var{m}3}, @samp{rotr@var{m}3} +Other shift and rotate instructions. + +Logical and arithmetic left shift are the same. Machines that do not +allow negative shift counts often have only one instruction for +shifting left. On such machines, you should define a pattern named +@samp{ashl@var{m}3} and leave @samp{lshl@var{m}3} undefined. + +There are special considerations for register classes for shift +instructions, affecting also the macro @code{PREFERRED_RELOAD_CLASS}. +They apply not only to the patterns with these standard names, but to +any patterns that will match such an instruction. @xref{Register +Classes}. + +@item @samp{neg@var{m}2} +Negate operand 1 and store the result in operand 0. + +@item @samp{abs@var{m}2} +Store the absolute value of operand 1 into operand 0. + +@item @samp{sqrt@var{m}2} +Store the square root of operand 1 into operand 0. + +@item @samp{ffs@var{m}2} +Store into operand 0 one plus the index of the least significant 1-bit +of operand 1. If operand 1 is zero, store zero. @var{m} is the mode +of operand 0; operand 1's mode is specified by the instruction +pattern, and the compiler will convert the operand to that mode before +generating the instruction. + +@item @samp{one_cmpl@var{m}2} +Store the bitwise-complement of operand 1 into operand 0. + +@item @samp{cmp@var{m}} +Compare operand 0 and operand 1, and set the condition codes. +The RTL pattern should look like this: + +@example +(set (cc0) (compare (match_operand:@var{m} 0 @dots{}) + (match_operand:@var{m} 1 @dots{}))) +@end example + +Each such definition in the machine description, for integer mode +@var{m}, must have a corresponding @samp{tst@var{m}} pattern, because +optimization can simplify the compare into a test when operand 1 is +zero. + +@item @samp{tst@var{m}} +Compare operand 0 against zero, and set the condition codes. +The RTL pattern should look like this: + +@example +(set (cc0) (match_operand:@var{m} 0 @dots{})) +@end example + +@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}. +The fourth operand is the known shared alignment of the source and +destination, in the form of a @code{const_int} rtx. + +@item @samp{cmpstr@var{m}} +Block compare instruction, with operands like @samp{movstr@var{m}} +except that the two memory blocks are compared byte by byte +in lexicographic order. The effect of the instruction is to set +the condition codes. + +@item @samp{float@var{m}@var{n}2} +Convert signed integer operand 1 (valid for fixed point mode @var{m}) to +floating point mode @var{n} and store in operand 0 (which has mode +@var{n}). + +@item @samp{floatuns@var{m}@var{n}2} +Convert unsigned integer operand 1 (valid for fixed point mode @var{m}) +to floating point mode @var{n} and store in operand 0 (which has mode +@var{n}). + +@item @samp{fix@var{m}@var{n}2} +Convert operand 1 (valid for floating point mode @var{m}) to fixed +point mode @var{n} as a signed number and store in operand 0 (which +has mode @var{n}). This instruction's result is defined only when +the value of operand 1 is an integer. + +@item @samp{fixuns@var{m}@var{n}2} +Convert operand 1 (valid for floating point mode @var{m}) to fixed +point mode @var{n} as an unsigned number and store in operand 0 (which +has mode @var{n}). This instruction's result is defined only when the +value of operand 1 is an integer. + +@item @samp{ftrunc@var{m}2} +Convert operand 1 (valid for floating point mode @var{m}) to an +integer value, still represented in floating point mode @var{m}, and +store it in operand 0 (valid for floating point mode @var{m}). + +@item @samp{fix_trunc@var{m}@var{n}2} +Like @samp{fix@var{m}@var{n}2} but works for any floating point value +of mode @var{m} by converting the value to an integer. + +@item @samp{fixuns_trunc@var{m}@var{n}2} +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. + +@item @samp{trunc@var{m}@var{n}} +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. + +@item @samp{extend@var{m}@var{n}} +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. + +@item @samp{zero_extend@var{m}@var{n}} +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. + +@item @samp{extv} +Extract a bit-field from operand 1 (a register or memory operand), +where operand 2 specifies the width in bits and operand 3 the starting +bit, and store it in operand 0. Operand 0 must have @code{SImode}. +Operand 1 may have mode @code{QImode} or @code{SImode}; often +@code{SImode} is allowed only for registers. Operands 2 and 3 must be +valid for @code{SImode}. + +The RTL generation pass generates this instruction only with constants +for operands 2 and 3. + +The bit-field value is sign-extended to a full word integer +before it is stored in operand 0. + +@item @samp{extzv} +Like @samp{extv} except that the bit-field value is zero-extended. + +@item @samp{insv} +Store operand 3 (which must be valid for @code{SImode}) into a +bit-field in operand 0, where operand 1 specifies the width in bits +and operand 2 the starting bit. Operand 0 may have mode @code{QImode} +or @code{SImode}; often @code{SImode} is allowed only for registers. +Operands 1 and 2 must be valid for @code{SImode}. + +The RTL generation pass generates this instruction only with constants +for operands 1 and 2. + +@item @samp{s@var{cond}} +Store zero or nonzero in the operand according to the condition codes. +Value stored is nonzero iff the condition @var{cond} is true. +@var{cond} is the name of a comparison operation expression code, such +as @code{eq}, @code{lt} or @code{leu}. + +You specify the mode that the operand must have when you write the +@code{match_operand} expression. The compiler automatically sees +which mode you have used and supplies an operand of that mode. + +The value stored for a true condition must have 1 as its low bit, or +else must be negative. Otherwise the instruction is not suitable and +must be omitted from the machine description. You must tell the +compiler exactly which value is stored by defining the macro +@code{STORE_FLAG_VALUE}. + +@item @samp{b@var{cond}} +Conditional branch instruction. Operand 0 is a @code{label_ref} +that refers to the label to jump to. Jump if the condition codes +meet condition @var{cond}. + +@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. + +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 +to put this information into the assembler code; they can put it in +the RTL instead of operand 1. + +Operand 0 should be a @code{mem} RTX whose address is the address of +the function. + +@item @samp{call_value} +Subroutine call instruction returning a value. Operand 0 is the hard +register in which the value is returned. There are three more +operands, the same as the three operands of the @samp{call} +instruction (but with numbers increased by one). + +Subroutines that return @code{BLKmode} objects use the @samp{call} +insn. + +@item @samp{return} +Subroutine return instruction. This instruction pattern name should be +defined only if a single instruction can do all the work of returning +from a function. + +@item @samp{nop} +No-op instruction. This instruction pattern name should always be defined +to output a no-op in assembler code. @code{(const_int 0)} will do as an +RTL pattern. + +@item @samp{casesi} +Instruction to jump through a dispatch table, including bounds checking. +This instruction takes five operands: + +@enumerate +@item +The index to dispatch on, which has mode @code{SImode}. + +@item +The lower bound for indices in the table, an integer constant. + +@item +The total range of indices in the table---the largest index +minus the smallest one (both inclusive). + +@item +A label to jump to if the index has a value outside the bounds. +(If the machine-description macro @code{CASE_DROPS_THROUGH} is defined, +then an out-of-bounds index drops through to the code following +the jump table instead of jumping to this label. In that case, +this label is not actually used by the @samp{casesi} instruction, +but it is always provided as an operand.) + +@item +A label that precedes the table itself. +@end enumerate + +The table is a @code{addr_vec} or @code{addr_diff_vec} inside of a +@code{jump_insn}. The number of elements in the table is one plus the +difference between the upper bound and the lower bound. + +@item @samp{tablejump} +Instruction to jump to a variable address. This is a low-level +capability which can be used to implement a dispatch table when there +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 that counts from the address of the table; otherwise, it is an +absolute address to jump to. + +The @samp{tablejump} insn is always the last insn before the jump +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. +@end table + +@node Pattern Ordering, Dependent Patterns, Standard Names, Machine Desc +@section When the Order of Patterns Matters + +Sometimes an insn can match more than one instruction pattern. Then the +pattern that appears first in the machine description is the one used. +Therefore, more specific patterns (patterns that will match fewer things) +and faster instructions (those that will produce better code when they +do match) should usually go first in the description. + +In some cases the effect of ordering the patterns can be used to hide +a pattern when it is not valid. For example, the 68000 has an +instruction for converting a fullword to floating point and another +for converting a byte to floating point. An instruction converting +an integer to floating point could match either one. We put the +pattern to convert the fullword first to make sure that one will +be used rather than the other. (Otherwise a large integer might +be generated as a single-byte immediate quantity, which would not work.) +Instead of using this pattern ordering it would be possible to make the +pattern for convert-a-byte smart enough to deal properly with any +constant value. + +@node Dependent Patterns, Jump Patterns, Pattern Ordering, Machine Desc +@section Interdependence of Patterns + +Every machine description must have a named pattern for each of the +conditional branch names @samp{b@var{cond}}. The recognition template +must always have the form + +@example +(set (pc) + (if_then_else (@var{cond} (cc0) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc))) +@end example + +@noindent +In addition, every machine description must have an anonymous pattern +for each of the possible reverse-conditional branches. These patterns +look like + +@example +(set (pc) + (if_then_else (@var{cond} (cc0) (const_int 0)) + (pc) + (label_ref (match_operand 0 "" "")))) +@end example + +@noindent +They are necessary because jump optimization can turn direct-conditional +branches into reverse-conditional branches. + +The compiler does more with RTL than just create it from patterns +and recognize the patterns: it can perform arithmetic expression codes +when constant values for their operands can be determined. As a result, +sometimes having one pattern can require other patterns. For example, the +Vax has no `and' instruction, but it has `and not' instructions. Here +is the definition of one of them: + +@example +(define_insn "andcbsi2" + [(set (match_operand:SI 0 "general_operand" "") + (and:SI (match_dup 0) + (not:SI (match_operand:SI + 1 "general_operand" ""))))] + "" + "bicl2 %1,%0") +@end example + +@noindent +If operand 1 is an explicit integer constant, an instruction constructed +using that pattern can be simplified into an `and' like this: + +@example +(set (reg:SI 41) + (and:SI (reg:SI 41) + (const_int 0xffff7fff))) +@end example + +@noindent +(where the integer constant is the one's complement of what +appeared in the original instruction). + +To avoid a fatal error, the compiler must have a pattern that recognizes +such an instruction. Here is what is used: + +@example +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "") + (and:SI (match_dup 0) + (match_operand:SI 1 "general_operand" "")))] + "GET_CODE (operands[1]) == CONST_INT" + "* +@{ operands[1] + = gen_rtx (CONST_INT, VOIDmode, ~INTVAL (operands[1])); + return \"bicl2 %1,%0\"; +@}") +@end example + +@noindent +Whereas a pattern to match a general `and' instruction is impossible to +support on the Vax, this pattern is possible because it matches only a +constant second argument: a special case that can be output as an `and not' +instruction. + +A ``compare'' instruction whose RTL looks like this: + +@example +(set (cc0) (compare @var{operand} (const_int 0))) +@end example + +@noindent +may be simplified by optimization into a ``test'' like this: + +@example +(set (cc0) @var{operand}) +@end example + +@noindent +So in the machine description, each ``compare'' pattern for an integer +mode must have a corresponding ``test'' pattern that will match the +result of such simplification. + +In some cases machines support instructions identical except for the +machine mode of one or more operands. For example, there may be +``sign-extend halfword'' and ``sign-extend byte'' instructions whose +patterns are + +@example +(set (match_operand:SI 0 @dots{}) + (extend:SI (match_operand:HI 1 @dots{}))) + +(set (match_operand:SI 0 @dots{}) + (extend:SI (match_operand:QI 1 @dots{}))) +@end example + +@noindent +Constant integers do not specify a machine mode, so an instruction to +extend a constant value could match either pattern. The pattern it +actually will match is the one that appears first in the file. For correct +results, this must be the one for the widest possible mode (@code{HImode}, +here). If the pattern matches the @code{QImode} instruction, the results +will be incorrect if the constant value does not actually fit that mode. + +Such instructions to extend constants are rarely generated because they are +optimized away, but they do occasionally happen in nonoptimized +compilations. + +When an instruction has the constraint letter @samp{o}, the reload +pass may generate instructions which copy a nonoffsettable address into +an index register. The idea is that the register can be used as a +replacement offsettable address. In order for these generated +instructions to work, there must be patterns to copy any kind of valid +address into a register. + +Most older machine designs have ``load address'' instructions which do +just what is needed here. Some RISC machines do not advertise such +instructions, but the possible addresses on these machines are very +limited, so it is easy to fake them. + +Auto-increment and auto-decrement addresses are an exception; there +need not be an instruction that can copy such an address into a +register, because reload handles these cases in a different manner. + +@node Jump Patterns, Peephole Definitions, Dependent Patterns, Machine Desc +@section Defining Jump Instruction Patterns + +GNU CC assumes that the machine has a condition code. A comparison insn +sets the condition code, recording the results of both signed and unsigned +comparison of the given operands. A separate branch insn tests the +condition code and branches or not according its value. The branch insns +come in distinct signed and unsigned flavors. Many common machines, such +as the Vax, the 68000 and the 32000, work this way. + +Some machines have distinct signed and unsigned compare instructions, and +only one set of conditional branch instructions. The easiest way to handle +these machines is to treat them just like the others until the final stage +where assembly code is written. At this time, when outputting code for the +compare instruction, peek ahead at the following branch using +@code{NEXT_INSN (insn)}. (The variable @code{insn} refers to the insn +being output, in the output-writing code in an instruction pattern.) If +the RTL says that is an unsigned branch, output an unsigned compare; +otherwise output a signed compare. When the branch itself is output, you +can treat signed and unsigned branches identically. + +The reason you can do this is that GNU CC always generates a pair of +consecutive RTL insns, one to set the condition code and one to test it, +and keeps the pair inviolate until the end. + +To go with this technique, you must define the machine-description macro +@code{NOTICE_UPDATE_CC} to do @code{CC_STATUS_INIT}; in other words, no +compare instruction is superfluous. + +Some machines have compare-and-branch instructions and no condition code. +A similar technique works for them. When it is time to ``output'' a +compare instruction, record its operands in two static variables. When +outputting the branch-on-condition-code instruction that follows, actually +output a compare-and-branch instruction that uses the remembered operands. + +It also works to define patterns for compare-and-branch instructions. +In optimizing compilation, the pair of compare and branch instructions +will be combined according to these patterns. But this does not happen +if optimization is not requested. So you must use one of the solutions +above in addition to any special patterns you define. + +@node Peephole Definitions, Expander Definitions, Jump Patterns, Machine Desc +@section Defining Machine-Specific Peephole Optimizers + +In addition to instruction patterns the @file{md} file may contain +definitions of machine-specific peephole optimizations. + +The combiner does not notice certain peephole optimizations when the data +flow in the program does not suggest that it should try them. For example, +sometimes two consecutive insns related in purpose can be combined even +though the second one does not appear to use a register computed in the +first one. A machine-specific peephole optimizer can detect such +opportunities. + +A definition looks like this: + +@example +(define_peephole + [@var{insn-pattern-1} + @var{insn-pattern-2} + @dots{}] + "@var{condition}" + "@var{template}" + "@var{machine-specific info}") +@end example + +@noindent +The last string operand may be omitted if you are not using any +machine-specific information in this machine description. If present, +it must obey the same rules as in a @code{define_insn}. + +In this skeleton, @var{insn-pattern-1} and so on are patterns to match +consecutive insns. The optimization applies to a sequence of insns when +@var{insn-pattern-1} matches the first one, @var{insn-pattern-2} matches +the next, and so on.@refill + +Each of the insns matched by a peephole must also match a +@code{define_insn}. Peepholes are checked only at the last stage just +before code generation, and only optionally. Therefore, any insn which +would match a peephole but no @code{define_insn} will cause a crash in code +generation in an unoptimized compilation, or at various optimization +stages. + +The operands of the insns are matched with @code{match_operands} and +@code{match_dup}, as usual. What is not usual is that the operand numbers +apply to all the insn patterns in the definition. So, you can check for +identical operands in two insns by using @code{match_operand} in one insn +and @code{match_dup} in the other. + +The operand constraints used in @code{match_operand} patterns do not have +any direct effect on the applicability of the peephole, but they will +be validated afterward, so make sure your constraints are general enough +to apply whenever the peephole matches. If the peephole matches +but the constraints are not satisfied, the compiler will crash. + +It is safe to omit constraints in all the operands of the peephole; or +you can write constraints which serve as a double-check on the criteria +previously tested. + +Once a sequence of insns matches the patterns, the @var{condition} is +checked. This is a C expression which makes the final decision whether to +perform the optimization (we do so if the expression is nonzero). If +@var{condition} is omitted (in other words, the string is empty) then the +optimization is applied to every sequence of insns that matches the +patterns. + +The defined peephole optimizations are applied after register allocation +is complete. Therefore, the peephole definition can check which +operands have ended up in which kinds of registers, just by looking at +the operands. + +The way to refer to the operands in @var{condition} is to write +@code{operands[@var{i}]} for operand number @var{i} (as matched by +@code{(match_operand @var{i} @dots{})}). Use the variable @code{insn} to +refer to the last of the insns being matched; use @code{PREV_INSN} to find +the preceding insns (but be careful to skip over any @code{note} insns that +intervene).@refill + +When optimizing computations with intermediate results, you can use +@var{condition} to match only when the intermediate results are not used +elsewhere. Use the C expression @code{dead_or_set_p (@var{insn}, +@var{op})}, where @var{insn} is the insn in which you expect the value to +be used for the last time (from the value of @code{insn}, together with use +of @code{PREV_INSN}), and @var{op} is the intermediate value (from +@code{operands[@var{i}]}).@refill + +Applying the optimization means replacing the sequence of insns with one +new insn. The @var{template} controls ultimate output of assembler code +for this combined insn. It works exactly like the template of a +@code{define_insn}. Operand numbers in this template are the same ones +used in matching the original sequence of insns. + +The result of a defined peephole optimizer does not need to match any of +the insn patterns in the machine description; it does not even have an +opportunity to match them. The peephole optimizer definition itself serves +as the insn pattern to control how the insn is output. + +Defined peephole optimizers are run as assembler code is being output, +so the insns they produce are never combined or rearranged in any way. + +Here is an example, taken from the 68000 machine description: + +@example +(define_peephole + [(set (reg:SI 15) (plus:SI (reg:SI 15) (const_int 4))) + (set (match_operand:DF 0 "register_operand" "f") + (match_operand:DF 1 "register_operand" "ad"))] + "FP_REG_P (operands[0]) && ! FP_REG_P (operands[1])" + "* +@{ + rtx xoperands[2]; + xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1); +#ifdef MOTOROLA + output_asm_insn (\"move.l %1,(sp)\", xoperands); + output_asm_insn (\"move.l %1,-(sp)\", operands); + return \"fmove.d (sp)+,%0\"; +#else + output_asm_insn (\"movel %1,sp@@\", xoperands); + output_asm_insn (\"movel %1,sp@@-\", operands); + return \"fmoved sp@@+,%0\"; +#endif +@} +") +@end example + +The effect of this optimization is to change + +@example +jbsr _foobar +addql #4,sp +movel d1,sp@@- +movel d0,sp@@- +fmoved sp@@+,fp0 +@end example + +@noindent +into + +@example +jbsr _foobar +movel d1,sp@@ +movel d0,sp@@- +fmoved sp@@+,fp0 +@end example + +@ignore +If a peephole matches a sequence including one or more jump insns, you must +take account of the flags such as @code{CC_REVERSED} which specify that the +condition codes are represented in an unusual manner. The compiler +automatically alters any ordinary conditional jumps which occur in such +situations, but the compiler cannot alter jumps which have been replaced by +peephole optimizations. So it is up to you to alter the assembler code +that the peephole produces. Supply C code to write the assembler output, +and in this C code check the condition code status flags and change the +assembler code as appropriate. +@end ignore + +@var{insn-pattern-1} and so on look @emph{almost} like the second +operand of @code{define_insn}. There is one important difference: the +second operand of @code{define_insn} consists of one or more RTX's +enclosed in square brackets. Usually, there is only one: then the same +action can be written as an element of a @code{define_peephole}. But +when there are multiple actions in a @code{define_insn}, they are +implicitly enclosed in a @code{parallel}. Then you must explicitly +write the @code{parallel}, and the square brackets within it, in the +@code{define_peephole}. Thus, if an insn pattern looks like this, + +@example +(define_insn "divmodsi4" + [(set (match_operand:SI 0 "general_operand" "=d") + (div:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "dmsK"))) + (set (match_operand:SI 3 "general_operand" "=d") + (mod:SI (match_dup 1) (match_dup 2)))] + "TARGET_68020" + "divsl%.l %2,%3:%0") +@end example + +@noindent +then the way to mention this insn in a peephole is as follows: + +@example +(define_peephole + [@dots{} + (parallel + [(set (match_operand:SI 0 "general_operand" "=d") + (div:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "dmsK"))) + (set (match_operand:SI 3 "general_operand" "=d") + (mod:SI (match_dup 1) (match_dup 2)))]) + @dots{}] + @dots{}) +@end example + +@node Expander Definitions,, Peephole Definitions, Machine Desc +@section Defining RTL Sequences for Code Generation + +On some target machines, some standard pattern names for RTL generation +cannot be handled with single insn, but a sequence of RTL insns can +represent them. For these target machines, you can write a +@code{define_expand} to specify how to generate the sequence of RTL. + +A @code{define_expand} is an RTL expression that looks almost like a +@code{define_insn}; but, unlike the latter, a @code{define_expand} is used +only for RTL generation and it can produce more than one RTL insn. + +A @code{define_expand} RTX has four operands: + +@itemize @bullet +@item +The name. Each @code{define_expand} must have a name, since the only +use for it is to refer to it by name. + +@item +The RTL template. This is just like the RTL template for a +@code{define_peephole} in that it is a vector of RTL expressions +each being one insn. + +@item +The condition, a string containing a C expression. This expression is +used to express how the availability of this pattern depends on +subclasses of target machine, selected by command-line options when +GNU CC is run. This is just like the condition of a +@code{define_insn} that has a standard name. + +@item +The preparation statements, a string containing zero or more C +statements which are to be executed before RTL code is generated from +the RTL template. + +Usually these statements prepare temporary registers for use as +internal operands in the RTL template, but they can also generate RTL +insns directly by calling routines such as @code{emit_insn}, etc. +Any such insns precede the ones that come from the RTL template. +@end itemize + +Every RTL insn emitted by a @code{define_expand} must match some +@code{define_insn} in the machine description. Otherwise, the compiler +will crash when trying to generate code for the insn or trying to optimize +it. + +The RTL template, in addition to controlling generation of RTL insns, +also describes the operands that need to be specified when this pattern +is used. In particular, it gives a predicate for each operand. + +A true operand, which need to be specified in order to generate RTL from +the pattern, should be described with a @code{match_operand} in its first +occurrence in the RTL template. This enters information on the operand's +predicate into the tables that record such things. GNU CC uses the +information to preload the operand into a register if that is required for +valid RTL code. If the operand is referred to more than once, subsequent +references should use @code{match_dup}. + +The RTL template may also refer to internal ``operands'' which are +temporary registers or labels used only within the sequence made by the +@code{define_expand}. Internal operands are substituted into the RTL +template with @code{match_dup}, never with @code{match_operand}. The +values of the internal operands are not passed in as arguments by the +compiler when it requests use of this pattern. Instead, they are computed +within the pattern, in the preparation statements. These statements +compute the values and store them into the appropriate elements of +@code{operands} so that @code{match_dup} can find them. + +There are two special macros defined for use in the preparation statements: +@code{DONE} and @code{FAIL}. Use them with a following semicolon, +as a statement. + +@table @code +@item DONE +Use the @code{DONE} macro to end RTL generation for the pattern. The +only RTL insns resulting from the pattern on this occasion will be +those already emitted by explicit calls to @code{emit_insn} within the +preparation statements; the RTL template will not be generated. + +@item FAIL +Make the pattern fail on this occasion. When a pattern fails, it means +that the pattern was not truly available. The calling routines in the +compiler will try other strategies for code generation using other patterns. + +Failure is currently supported only for binary operations (addition, +multiplication, shifting, etc.). + +Do not emit any insns explicitly with @code{emit_insn} before failing. +@end table + +Here is an example, the definition of left-shift for the SPUR chip: + +@example +(define_expand "ashlsi3" + [(set (match_operand:SI 0 "register_operand" "") + (ashift:SI + (match_operand:SI 1 "register_operand" "") + (match_operand:SI 2 "nonmemory_operand" "")))] + "" + " +@{ + if (GET_CODE (operands[2]) != CONST_INT + || (unsigned) INTVAL (operands[2]) > 3) + FAIL; +@}") +@end example + +@noindent +This example uses @code{define_expand} so that it can generate an RTL insn +for shifting when the shift-count is in the supported range of 0 to 3 but +fail in other cases where machine insns aren't available. When it fails, +the compiler tries another strategy using different patterns (such as, a +library call). + +If the compiler were able to handle nontrivial condition-strings in +patterns with names, then it would be possible to use a +@code{define_insn} in that case. Here is another case (zero-extension +on the 68000) which makes more use of the power of @code{define_expand}: + +@example +(define_expand "zero_extendhisi2" + [(set (match_operand:SI 0 "general_operand" "") + (const_int 0)) + (set (strict_low_part + (subreg:HI + (match_dup 0) + 0)) + (match_operand:HI 1 "general_operand" ""))] + "" + "operands[1] = make_safe_from (operands[1], operands[0]);") +@end example + +@noindent +Here two RTL insns are generated, one to clear the entire output operand +and the other to copy the input operand into its low half. This sequence +is incorrect if the input operand refers to [the old value of] the output +operand, so the preparation statement makes sure this isn't so. The +function @code{make_safe_from} copies the @code{operands[1]} into a +temporary register if it refers to @code{operands[0]}. It does this +by emitting another RTL insn. + +Finally, a third example shows the use of an internal operand. +Zero-extension on the SPUR chip is done by @code{and}-ing the result +against a halfword mask. But this mask cannot be represented by a +@code{const_int} because the constant value is too large to be legitimate +on this machine. So it must be copied into a register with +@code{force_reg} and then the register used in the @code{and}. + +@example +(define_expand "zero_extendhisi2" + [(set (match_operand:SI 0 "register_operand" "") + (and:SI (subreg:SI + (match_operand:HI 1 "register_operand" "") + 0) + (match_dup 2)))] + "" + "operands[2] + = force_reg (SImode, gen_rtx (CONST_INT, + VOIDmode, 65535)); ") +@end example + +@strong{Note:} If the @code{define_expand} is used to serve a standard +binary or unary arithmetic operation, then the last insn it generates +must not be a @code{code_label}, @code{barrier} or @code{note}. It must +be an @code{insn}, @code{jump_insn} or @code{call_insn}. + +@node Machine Macros, Config, Machine Desc, Top +@chapter Machine Description Macros + +The other half of the machine description is a C header file conventionally +given the name @file{tm-@var{machine}.h}. The file @file{tm.h} should be a +link to it. The header file @file{config.h} includes @file{tm.h} and most +compiler source files include @file{config.h}. + +@menu +* Run-time Target:: Defining @samp{-m} options like @samp{-m68000} and @samp{-m68020}. +* Storage Layout:: Defining sizes and alignments of data types. +* Registers:: Naming and describing the hardware registers. +* Register Classes:: Defining the classes of hardware registers. +* Stack Layout:: Defining which way the stack grows and by how much. +* Library Calls:: Specifying how to call certain library routines. +* Addressing Modes:: Defining addressing modes valid for memory operands. +* Delayed Branch:: Do branches execute the following instruction? +* Condition Code:: Defining how insns update the condition code. +* Cross-compilation:: Handling floating point for cross-compilers. +* Misc:: Everything else. +* Assembler Format:: Defining how to write insns and pseudo-ops to output. +@end menu + +@node Run-time Target, Storage Layout, Machine Macros, Machine Macros +@section Run-time Target Specification + +@table @code +@item CPP_PREDEFINES +Define this to be a string constant containing @samp{-D} options to +define the predefined macros that identify this machine and system. +These macros will be predefined unless the @samp{-ansi} option is +specified. + +In addition, a parallel set of macros are predefined, whose names are +made by appending @samp{__} at the beginning and at the end. These +@samp{__} macros are permitted by the ANSI standard, so they are +predefined regardless of whether @samp{-ansi} is specified. + +For example, on the Sun, one can use the following value: + +@example +"-Dmc68000 -Dsun -Dunix" +@end example + +The result is to define the macros @code{__mc68000__}, @code{__sun__} +and @code{__unix__} unconditionally, and the macros @code{mc68000}, +@code{sun} and @code{unix} provided @samp{-ansi} is not specified. + +@item CPP_SPEC +A C string constant that tells the GNU CC driver program options to +pass to CPP. It can also specify how to translate options you +give to GNU CC into options for GNU CC to pass to the CPP. + +Do not define this macro if it does not need to do anything. + +@item CC1_SPEC +A C string constant that tells the GNU CC driver program options to +pass to CC1. It can also specify how to translate options you +give to GNU CC into options for GNU CC to pass to the CC1. + +Do not define this macro if it does not need to do anything. + +@item extern int target_flags; +This declaration should be present. + +@item TARGET_@dots{} +This series of macros is to allow compiler command arguments to +enable or disable the use of optional features of the target machine. +For example, one machine description serves both the 68000 and +the 68020; a command argument tells the compiler whether it should +use 68020-only instructions or not. This command argument works +by means of a macro @code{TARGET_68020} that tests a bit in +@code{target_flags}. + +Define a macro @code{TARGET_@var{featurename}} for each such option. +Its definition should test a bit in @code{target_flags}; for example: + +@example +#define TARGET_68020 (target_flags & 1) +@end example + +One place where these macros are used is in the condition-expressions +of instruction patterns. Note how @code{TARGET_68020} appears +frequently in the 68000 machine description file, @file{m68k.md}. +Another place they are used is in the definitions of the other +macros in the @file{tm-@var{machine}.h} file. + +@item TARGET_SWITCHES +This macro defines names of command options to set and clear +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. + +One of the subgroupings should have a null string. The number in +this grouping is the default value for @code{target_flags}. Any +target options act starting with that value. + +Here is an example which defines @samp{-m68000} and @samp{-m68020} +with opposite meanings, and picks the latter as the default: + +@example +#define TARGET_SWITCHES \ + @{ @{ "68020", 1@}, \ + @{ "68000", -1@}, \ + @{ "", 1@}@} +@end example + +@item OVERRIDE_OPTIONS +Sometimes certain combinations of command options do not make sense on +a particular target machine. You can define a macro +@code{OVERRIDE_OPTIONS} to take account of this. This macro, if +defined, is executed once just after all the command options have been +parsed. +@end table + +@node Storage Layout, Registers, Run-time Target, Machine Macros +@section Storage Layout + +Note that the definitions of the macros in this table which are sizes or +alignments measured in bits do not need to be constant. They can be C +expressions that refer to static variables, such as the @code{target_flags}. +@xref{Run-time Target}. + +@table @code +@item BITS_BIG_ENDIAN +Define this macro if the most significant bit in a byte has the lowest +number. This means that bit-field instructions count from the most +significant bit. If the machine has no bit-field instructions, this +macro is irrelevant. + +This macro does not affect the way structure fields are packed into +bytes or words; that is controlled by @code{BYTES_BIG_ENDIAN}. + +@item BYTES_BIG_ENDIAN +Define this macro if the most significant byte in a word has the +lowest number. + +@item WORDS_BIG_ENDIAN +Define this macro if, in a multiword object, the most significant +word has the lowest number. + +@item BITS_PER_UNIT +Number of bits in an addressable storage unit (byte); normally 8. + +@item BITS_PER_WORD +Number of bits in a word; normally 32. + +@item UNITS_PER_WORD +Number of storage units in a word; normally 4. + +@item POINTER_SIZE +Width of a pointer, in bits. + +@item POINTER_BOUNDARY +Alignment required for pointers stored in memory, in bits. + +@item PARM_BOUNDARY +Normal alignment required for function parameters on the stack, in +bits. All stack parameters receive least this much alignment +regardless of data type. On most machines, this is the same as the +size of an integer. + +@item MAX_PARM_BOUNDARY +Largest alignment required for any stack parameters, in bits. If the +data type of the parameter calls for more alignment than +@code{PARM_BOUNDARY}, then it is given extra padding up to this limit. + +Don't define this macro if it would be equal to @code{PARM_BOUNDARY}; +in other words, if the alignment of a stack parameter should not +depend on its data type (as is the case on most machines). + +@item STACK_BOUNDARY +Define this macro if you wish to preserve a certain alignment for +the stack pointer at all times. The definition is a C expression +for the desired alignment (measured in bits). + +@item FUNCTION_BOUNDARY +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. + +@item CONSTANT_ALIGNMENT (@var{code}, @var{typealign}) +A C expression to compute the alignment for a constant. The argument +@var{typealign} is the alignment required for the constant's data type. +@var{code} is the tree code of the constant itself. + +If this macro is not defined, the default is to use @var{typealign}. If +you do define this macro, the value must be a multiple of +@var{typealign}. + +The purpose of defining this macro is usually to cause string constants +to be word aligned so that @file{dhrystone} can be made to run faster. + +@item EMPTY_FIELD_BOUNDARY +Alignment in bits to be given to a structure bit field that follows an +empty field such as @code{int : 0;}. + +@item STRUCTURE_SIZE_BOUNDARY +Number of bits which any structure or union's size must be a multiple of. +Each structure or union's size is rounded up to a multiple of this. + +If you do not define this macro, the default is the same as +@code{BITS_PER_UNIT}. + +@item STRICT_ALIGNMENT +Define this if instructions will fail to work if given data not +on the nominal alignment. If instructions will merely go slower +in that case, do not define this macro. + +@item PCC_BITFIELD_TYPE_MATTERS +Define this if you wish to imitate a certain bizarre behavior pattern +of some instances of PCC: a bit field whose declared type is +@code{int} has the same effect on the size and alignment of a +structure as an actual @code{int} would have. + +If the macro is defined, then its definition should be a C expression; +a nonzero value for the expression enables PCC-compatible behavior. + +Just what effect that is in GNU CC depends on other parameters, but on +most machines it would force the structure's alignment and size to a +multiple of 32 or @code{BIGGEST_ALIGNMENT} bits. + +@item MAX_FIXED_MODE_SIZE +An integer expression for the largest integer machine mode that should +actually be used. All integer machine modes of this size or smaller +can be used for structures and unions with the appropriate sizes. + +@item CHECK_FLOAT_VALUE (@var{mode}, @var{value}) +A C statement to validate the value @var{value} (or type +@code{double}) for mode @var{mode}. This means that you check whether +@var{value} fits within the possible range of values for mode +@var{mode} on this target machine. The mode @var{mode} is always +@code{SFmode} or @code{DFmode}. + +If @var{value} is not valid, you should call @code{error} to print an +error message and then assign some valid value to @var{value}. +Allowing an invalid value to go through the compiler can produce +incorrect assembler code which may even cause Unix assemblers to +crash. + +This macro need not be defined if there is no work for it to do. +@end table + +@node Registers, Register Classes, Storage Layout, Machine Macros +@section Register Usage + +@table @code +@item FIRST_PSEUDO_REGISTER +Number of hardware registers known to the compiler. They receive +numbers 0 through @code{FIRST_PSEUDO_REGISTER-1}; thus, the first +pseudo register's number really is assigned the number +@code{FIRST_PSEUDO_REGISTER}. + +@item FIXED_REGISTERS +An initializer that says which registers are used for fixed purposes +all throughout the compiled code and are therefore not available for +general allocation. These would include the stack pointer, the frame +pointer (except on machines where that can be used as a general +register when no frame pointer is needed), the program counter on +machines where that is considered one of the addressable registers, +and any other numbered register with a standard use. + +This information is expressed as a sequence of numbers, separated by +commas and surrounded by braces. The @var{n}th number is 1 if +register @var{n} is fixed, 0 otherwise. + +The table initialized from this macro, and the table initialized by +the following one, may be overridden at run time either automatically, +by the actions of the macro @code{CONDITIONAL_REGISTER_USAGE}, or by +the user with the command options @samp{-ffixed-@var{reg}}, +@samp{-fcall-used-@var{reg}} and @samp{-fcall-saved-@var{reg}}. + +@item CALL_USED_REGISTERS +Like @code{FIXED_REGISTERS} but has 1 for each register that is +clobbered (in general) by function calls as well as for fixed +registers. This macro therefore identifies the registers that are not +available for general allocation of values that must live across +function calls. + +If a register has 0 in @code{CALL_USED_REGISTERS}, the compiler +automatically saves it on function entry and restores it on function +exit, if the register is used within the function. + +@item DEFAULT_CALLER_SAVES +Define this macro if function calls on the target machine do not preserve +any registers; in other words, if @code{CALL_USED_REGISTERS} has 1 +for all registers. This macro enables @samp{-fcaller-saves} by default. +Eventually that option will be enabled by default on all machines and both +the option and this macro will be eliminated. + +@item CONDITIONAL_REGISTER_USAGE +Zero or more C statements that may conditionally modify two variables +@code{fixed_regs} and @code{call_used_regs} (both of type @code{char +[]}) after they have been initialized from the two preceding macros. + +This is necessary in case the fixed or call-clobbered registers depend +on target flags. + +You need not define this macro if it has no work to do. + +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 +registers in the classes which should not be used by GCC. Also define +the macro @code{REG_CLASS_FROM_LETTER} to return @code{NO_REGS} if it +is called with a letter for a class that shouldn't be used. + +(However, if this class is not included in @code{GENERAL_REGS} and all +of the insn patterns whose constraints permit this class are +controlled by target switches, then GCC will automatically avoid using +these registers when the target switches are opposed to them.) + +@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 +hard register which overlaps a hard register with a different number. +(Such overlap is undesirable, but occasionally it allows a machine to +be supported which otherwise could not be.) This macro must return +nonzero for @emph{all} the registers which overlap each other. GNU CC +can use an overlapping register only in certain limited ways. It can +be used for allocation within a basic block, and may be spilled for +reloading; that is all. + +If this macro is not defined, it means that none of the hard registers +overlap each other. This is the usual situation. + +@item INSN_CLOBBERS_REGNO_P (@var{insn}, @var{regno}) +If defined, this is a C expression whose value should be nonzero if +the insn @var{insn} has the effect of mysteriously clobbering the +contents of hard register number @var{regno}. By ``mysterious'' we +mean that the insn's RTL expression doesn't describe such an effect. + +If this macro is not defined, it means that no insn clobbers registers +mysteriously. This is the usual situation; all else being equal, +it is best for the RTL expression to show all the activity. + +@item PRESERVE_DEATH_INFO_REGNO_P (@var{regno}) +If defined, this is a C expression whose value is nonzero if accurate +@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. + +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 +code looks at the death notes. This is necessary only when the actual +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.) + +If this macro is not defined, it means that no death notes need to be +preserved. This is the usual situation. + +@item HARD_REGNO_NREGS (@var{regno}, @var{mode}) +A C expression for the number of consecutive hard registers, starting +at register number @var{regno}, required to hold a value of mode +@var{mode}. + +On a machine where all registers are exactly one word, a suitable +definition of this macro is + +@example +#define HARD_REGNO_NREGS(REGNO, MODE) \ + ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) \ + / UNITS_PER_WORD)) +@end example + +@item HARD_REGNO_MODE_OK (@var{regno}, @var{mode}) +A C expression that is nonzero if it is permissible to store a value +of mode @var{mode} in hard register number @var{regno} (or in several +registers starting with that one). For a machine where all registers +are equivalent, a suitable definition is + +@example +#define HARD_REGNO_MODE_OK(REGNO, MODE) 1 +@end example + +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. + +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. + +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. + +Many machines have special registers for floating point arithmetic. +Often people assume that floating point machine modes are allowed only +in floating point registers. This is not true. Any registers that +can hold integers can safely @emph{hold} a floating point machine +mode, whether or not floating arithmetic can be done on it in those +registers. + +On some machines, though, the converse is true: fixed-point machine +modes may not go in floating registers. This is true if the floating +registers normalize any value stored in them, because storing a +non-floating value there would garble it. In this case, +@code{HARD_REGNO_MODE_OK} should reject fixed-point machine modes in +floating registers. But if the floating registers do not automatically +normalize, if you can store any bit pattern in one and retrieve it +unchanged without a trap, then any machine mode may go in a floating +register and this macro should say so. + +The primary significance of special floating registers is rather that +they are the registers acceptable in floating point arithmetic +instructions. However, this is of no concern to +@code{HARD_REGNO_MODE_OK}. You handle it by writing the proper +constraints for those instructions. + +On some machines, the floating registers are especially slow to access, +so that it is better to store a value in a stack frame than in such a +register if floating point arithmetic is not being done. As long as the +floating registers are not in class @code{GENERAL_REGS}, they will not +be used unless some insn's constraint asks for one. + +@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}. + +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. + +@item PC_REGNUM +If the program counter has a register number, define this as that +register number. Otherwise, do not define it. + +@item STACK_POINTER_REGNUM +The register number of the stack pointer register, which must also be +a fixed register according to @code{FIXED_REGISTERS}. On many +machines, the hardware determines which register this is. + +@item FRAME_POINTER_REGNUM +The register number of the frame pointer register, which is used to +access automatic variables in the stack frame. On some machines, the +hardware determines which register this is. On other machines, you +can choose any register you wish for this purpose. + +@item FRAME_POINTER_REQUIRED +A C expression which is nonzero if a function must have and use a frame +pointer. This expression is evaluated twice: at the beginning of +generating RTL, and in the reload pass. If its value is nonzero at +either time, then the function will have a frame pointer. + +The expression can in principle examine the current function and decide +according to the facts, but on most machines the constant 0 or the +constant 1 suffices. Use 0 when the machine allows code to be generated +with no frame pointer, and doing so saves some time or space. Use 1 +when there is no possible advantage to avoiding a frame pointer. + +In certain cases, the compiler does not know how to produce valid code +without a frame pointer. The compiler recognizes those cases and +automatically gives the function a frame pointer regardless of what +@code{FRAME_POINTER_REQUIRED} says. You don't need to worry about +them.@refill + +In a function that does not require a frame pointer, the frame pointer +register can be allocated for ordinary usage, unless you mark it as a +fixed register. See @code{FIXED_REGISTERS} for more information. + +@item ARG_POINTER_REGNUM +The register number of the arg pointer register, which is used to +access the function's argument list. On some machines, this is the +same as the frame pointer register. On some machines, the hardware +determines which register this is. On other machines, you can choose +any register you wish for this purpose. If this is not the same +register as the frame pointer register, then you must mark it as a +fixed register according to @code{FIXED_REGISTERS}. + +@item STATIC_CHAIN_REGNUM +The register number used for passing a function's static chain +pointer. This is needed for languages such as Pascal and Algol where +functions defined within other functions can access the local +variables of the outer functions; it is not currently used because C +does not provide this feature, but you must define the macro. + +The static chain register need not be a fixed register. + +@item STRUCT_VALUE_REGNUM +When a function's value's mode is @code{BLKmode}, the value is not +returned according to @code{FUNCTION_VALUE}. Instead, the caller +passes the address of a block of memory in which the value should be +stored. + +If this value is passed in a register, then @code{STRUCT_VALUE_REGNUM} +should be the number of that register. + +@item STRUCT_VALUE +If the structure value address is not passed in a register, define +@code{STRUCT_VALUE} as an expression returning an RTX for the place +where the address is passed. If it returns a @code{mem} RTX, the +address is passed as an ``invisible'' first argument. + +@item STRUCT_VALUE_INCOMING_REGNUM +On some architectures the place where the structure value address +is found by the called function is not the same place that the +caller put it. This can be due to register windows, or it could +be because the function prologue moves it to a different place. + +If the incoming location of the structure value address is in a +register, define this macro as the register number. + +@item STRUCT_VALUE_INCOMING +If the incoming location is not a register, define +@code{STRUCT_VALUE_INCOMING} as an expression for an RTX for where the +called function should find the value. If it should find the value on +the stack, define this to create a @code{mem} which refers to the +frame pointer. If the value is a @code{mem}, the compiler assumes it +is for an invisible first argument, and leaves space for it when +finding the first real argument. + +@item REG_ALLOC_ORDER +If defined, an initializer for a vector of integers, containing the +numbers of hard registers in the order in which the GNU CC should +prefer to use them (from most preferred to least). + +If this macro is not defined, registers are used lowest numbered first +(all else being equal). + +One use of this macro is on the 360, where the highest numbered +registers must always be saved and the save-multiple-registers +instruction supports only sequences of consecutive registers. This +macro is defined to cause the highest numbered allocatable registers +to be used first. +@end table + +@node Register Classes, Stack Layout, Registers, Machine Macros +@section Register Classes + +On many machines, the numbered registers are not all equivalent. +For example, certain registers may not be allowed for indexed addressing; +certain registers may not be allowed in some instructions. These machine +restrictions are described to the compiler using @dfn{register classes}. + +You define a number of register classes, giving each one a name and saying +which of the registers belong to it. Then you can specify register classes +that are allowed as operands to particular instruction patterns. + +In general, each register will belong to several classes. In fact, one +class must be named @code{ALL_REGS} and contain all the registers. Another +class must be named @code{NO_REGS} and contain no registers. Often the +union of two classes will be another class; however, this is not required. + +One of the classes must be named @code{GENERAL_REGS}. There is nothing +terribly special about the name, but the operand constraint letters +@samp{r} and @samp{g} specify this class. If @code{GENERAL_REGS} is +the same as @code{ALL_REGS}, just define it as a macro which expands +to @code{ALL_REGS}. + +The way classes other than @code{GENERAL_REGS} are specified in operand +constraints is through machine-dependent operand constraint letters. +You can define such letters to correspond to various classes, then use +them in operand constraints. + +You should define a class for the union of two classes whenever some +instruction allows both classes. For example, if an instruction allows +either a floating-point (coprocessor) register or a general register for a +certain operand, you should define a class @code{FLOAT_OR_GENERAL_REGS} +which includes both of them. Otherwise you will get suboptimal code. + +You must also specify certain redundant information about the register +classes: for each class, which classes contain it and which ones are +contained in it; for each pair of classes, the largest class contained +in their union. + +When a value occupying several consecutive registers is expected in a +certain class, all the registers used must belong to that class. +Therefore, register classes cannot be used to enforce a requirement for +a register pair to start with an even-numbered register. The way to +specify this requirement is with @code{HARD_REGNO_MODE_OK}. + +Register classes used for input-operands of bitwise-and or shift +instructions have a special requirement: each such class must have, for +each fixed-point machine mode, a subclass whose registers can transfer that +mode to or from memory. For example, on some machines, the operations for +single-byte values (@code{QImode}) are limited to certain registers. When +this is so, each register class that is used in a bitwise-and or shift +instruction must have a subclass consisting of registers from which +single-byte values can be loaded or stored. This is so that +@code{PREFERRED_RELOAD_CLASS} can always have a possible value to return. + +@table @code +@item enum reg_class +An enumeral type that must be defined with all the register class names +as enumeral values. @code{NO_REGS} must be first. @code{ALL_REGS} +must be the last register class, followed by one more enumeral value, +@code{LIM_REG_CLASSES}, which is not a register class but rather +tells how many classes there are. + +Each register class has a number, which is the value of casting +the class name to type @code{int}. The number serves as an index +in many of the tables described below. + +@item N_REG_CLASSES +The number of distinct register classes, defined as follows: + +@example +#define N_REG_CLASSES (int) LIM_REG_CLASSES +@end example + +@item REG_CLASS_NAMES +An initializer containing the names of the register classes as C string +constants. These names are used in writing some of the debugging dumps. + +@item REG_CLASS_CONTENTS +An initializer containing the contents of the register classes, as integers +which are bit masks. The @var{n}th integer specifies the contents of class +@var{n}. The way the integer @var{mask} is interpreted is that +register @var{r} is in the class if @code{@var{mask} & (1 << @var{r})} is 1. + +When the machine has more than 32 registers, an integer does not suffice. +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}. + +@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 that one such class; choose a class +which is @dfn{minimal}, meaning that no smaller class also contains the +register. + +@item BASE_REG_CLASS +A macro whose definition is the name of the class to which a valid +base register must belong. A base register is one used in an address +which is the register value plus a displacement. + +@item INDEX_REG_CLASS +A macro whose definition is the name of the class to which a valid +index register must belong. An index register is one used in an +address where its value is either multiplied by a scale factor or +added to another register (as well as added to a displacement). + +@item REG_CLASS_FROM_LETTER (@var{char}) +A C expression which defines the machine-dependent operand constraint +letters for register classes. If @var{char} is such a letter, the +value should be the register class corresponding to it. Otherwise, +the value should be @code{NO_REGS}. + +@item REGNO_OK_FOR_BASE_P (@var{num}) +A C expression which is nonzero if register number @var{num} is +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. + +@item REGNO_OK_FOR_INDEX_P (@var{num}) +A C expression which is nonzero if register number @var{num} is +suitable for use as an index register in operand addresses. It may be +either a suitable hard register or a pseudo register that has been +allocated such a hard register. + +The difference between an index register and a base register is that +the index register may be scaled. If an address involves the sum of +two registers, neither one of them scaled, then either one may be +labeled the ``base'' and the other the ``index''; but whichever +labeling is used must fit the machine's constraints of which registers +may serve in each capacity. The compiler will try both labelings, +looking for one that is valid, and will reload one or both registers +only if neither labeling works. + +@item PREFERRED_RELOAD_CLASS (@var{x}, @var{class}) +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 definition + +@example +#define PREFERRED_RELOAD_CLASS(X,CLASS) CLASS +@end example + +@noindent +is safe. + +Sometimes returning a more restrictive class makes better code. For +example, on the 68000, when @var{x} is an integer constant that is in range +for a @samp{moveq} instruction, the value of this macro is always +@code{DATA_REGS} as long as @var{class} includes the data registers. +Requiring a data register guarantees that a @samp{moveq} will be used. + +If @var{x} is a @code{const_double}, by returning @code{NO_REGS} +you can force @var{x} into a memory constant. This is useful on +certain machines where immediate floating values cannot be loaded into +certain kinds of registers. + +In a shift instruction or a bitwise-and instruction, the mode of @var{x}, +the value being reloaded, may not be the same as the mode of the +instruction's operand. (They will both be fixed-point modes, however.) In +such a case, @var{class} may not be a safe value to return. @var{class} is +certainly valid for the instruction, but it may not be valid for reloading +@var{x}. This problem can occur on machines such as the 68000 and 80386 +where some registers can handle full-word values but cannot handle +single-byte values. + +On such machines, this macro must examine the mode of @var{x} and return a +subclass of @var{class} which can handle loads and stores of that mode. On +the 68000, where address registers cannot handle @code{QImode}, if @var{x} +has @code{QImode} then you must return @code{DATA_REGS}. If @var{class} is +@code{ADDR_REGS}, then there is no correct value to return; but the shift +and bitwise-and instructions don't use @code{ADDR_REGS}, so this fatal case +never arises. + +@item CLASS_MAX_NREGS (@var{class}, @var{mode}) +A C expression for the maximum number of consecutive registers +of class @var{class} needed to hold a value of mode @var{mode}. + +This is closely related to the macro @code{HARD_REGNO_NREGS}. +In fact, the value of the macro @code{CLASS_MAX_NREGS (@var{class}, @var{mode})} +should be the maximum value of @code{HARD_REGNO_NREGS (@var{regno}, @var{mode})} +for all @var{regno} values in the class @var{class}. + +This macro helps control the handling of multiple-word values +in the reload pass. +@end table + +Two other special macros describe which constants fit which constraint +letters. + +@table @code +@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}. + +@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 floating values. 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 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}. +@end table + +@node Stack Layout, Library Calls, Register Classes, Machine Macros +@section Describing Stack Layout + +@table @code +@item STACK_GROWS_DOWNWARD +Define this macro if pushing a word onto the stack moves the stack +pointer to a smaller address. + +When we say, ``define this macro if @dots{},'' it means that the +compiler checks this macro only with @code{#ifdef} so the precise +definition used does not matter. + +@item FRAME_GROWS_DOWNWARD +Define this macro if the addresses of local variable slots are at negative +offsets from the frame pointer. + +@item STARTING_FRAME_OFFSET +Offset from the frame pointer to the first local variable slot to be allocated. + +If @code{FRAME_GROWS_DOWNWARD}, the next slot's offset is found by +subtracting the length of the first slot from @code{STARTING_FRAME_OFFSET}. +Otherwise, it is found by adding the length of the first slot to +the value @code{STARTING_FRAME_OFFSET}. + +@item PUSH_ROUNDING (@var{npushed}) +A C expression that is the number of bytes actually pushed onto the +stack when an instruction attempts to push @var{npushed} bytes. + +If the target machine does not have a push instruction, do not define +this macro. That directs GNU CC to use an alternate strategy: to +allocate the entire argument block and then store the arguments into +it. + +On some machines, the definition + +@example +#define PUSH_ROUNDING(BYTES) (BYTES) +@end example + +@noindent +will suffice. But on other machines, instructions that appear +to push one byte actually push two bytes in an attempt to maintain +alignment. Then the definition should be + +@example +#define PUSH_ROUNDING(BYTES) (((BYTES) + 1) & ~1) +@end example + +@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. (In the next version of GNU CC, the argument will be +changed to the function data type rather than its declaration.) + +@item FIRST_PARM_CALLER_OFFSET (@var{fundecl}) +Define this macro on machines where register parameters have shadow +locations on the stack, at addresses below the nominal parameter. +This matters because certain arguments cannot be passed on the stack. +On these machines, such arguments must be stored into the shadow +locations. + +This macro should expand into a C expression whose value is the offset +of the first parameter's shadow location from the nominal stack +pointer value. (That value is itself computed by adding the value of +@code{STACK_POINTER_OFFSET} to the stack pointer register.) + +@item REG_PARM_STACK_SPACE +Define this macro if functions should assume that stack space has been +allocated for arguments even when their values are passed in +registers. + +The actual allocation of such space would be done either by +the call instruction or by the function prologue, or by +defining @code{FIRST_PARM_CALLER_OFFSET}. + +@item STACK_ARGS_ADJUST (@var{size}) +Define this macro if the machine requires padding on the stack for +certain function calls. This is padding on a per-function-call basis, +not padding for individual arguments. + +The argument @var{size} will be a C variable of type @code{struct +arg_data} which contains two fields, an integer named @code{constant} +and an RTX named @code{var}. These together represent a size measured +in bytes which is the sum of the integer and the RTX. Most of the +time @code{var} is 0, which means that the size is simply the integer. + +The definition should be a C statement or compound statement +which alters the variable supplied in whatever way you wish. + +Note that the value you leave in the variable @code{size} will +ultimately be rounded up to a multiple of @code{STACK_BOUNDARY} bits. + +This macro is not fully implemented for machines which have push +instructions (i.e., on which @code{PUSH_ROUNDING} is defined). + +@item RETURN_POPS_ARGS (@var{funtype}) +A C expression that should be 1 if a function pops its own arguments +on returning, or 0 if the function pops no arguments and the caller +must therefore pop them all after the function returns. + +@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 +@code{FUNCTION_TYPE} that describes the data type of the function. +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} +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 +a function used to perform arithmetic, whose name is known specially +in the compiler and was not mentioned in the C code being compiled. + +On the Vax, all functions always pop their arguments, so the +definition of this macro is 1. On the 68000, using the standard +calling convention, no functions pop their arguments, so the value of +the macro is always 0 in this case. But an alternative calling +convention is available in which functions that take a fixed number of +arguments pop them but other functions (such as @code{printf}) pop +nothing (the caller pops all). When this convention is in use, +@var{funtype} is examined to determine whether a function takes a +fixed number of arguments. + +When this macro returns nonzero, the macro @code{FRAME_POINTER_REQUIRED} +must also return nonzero for proper operation. + +@item FUNCTION_VALUE (@var{valtype}, @var{func}) +A C expression to create an RTX representing the place where a +function returns a value of data type @var{valtype}. @var{valtype} is +a tree node representing a data type. Write @code{TYPE_MODE +(@var{valtype})} to get the machine mode used to represent that type. +On many machines, only the mode is relevant. (Actually, on most +machines, scalar values are returned in the same place regardless of +mode).@refill + +If the precise function being called is known, @var{func} is a tree +node (@code{FUNCTION_DECL}) for it; otherwise, @var{func} is a null +pointer. This makes it possible to use a different value-returning +convention for specific functions when all their calls are +known.@refill + +@item FUNCTION_OUTGOING_VALUE (@var{valtype}, @var{func}) +Define this macro if the target machine has ``register windows'' +so that the register in which a function returns its value is not +the same as the one in which the caller sees the value. + +For such machines, @code{FUNCTION_VALUE} computes the register in +which the caller will see the value, and +@code{FUNCTION_OUTGOING_VALUE} should be defined in a similar fashion +to tell the function where to put the value.@refill + +If @code{FUNCTION_OUTGOING_VALUE} is not defined, +@code{FUNCTION_VALUE} serves both purposes.@refill + +@item RETURN_IN_MEMORY (@var{type}) +A C expression which can inhibit the returning of certain function +values in registers, based on the type of value. A nonzero value says +to return the function value in memory, just as large structures are +always returned. Here @var{type} will be a C expression of type +@code{tree}, representing the data type of the value. + +Note that values of mode @code{BLKmode} are returned in memory +regardless of this macro. Also, the option @samp{-fpcc-struct-return} +takes effect regardless of this macro. On most systems, it is +possible to leave the macro undefined; this causes a default +definition to be used, whose value is the constant 0. + +@item LIBCALL_VALUE (@var{mode}) +A C expression to create an RTX representing the place where a library +function returns a value of mode @var{mode}. If the precise function +being called is known, @var{func} is a tree node +(@code{FUNCTION_DECL}) for it; otherwise, @var{func} is a null +pointer. This makes it possible to use a different value-returning +convention for specific functions when all their calls are +known.@refill + +Note that ``library function'' in this context means a compiler +support routine, used to perform arithmetic, whose name is known +specially by the compiler and was not mentioned in the C code being +compiled. + +@item FUNCTION_VALUE_REGNO_P (@var{regno}) +A C expression that is nonzero if @var{regno} is the number of a hard +register in which the values of called function may come back. + +A register whose use for returning values is limited to serving as the +second of a pair (for a value of type @code{double}, say) need not be +recognized by this macro. So for most machines, this definition +suffices: + +@example +#define FUNCTION_VALUE_REGNO_P(N) ((N) == 0) +@end example + +If the machine has register windows, so that the caller and the called +function use different registers for the return value, this macro +should recognize only the caller's register numbers. + +@item FUNCTION_ARG (@var{cum}, @var{mode}, @var{type}, @var{named}) +A C expression that controls whether a function argument is passed +in a register, and which register. + +The arguments are @var{cum}, which summarizes all the previous +arguments; @var{mode}, the machine mode of the argument; @var{type}, +the data type of the argument as a tree node or 0 if that is not known +(which happens for C support library functions); and @var{named}, +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 +hard register in which to pass the argument, or zero to pass the +argument on the stack. + +For the Vax and 68000, where normally all arguments are pushed, zero +suffices as a definition. + +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 +nameless arguments to be passed on the stack instead. This is done +by making @code{FUNCTION_ARG} return 0 whenever @var{named} is 0. + +@item FUNCTION_INCOMING_ARG (@var{cum}, @var{mode}, @var{type}, @var{named}) +Define this macro if the target machine has ``register windows'', so +that the register in which a function sees an arguments is not +necessarily the same as the one in which the caller passed the +argument. + +For such machines, @code{FUNCTION_ARG} computes the register in which +the caller passes the value, and @code{FUNCTION_INCOMING_ARG} should +be defined in a similar fashion to tell the function being called +where the arguments will arrive. + +If @code{FUNCTION_INCOMING_ARG} is not defined, @code{FUNCTION_ARG} +serves both purposes.@refill + +@item FUNCTION_ARG_PARTIAL_NREGS (@var{cum}, @var{mode}, @var{type}, @var{named}) +A C expression for the number of words, at the beginning of an +argument, must be put in registers. The value must be zero for +arguments that are passed entirely in registers or that are entirely +pushed on the stack. + +On some machines, certain arguments must be passed partially in +registers and partially in memory. On these machines, typically the +first @var{n} words of arguments are passed in registers, and the rest +on the stack. If a multi-word argument (a @code{double} or a +structure) crosses that boundary, its first few words must be passed +in registers and the rest must be pushed. This macro tells the +compiler when this occurs, and how many of the words should go in +registers. + +@code{FUNCTION_ARG} for these arguments should return the first +register to be used by the caller for this argument; likewise +@code{FUNCTION_INCOMING_ARG}, for the called function. + +@item CUMULATIVE_ARGS +A C type for declaring a variable that is used as the first argument +of @code{FUNCTION_ARG} and other related values. For some target +machines, the type @code{int} suffices and can hold the number of +bytes of argument so far. + +@item INIT_CUMULATIVE_ARGS (@var{cum}, @var{fntype}) +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. + +@item FUNCTION_ARG_ADVANCE (@var{cum}, @var{mode}, @var{type}, @var{named}) +A C statement (sans semicolon) to update the summarizer variable +@var{cum} to advance past an argument in the argument list. The +values @var{mode}, @var{type} and @var{named} describe that argument. +Once this is done, the variable @var{cum} is suitable for analyzing +the @emph{following} argument with @code{FUNCTION_ARG}, etc.@refill + +@item FUNCTION_ARG_REGNO_P (@var{regno}) +A C expression that is nonzero if @var{regno} is the number of a hard +register in which function arguments are sometimes passed. This does +@emph{not} include implicit arguments such as the static chain and +the structure-value address. On many machines, no registers can be +used for this purpose since all function arguments are pushed on the +stack. + +@item FUNCTION_ARG_PADDING (@var{mode}, @var{size}) +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 +@code{enum direction}: either @code{upward} to pad above the argument, +@code{downward} to pad below, or @code{none} to inhibit padding. + +The argument @var{size} is an RTX which describes the size of the +argument, in bytes. It should be used only if @var{mode} is +@code{BLKmode}. Otherwise, @var{size} is 0. + +This macro does not control the @emph{amount} of padding; that is +always just enough to reach the next multiple of @code{PARM_BOUNDARY}. + +This macro has a default definition which is right for most systems. +For little-endian machines, the default is to pad upward. For +big-endian machines, the default is to pad downward for an argument of +constant size shorter than an @code{int}, and upward otherwise. + +@item FUNCTION_PROLOGUE (@var{file}, @var{size}) +A C compound statement that outputs the assembler code for entry to a +function. The prologue is responsible for setting up the stack frame, +initializing the frame pointer register, saving registers that must be +saved, and allocating @var{size} additional bytes of storage for the +local variables. @var{size} is an integer. @var{file} is a stdio +stream to which the assembler code should be output. + +The label for the beginning of the function need not be output by this +macro. That has already been done when the macro is run. + +To determine which registers to save, the macro can refer to the array +@code{regs_ever_live}: element @var{r} is nonzero if hard register +@var{r} is used anywhere within the function. This implies the +function prologue should save register @var{r}, but not if it is one +of the call-used registers. + +On machines where functions may or may not have frame-pointers, the +function entry code must vary accordingly; it must set up the frame +pointer if one is wanted, and not otherwise. To determine whether a +frame pointer is in wanted, the macro can refer to the variable +@code{frame_pointer_needed}. The variable's value will be 1 at run +time in a function that needs a frame pointer. + +On machines where an argument may be passed partly in registers and +partly in memory, this macro must examine the variable +@code{current_function_pretend_args_size}, and allocate that many bytes +of uninitialized space on the stack just underneath the first argument +arriving on the stack. (This may not be at the very end of the stack, +if the calling sequence has pushed anything else since pushing the stack +arguments. But usually, on such machines, nothing else has been pushed +yet, because the function prologue itself does all the pushing.) + +@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}. +Before calling, the assembler code must load the address of a +counter variable into a register where @code{mcount} expects to +find the address. The name of this variable is @samp{LP} followed +by the number @var{labelno}, so you would generate the name using +@samp{LP%d} in a @code{fprintf}. + +The details of how the address should be passed to @code{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. + +@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. + +The name of the block is a local symbol made with this statement: + +@example +ASM_GENERATE_INTERNAL_LABEL (@var{buffer}, "LPBX", 0); +@end example + +Of course, since you are writing the definition of +@code{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 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. + +@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: + +@example +ASM_GENERATE_INTERNAL_LABEL (@var{buffer}, "LPBX", 2); +@end example + +Of course, since you are writing the definition of +@code{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. + +@item EXIT_IGNORE_STACK +Define this macro as a C expression that is nonzero if the return +instruction or the function epilogue ignores the value of the stack +pointer; in other words, if it is safe to delete an instruction to +adjust the stack pointer before a return from the function. + +Note that this macro's value is relevant only for functions for which +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}. + +@item FUNCTION_EPILOGUE (@var{file}, @var{size}) +A C compound statement that outputs the assembler code for exit from a +function. The epilogue is responsible for restoring the saved +registers and stack pointer to their values when the function was +called, and returning control to the caller. This macro takes the +same arguments as the macro @code{FUNCTION_PROLOGUE}, and the +registers to restore are determined from @code{regs_ever_live} and +@code{CALL_USED_REGISTERS} in the same way. + +On some machines, there is a single instruction that does all the work +of returning from the function. On these machines, give that +instruction the name @samp{return} and do not define the macro +@code{FUNCTION_EPILOGUE} at all. + +Do not define a pattern named @samp{return} if you want the +@code{FUNCTION_EPILOGUE} to be used. If you want the target switches +to control whether return instructions or epilogues are used, define a +@samp{return} pattern with a validity condition that tests the target +switches appropriately. If the @samp{return} pattern's validity +condition is false, epilogues will be used. + +On machines where functions may or may not have frame-pointers, the +function exit code must vary accordingly. Sometimes the code for +these two cases is completely different. To determine whether a frame +pointer is in wanted, the macro can refer to the variable +@code{frame_pointer_needed}. The variable's value will be 1 at run +time in a function that needs a frame pointer. + +On some machines, some functions pop their arguments on exit while +others leave that for the caller to do. For example, the 68020 when +given @samp{-mrtd} pops arguments in functions that take a fixed +number of arguments. + +Your definition of the macro @code{RETURN_POPS_ARGS} decides which +functions pop their own arguments. @code{FUNCTION_EPILOGUE} needs to +know what was decided. The variable @code{current_function_pops_args} +is nonzero if the function should pop its own arguments. If so, use +the variable @code{current_function_args_size} as the number of bytes +to pop. + +@item FIX_FRAME_POINTER_ADDRESS (@var{addr}, @var{depth}) +A C compound statement to alter a memory address that uses the frame +pointer register so that it uses the stack pointer register instead. +This must be done in the instructions that load parameter values into +registers, when the reload pass determines that a frame pointer is not +necessary for the function. @var{addr} will be a C variable name, and +the updated address should be stored in that variable. @var{depth} +will be the current depth of stack temporaries (number of bytes of +arguments currently pushed). The change in offset between a +frame-pointer-relative address and a stack-pointer-relative address +must include @var{depth}. + +Even if your machine description specifies there will always be a +frame pointer in the frame pointer register, you must still define +@code{FIX_FRAME_POINTER_ADDRESS}, but the definition will never be +executed at run time, so it may be empty. + +@item LONGJMP_RESTORE_FROM_STACK +Define this macro if the @code{longjmp} function restores registers +from the stack frames, rather than from those saved specifically by +@code{setjmp}. Certain quantities must not be kept in registers +across a call to @code{setjmp} on such machines. +@end table + +@node Library Calls, Addressing Modes, Stack Layout, Machine Macros +@section Implicit Use of Library Routines + +@table @code +@item MULSI3_LIBCALL +A C string constant giving the name of the function to call for +multiplication of one signed full-word by another. If you do not +define this macro, the default name is used, which is @code{__mulsi3}, +a function defined in @file{gnulib}. + +@item UMULSI3_LIBCALL +A C string constant giving the name of the function to call for +multiplication of one unsigned full-word by another. If you do not +define this macro, the default name is used, which is +@code{__umulsi3}, a function defined in @file{gnulib}. + +@item DIVSI3_LIBCALL +A C string constant giving the name of the function to call for +division of one signed full-word by another. If you do not define +this macro, the default name is used, which is @code{__divsi3}, a +function defined in @file{gnulib}. + +@item UDIVSI3_LIBCALL +A C string constant giving the name of the function to call for +division of one unsigned full-word by another. If you do not define +this macro, the default name is used, which is @code{__udivsi3}, a +function defined in @file{gnulib}. + +@item MODSI3_LIBCALL +A C string constant giving the name of the function to call for the +remainder in division of one signed full-word by another. If you do +not define this macro, the default name is used, which is +@code{__modsi3}, a function defined in @file{gnulib}. + +@item UMODSI3_LIBCALL +A C string constant giving the name of the function to call for the +remainder in division of one unsigned full-word by another. If you do +not define this macro, the default name is used, which is +@code{__umodsi3}, a function defined in @file{gnulib}. + +@item TARGET_MEM_FUNCTIONS +Define this macro if GNU CC should generate calls to the System V +(and ANSI C) library functions @code{memcpy} and @code{memset} +rather than the BSD functions @code{bcopy} and @code{bzero}. + +@item GNULIB_NEEDS_DOUBLE +Define this macro if only @code{float} arguments cannot be passed to +library routines (so they must be converted to @code{double}). This +macro affects both how library calls are generated and how the library +routines in @file{gnulib.c} accept their arguments. It is useful on +machines where floating and fixed point arguments are passed +differently, such as the i860. +@end table + +@node Addressing Modes, Delayed Branch, Library Calls, Machine Macros +@section Addressing Modes + +@table @code +@item HAVE_POST_INCREMENT +Define this macro if the machine supports post-increment addressing. + +@item HAVE_PRE_INCREMENT +@itemx HAVE_POST_DECREMENT +@itemx HAVE_PRE_DECREMENT +Similar for other kinds of addressing. + +@item CONSTANT_ADDRESS_P (@var{x}) +A C expression that is 1 if the RTX @var{x} is a constant whose value +is an integer. This includes integers whose values are not explicitly +known, such as @code{symbol_ref} and @code{label_ref} expressions and +@code{const} arithmetic expressions. + +On most machines, this can be defined as @code{CONSTANT_P (@var{x})}, +but a few machines are more restrictive in which constant addresses +are supported. + +@item MAX_REGS_PER_ADDRESS +A number, the maximum number of registers that can appear in a valid +memory address. Note that it is up to you to specify a value equal to +the maximum number that @code{go_if_legitimate_address} would ever +accept. + +@item GO_IF_LEGITIMATE_ADDRESS (@var{mode}, @var{x}, @var{label}) +A C compound statement with a conditional @code{goto @var{label};} +executed if @var{x} (an RTX) is a legitimate memory address on the +target machine for a memory operand of mode @var{mode}. + +It usually pays to define several simpler macros to serve as +subroutines for this one. Otherwise it may be too complicated to +understand. + +This macro must exist in two variants: a strict variant and a +non-strict one. The strict variant is used in the reload pass. It +must be defined so that any pseudo-register that has not been +allocated a hard register is considered a memory reference. In +contexts where some kind of register is required, a pseudo-register +with no hard register must be rejected. + +The non-strict variant is used in other passes. It must be defined to +accept all pseudo-registers in every context where some kind of +register is required. + +Compiler source files that want to use the strict variant of this +macro define the macro @code{REG_OK_STRICT}. You should use an +@code{#ifdef REG_OK_STRICT} conditional to define the strict variant +in that case and the non-strict variant otherwise. + +Typically among the subroutines used to define +@code{GO_IF_LEGITIMATE_ADDRESS} are subroutines to check for +acceptable registers for various purposes (one for base registers, one +for index registers, and so on). Then only these subroutine macros +need have two variants; the higher levels of macros may be the same +whether strict or not.@refill + +Normally, constant addresses which are the sum of a @code{symbol_ref} +and an integer are stored inside a @code{const} RTX to mark them as +constant. Therefore, there is no need to recognize such sums as +legitimate addresses. + +Usually @code{PRINT_OPERAND_ADDRESS} is not prepared to handle constant +sums that are not marked with @code{const}. It assumes that a naked +@code{plus} indicates indexing. If so, then you @emph{must} reject such +naked constant sums as illegitimate addresses, so that none of them will +be given to @code{PRINT_OPERAND_ADDRESS}.@refill + +@item REG_OK_FOR_BASE_P (@var{x}) +A C expression that is nonzero if @var{x} (assumed to be a @code{reg} +RTX) is valid for use as a base register. For hard registers, it +should always accept those which the hardware permits and reject the +others. Whether the macro accepts or rejects pseudo registers must be +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. + +@item REG_OK_FOR_INDEX_P (@var{x}) +A C expression that is nonzero if @var{x} (assumed to be a @code{reg} +RTX) is valid for use as an index register. + +The difference between an index register and a base register is that +the index register may be scaled. If an address involves the sum of +two registers, neither one of them scaled, then either one may be +labeled the ``base'' and the other the ``index''; but whichever +labeling is used must fit the machine's constraints of which registers +may serve in each capacity. The compiler will try both labelings, +looking for one that is valid, and will reload one or both registers +only if neither labeling works. + +@item LEGITIMIZE_ADDRESS (@var{x}, @var{oldx}, @var{mode}, @var{win}) +A C compound statement that attempts to replace @var{x} with a valid +memory address for an operand of mode @var{mode}. @var{win} will be a +C statement label elsewhere in the code; the macro definition may use + +@example +GO_IF_LEGITIMATE_ADDRESS (@var{mode}, @var{x}, @var{win}); +@end example + +@noindent +to avoid further processing if the address has become legitimate. + +@var{x} will always be the result of a call to @code{break_out_memory_refs}, +and @var{oldx} will be the operand that was given to that function to produce +@var{x}. + +The code generated by this macro should 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. + +It is not necessary for this macro to come up with a legitimate +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. + +@item GO_IF_MODE_DEPENDENT_ADDRESS (@var{addr}, @var{label}) +A C statement or compound statement with a conditional @code{goto +@var{label};} executed if memory address @var{x} (an RTX) can have +different meanings depending on the machine mode of the memory +reference it is used for. + +Autoincrement and autodecrement addresses typically have mode-dependent +effects because the amount of the increment or decrement is the size +of the operand being addressed. Some machines have other mode-dependent +addresses. Many RISC machines have no mode-dependent addresses. + +You may assume that @var{addr} is a valid address for the machine. + +@item LEGITIMATE_CONSTANT_P (@var{x}) +A C expression that is nonzero if @var{x} is a legitimate constant for +an immediate operand on the target machine. You can assume that +either @var{x} is a @code{const_double} or it satisfies +@code{CONSTANT_P}, so you need not check these things. In fact, +@samp{1} is a suitable definition for this macro on machines where any +@code{const_double} is valid and anything @code{CONSTANT_P} is valid.@refill +@end table + +@node Delayed Branch, Condition Code, Addressing Modes, Machine Macros +@section Parameters for Delayed Branch Optimization + +@table @code +@item HAVE_DELAYED_BRANCH +Define this macro if the target machine has delayed branches, that is, +a branch does not take effect immediately, and the actual branch +instruction may be followed by one or more instructions that will be +issued before the PC is actually changed. + +If defined, this allows a special scheduling pass to be run after the +second jump optimization to attempt to reorder instructions to exploit +this. Defining this macro also requires the definition of certain +other macros described below. + +@item DBR_SLOTS_AFTER (@var{insn}) +This macro must be defined if @code{HAVE_DELAYED_BRANCH} is defined. +Its definition should be a C expression returning the number of +available delay slots following the instruction(s) output by the +pattern for @var{insn}. The definition of ``slot'' is +machine-dependent, and may denote instructions, bytes, or whatever. + +@item DBR_INSN_SLOTS (@var{insn}) +This macro must be defined if @code{HAVE_DELAYED_BRANCH} is defined. +It should be a C expression returning the number of slots (typically +the number of machine instructions) consumed by @var{insn}. + +You may assume that @var{insn} is truly an insn, not a note, label, +barrier, dispatch table, @code{use}, or @code{clobber}. + +@item DBR_INSN_ELIGIBLE_P (@var{insn}, @var{dinsn}) +A C expression whose value is non-zero if it is legitimate to put +@var{insn} in the delay slot following @var{dinsn}. + +You do not need to take account of data flow considerations in the +definition of this macro, because the delayed branch optimizer always +does that. This macro is needed only when certain insns may not be +placed in certain delay slots for reasons not evident from the RTL +expressions themselves. If there are no such problems, you don't need +to define this macro. + +You may assume that @var{insn} is truly an insn, not a note, label, +barrier, dispatch table, @code{use}, or @code{clobber}. You may +assume that @var{dinsn} is a jump insn with a delay slot. + +@item DBR_OUTPUT_SEQEND(@var{file}) +A C statement, to be executed after all slot-filler instructions have +been output. If necessary, call @code{dbr_sequence_length} to +determine the number of slots filled in a sequence (zero if not +currently outputting a sequence), to decide how many no-ops to output, +or whatever. + +Don't define this macro if it has nothing to do, but it is helpful in +reading assembly output if the extent of the delay sequence is made +explicit (e.g. with white space). + +Note that output routines for instructions with delay slots must be +prepared to deal with not being output as part of a sequence (i.e. +when the scheduling pass is not run, or when no slot fillers could be +found.) The variable @code{final_sequence} is null when not +processing a sequence, otherwise it contains the @code{sequence} rtx +being output. +@end table + +@node Condition Code, Cross-compilation, Delayed Branch, Machine Macros +@section Condition Code Information + +The file @file{conditions.h} defines a variable @code{cc_status} to +describe how the condition code was computed (in case the interpretation of +the condition code depends on the instruction that it was set by). This +variable contains the RTL expressions on which the condition code is +currently based, and several standard flags. + +Sometimes additional machine-specific flags must be defined in the machine +description header file. It can also add additional machine-specific +information by defining @code{CC_STATUS_MDEP}. + +@table @code +@item CC_STATUS_MDEP +C code for a data type which is used for declaring the @code{mdep} +component of @code{cc_status}. It defaults to @code{int}. + +@item CC_STATUS_MDEP_INIT +A C expression to initialize the @code{mdep} field to ``empty''. +The default definition does nothing, since most machines don't use +the field anyway. If you want to use the field, you should probably +define this macro to initialize it. + +@item NOTICE_UPDATE_CC (@var{exp}, @var{insn}) +A C compound statement to set the components of @code{cc_status} +appropriately for an insn @var{insn} whose body is @var{exp}. It is +this macro's responsibility to recognize insns that set the condition +code as a byproduct of other activity as well as those that explicitly +set @code{(cc0)}. + +If there are insn that do not set the condition code but do alter +other machine registers, this macro must check to see whether they +invalidate the expressions that the condition code is recorded as +reflecting. For example, on the 68000, insns that store in address +registers do not set the condition code, which means that usually +@code{NOTICE_UPDATE_CC} can leave @code{cc_status} unaltered for such +insns. But suppose that the previous insn set the condition code +based on location @samp{a4@@(102)} and the current insn stores a new +value in @samp{a4}. Although the condition code is not changed by +this, it will no longer be true that it reflects the contents of +@samp{a4@@(102)}. Therefore, @code{NOTICE_UPDATE_CC} must alter +@code{cc_status} in this case to say that nothing is known about the +condition code value. + +The definition of @code{NOTICE_UPDATE_CC} must be prepared to deal +with the results of peephole optimization: insns whose patterns are +@code{parallel} RTXs containing various @code{reg}, @code{mem} or +constants which are just the operands. The RTL structure of these +insns is not sufficient to indicate what the insns actually do. What +@code{NOTICE_UPDATE_CC} should do when it sees one is just to run +@code{CC_STATUS_INIT}. +@end table + +@node Cross-compilation, Misc, Condition Code, Machine Macros +@section Cross Compilation and Floating-Point Format + +While all modern machines use 2's complement representation for integers, +there are a variety of representations for floating point numbers. This +means that in a cross-compiler the representation of floating point numbers +in the compiled program may be different from that used in the machine +doing the compilation. + +Because different representation systems may offer different amounts of +range and precision, the cross compiler cannot safely use the host +machine's floating point arithmetic. Therefore, floating point constants +must be represented in the target machine's format. This means that the +cross compiler cannot use @code{atof} to parse a floating point constant; +it must have its own special routine to use instead. Also, constant +folding must emulate the target machine's arithmetic (or must not be done +at all). + +The macros in the following table should be defined only if you are cross +compiling between different floating point formats. + +Otherwise, don't define them. Then default definitions will be set up which +use @code{double} as the data type, @code{==} to test for equality, etc. + +You don't need to worry about how many times you use an operand of any +of these macros. The compiler never uses operands which have side effects. + +@table @code +@item REAL_VALUE_TYPE +A macro for the C data type to be used to hold a floating point value +in the target machine's format. Typically this would be a +@code{struct} containing an array of @code{int}. + +@item REAL_VALUES_EQUAL (@var{x}, @var{y}) +A macro for a C expression which compares for equality the two values, +@var{x} and @var{y}, both of type @code{REAL_VALUE_TYPE}. + +@item REAL_VALUES_LESS (@var{x}, @var{y}) +A macro for a C expression which tests whether @var{x} is less than +@var{y}, both values being of type @code{REAL_VALUE_TYPE} and +interpreted as floating point numbers in the target machine's +representation. + +@item REAL_VALUE_LDEXP (@var{x}, @var{scale}) +A macro for a C expression which performs the standard library +function @code{ldexp}, but using the target machine's floating point +representation. Both @var{x} and the value of the expression have +type @code{REAL_VALUE_TYPE}. The second argument, @var{scale}, is an +integer. + +@item REAL_VALUE_ATOF (@var{string}) +A macro for a C expression which converts @var{string}, an expression +of type @code{char *}, into a floating point number in the target +machine's representation. The value has type @code{REAL_VALUE_TYPE}. +@end table + +Define the following additional macros if you want to make floating +point constant folding work while cross compiling. If you don't +define them, cross compilation is still possible, but constant folding +will not happen for floating point values. + +@table @code +@item REAL_ARITHMETIC (@var{output}, @var{code}, @var{x}, @var{y}) +A macro for a C statement which calculates an arithmetic operation of +the two floating point values @var{x} and @var{y}, both of type +@code{REAL_VALUE_TYPE} in the target machine's representation, to +produce a result of the same type and representation which is stored +in @var{output} (which will be a variable). + +The operation to be performed is specified by @var{code}, a tree code +which will always be one of the following: @code{PLUS_EXPR}, +@code{MINUS_EXPR}, @code{MULT_EXPR}, @code{RDIV_EXPR}, +@code{MAX_EXPR}, @code{MIN_EXPR}.@refill + +The expansion of this macro is responsible for checking for overflow. +If overflow happens, the macro expansion should execute the statement +@code{return 0;}, which indicates the inability to perform the +arithmetic operation requested. + +@item REAL_VALUE_NEGATE (@var{x}) +A macro for a C expression which returns the negative of the floating +point value @var{x}. Both @var{x} and the value of the expression +have type @code{REAL_VALUE_TYPE} and are in the target machine's +floating point representation. + +There is no way for this macro to report overflow, since overflow +can't happen in the negation operation. + +@item REAL_VALUE_TO_INT (@var{low}, @var{high}, @var{x}) +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}) +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}. +@end table + +@node Misc, Assembler Format, Cross-compilation, Machine Macros +@section Miscellaneous Parameters + +@table @code +@item CASE_VECTOR_MODE +An alias for a machine mode name. This is the machine mode that +elements of a jump-table should have. + +@item CASE_VECTOR_PC_RELATIVE +Define this macro if jump-tables should contain relative addresses. + +@item CASE_DROPS_THROUGH +Define this if control falls through a @code{case} insn when the index +value is out of range. This means the specified default-label is +actually ignored by the @code{case} insn proper. + +@item IMPLICIT_FIX_EXPR +An alias for a tree code that should be used by default for conversion +of floating point values to fixed point. Normally, +@code{FIX_ROUND_EXPR} is used.@refill + +@item FIXUNS_TRUNC_LIKE_FIX_TRUNC +Define this macro if the same instructions that convert a floating +point number to a signed fixed point number also convert validly to an +unsigned one. + +@item EASY_DIV_EXPR +An alias for a tree code that is the easiest kind of division to +compile code for in the general case. It may be +@code{TRUNC_DIV_EXPR}, @code{FLOOR_DIV_EXPR}, @code{CEIL_DIV_EXPR} or +@code{ROUND_DIV_EXPR}. These four division operators differ in how +they round the result to an integer. @code{EASY_DIV_EXPR} is used +when it is permissible to use any of those kinds of division and the +choice should be made on the basis of efficiency.@refill + +@item DEFAULT_SIGNED_CHAR +An expression whose value is 1 or 0, according to whether the type +@code{char} should be signed or unsigned by default. The user can +always override this default with the options @samp{-fsigned-char} +and @samp{-funsigned-char}. + +@item SCCS_DIRECTIVE +Define this if the preprocessor should ignore @code{#sccs} directives +and print no error message. + +@item HAVE_VPRINTF +Define this if the library function @code{vprintf} is available on your +system. + +@item MOVE_MAX +The maximum number of bytes that a single instruction can move quickly +from memory to memory. + +@item INT_TYPE_SIZE +A C expression for the size in bits of the type @code{int} on the +target machine. If you don't define this, the default is one word. + +@item SHORT_TYPE_SIZE +A C expression for the size in bits of the type @code{short} on the +target machine. If you don't define this, the default is half a word. +(If this would be less than one storage unit, it is rounded up to one +unit.) + +@item LONG_TYPE_SIZE +A C expression for the size in bits of the type @code{long} on the +target machine. If you don't define this, the default is one word. + +@item LONG_LONG_TYPE_SIZE +A C expression for the size in bits of the type @code{long long} on the +target machine. If you don't define this, the default is two +words. + +@item CHAR_TYPE_SIZE +A C expression for the size in bits of the type @code{char} on the +target machine. If you don't define this, the default is one quarter +of a word. (If this would be less than one storage unit, it is rounded up +to one unit.) + +@item FLOAT_TYPE_SIZE +A C expression for the size in bits of the type @code{float} on the +target machine. If you don't define this, the default is one word. + +@item DOUBLE_TYPE_SIZE +A C expression for the size in bits of the type @code{double} on the +target machine. If you don't define this, the default is two +words. + +@item LONG_DOUBLE_TYPE_SIZE +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. + +@item SLOW_BYTE_ACCESS +Define this macro as a C expression which is nonzero if accessing less +than a word of memory (i.e. a @code{char} or a @code{short}) is slow +(requires more than one instruction). + +@item SLOW_ZERO_EXTEND +Define this macro if zero-extension (of a @code{char} or @code{short} +to an @code{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: + +@example +(set (strict-low-part (subreg:QI (reg:SI @dots{}) 0)) @dots{}) +@end example + +@noindent +and likewise for @code{HImode}. + +@item SHIFT_COUNT_TRUNCATED +Define this macro if shift instructions ignore all but the lowest few +bits of the shift count. It implies that a sign-extend or zero-extend +instruction for the shift count can be omitted. + +@item TRULY_NOOP_TRUNCATION (@var{outprec}, @var{inprec}) +A C expression which is nonzero if on this machine it is safe to +``convert'' an integer of @var{inprec} bits to one of @var{outprec} +bits (where @var{outprec} is smaller than @var{inprec}) by merely +operating on it as if it had only @var{outprec} bits. + +On many machines, this expression can be 1. + +@item NO_FUNCTION_CSE +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. + +@item PROMOTE_PROTOTYPES +Define this macro if an argument declared as @code{char} or +@code{short} in a prototype should actually be passed as an +@code{int}. In addition to avoiding errors in certain cases of +mismatch, it also makes for better code on certain machines. + +@item STORE_FLAG_VALUE +A C expression for the value stored by a store-flag instruction +(@code{s@var{cond}}) when the condition is true. This is usually 1 or +-1; it is required to be an odd number or a negative number. + +Do not define @code{STORE_FLAG_VALUE} if the machine has no store-flag +instructions. + +@item Pmode +An alias for the machine mode for pointers. Normally the definition +can be + +@example +#define Pmode SImode +@end example + +@item FUNCTION_MODE +An alias for the machine mode used for memory references to functions +being called, in @code{call} RTL expressions. On most machines this +should be @code{QImode}. + +@item INSN_MACHINE_INFO +This macro should expand into a C structure type to use for the +machine-dependent info field specified with the optional last argument +in @code{define_insn} and @code{define_peephole} patterns. For example, +it might expand into @code{struct machine_info}; then it would be up +to you to define this structure in the @file{tm.h} file. + +You do not need to define this macro if you do not write the optional +last argument in any of the patterns in the machine description. + +@item DEFAULT_MACHINE_INFO +This macro should expand into a C initializer to use to initialize +the machine-dependent info for one insn pattern. It is used for patterns +that do not specify the machine-dependent info. + +If you do not define this macro, zero is used. + +@item CONST_COSTS (@var{x}, @var{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 expression codes @code{const_int}, @code{const}, @code{symbol_ref}, @code{label_ref} +and @code{const_double}. Each case must ultimately reach a +@code{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 +@var{x}. + +@var{code} is the expression code---redundant, since it can be +obtained with @code{GET_CODE (@var{x})}. + +@item DOLLARS_IN_IDENTIFIERS +Define this to be nonzero if the character @samp{$} should be allowed +by default in identifier names. +@end table + +@node Assembler Format,, Misc, Machine Macros +@section Output of Assembler Code + +@table @code +@item ASM_SPEC +A C string constant that tells the GNU CC driver program options to +pass to the assembler. It can also specify how to translate options +you give to GNU CC into options for GNU CC to pass to the assembler. +See the file @file{tm-sun3.h} for an example of this. + +Do not define this macro if it does not need to do anything. + +@item LINK_SPEC +A C string constant that tells the GNU CC driver program options to +pass to the linker. It can also specify how to translate options you +give to GNU CC into options for GNU CC to pass to the linker. + +Do not define this macro if it does not need to do anything. + +@item LIB_SPEC +Another C string constant used much like @code{LINK_SPEC}. The difference +between the two is that @code{LIBS_SPEC} is used at the end of the +command given to the linker. + +If this macro is not defined, a default is provided that +loads the standard C library from the usual place. See @file{gcc.c}. + +@item LIBG_SPEC +Another C string constant used much like @code{LINK_SPEC}. +This controls whether to link @file{libg.a} when debugging. +Some systems expect this; others do not have any @file{libg.a}. + +If this macro is not defined, a default is provided that loads the +@file{libg.a} provided @samp{-g} is specified. See @file{gcc.c}. + +@item STARTFILE_SPEC +Another C string constant used much like @code{LINK_SPEC}. The +difference between the two is that @code{STARTFILE_SPEC} is used at +the very beginning of the command given to the linker. + +If this macro is not defined, a default is provided that loads the +standard C startup file from the usual place. See @file{gcc.c}. + +@item STANDARD_EXEC_PREFIX +Define this macro as a C string constant if you wish to override the +standard choice of @file{/usr/local/lib/gcc-} as the default prefix to +try when searching for the executable files of the compiler. + +The prefix specified by the @samp{-B} option, if any, is tried before +the default prefix. After the default prefix, if the executable is +not found that way, @file{/usr/lib/gcc-} is tried next; then the +directories in your search path for shell commands are searched. + +@item STANDARD_STARTFILE_PREFIX +Define this macro as a C string constant if you wish to override the +standard choice of @file{/usr/local/lib/} as the default prefix to try +when searching for startup files such as @file{crt0.o}. + +In this search, all the prefixes tried for executable files are tried +first. Then comes the default startfile prefix specified by this +macro, followed by the prefixes @file{/lib/} and @file{/usr/lib/} as +last resorts. + +@item ASM_FILE_START (@var{stream}) +A C expression which outputs to the stdio stream @var{stream} +some appropriate text to go at the start of an assembler file. + +Normally this macro is defined to output a line containing +@samp{#NO_APP}, which is a comment that has no effect on most +assemblers but tells the GNU assembler that it can save time by not +checking for certain assembler constructs. + +On systems that use SDB, it is necessary to output certain commands; +see @file{tm-attasm.h}. + +@item ASM_FILE_END (@var{stream}) +A C expression which outputs to the stdio stream @var{stream} +some appropriate text to go at the end of an assembler file. + +If this macro is not defined, the default is to output nothing +special at the end of the file. Most systems don't require any +definition. + +On systems that use SDB, it is necessary to output certain commands; +see @file{tm-attasm.h}. + +@item ASM_IDENTIFY_GCC (@var{file}) +A C statement to output assembler commands which will identify +the object file as having been compiled with GNU CC (or another +GNU compiler). + +If you don't define this macro, the string @samp{gcc_compiled.:} +is output. This string is calculated to define a symbol which, +on BSD systems, will never be defined for any other reason. +GDB checks for the presence of this symbol when reading the +symbol table of an executable. + +On non-BSD systems, you must arrange communication with GDB in +some other fashion. If GDB is not used on your system, you can +define this macro with an empty body. + +@item ASM_APP_ON +A C string constant for text to be output before each @code{asm} +statement or group of consecutive ones. Normally this is +@code{"#APP"}, which is a comment that has no effect on most +assemblers but tells the GNU assembler that it must check the lines +that follow for all valid assembler constructs. + +@item ASM_APP_OFF +A C string constant for text to be output after each @code{asm} +statement or group of consecutive ones. Normally this is +@code{"#NO_APP"}, which tells the GNU assembler to resume making the +time-saving assumptions that are valid for ordinary compiler output. + +@item TEXT_SECTION_ASM_OP +A C string constant for the assembler operation that should precede +instructions and read-only data. Normally @code{".text"} is right. + +@item DATA_SECTION_ASM_OP +A C string constant for the assembler operation to identify the +following data as writable initialized data. Normally @code{".data"} +is right. + +@item EXTRA_SECTIONS +A list of names for sections other than the standard two, which are +@code{in_text} and @code{in_data}. You need not define this macro +on a system with no other sections (that GCC needs to use). + +@item EXTRA_SECTION_FUNCTIONS +One or more functions to be defined in @file{varasm.c}. These +functions should do jobs analogous to those of @code{text_section} and +@code{data_section}, for your additional sections. Do not define this +macro if you do not define @code{EXTRA_SECTIONS}. + +@item SELECT_SECTION (@var{exp}) +A C statement or statements to switch to the appropriate section for +output of @var{exp}. You can assume that @var{exp} is either a +@code{VAR_DECL} node or a constant of some sort. Select the section +by calling @code{text_section} or one of the alternatives for other +sections. + +Do not define this macro if you use only the standard two sections +and put all read-only variables and constants in the text section. + +@item SELECT_RTX_SECTION (@var{mode}, @var{rtx}) +A C statement or statements to switch to the appropriate section for +output of @var{rtx} in mode @var{mode}. You can assume that @var{rtx} +is some kind of constant in RTL. The argument @var{mode} is redundant +except in the case of a @code{const_int} rtx. Select the section by +calling @code{text_section} or one of the alternatives for other +sections. + +Do not define this macro if you use only the standard two sections and +put all constants in the text section. + +@item REGISTER_NAMES +A C initializer containing the assembler's names for the machine +registers, each one as a C string constant. This is what translates +register numbers in the compiler into assembler language. + +@item DBX_REGISTER_NUMBER (@var{regno}) +A C expression that returns the DBX register number for the compiler +register number @var{regno}. In simple cases, the value of this +expression may be @var{regno} itself. But sometimes there are some +registers that the compiler knows about and DBX does not, or vice +versa. In such cases, some register may need to have one number in +the compiler and another for DBX. + +@item DBX_DEBUGGING_INFO +Define this macro if GNU CC should produce debugging output for DBX +in response to the @samp{-g} option. + +@item SDB_DEBUGGING_INFO +Define this macro if GNU CC should produce debugging output for SDB +in response to the @samp{-g} option. + +@item PUT_SDB_@var{op} +Define these macros to override the assembler syntax for the special +SDB assembler directives. See @file{sdbout.c} for a list of these +macros and their arguments. If the standard syntax is used, you need +not define them yourself. + +@item SDB_GENERATE_FAKE +Define this macro to override the usual method of constructing a dummy +name for anonymous structure and union types. See @file{sdbout.c} for +more information. + +@item DBX_NO_XREFS +Define this macro if DBX on your system does not support the construct +@samp{xs@var{tagname}}. On some systems, this construct is used to +describe a forward reference to a structure named @var{tagname}. +On other systems, this construct is not supported at all. + +@item DBX_CONTIN_LENGTH +A symbol name in DBX-format debugging information is normally +continued (split into two separate @code{.stabs} directives) when it +exceeds a certain length (by default, 80 characters). On some +operating systems, DBX requires this splitting; on others, splitting +must not be done. You can inhibit splitting by defining this macro +with the value zero. You can override the default splitting-length by +defining this macro as an expression for the length you desire. + +@item DBX_CONTIN_CHAR +Normally continuation is indicated by adding a @samp{\} character to +the end of a @code{.stabs} string when a continuation follows. To use +a different character instead, define this macro as a character +constant for the character you want to use. Do not define this macro +if backslash is correct for your system. + +@item DBX_STATIC_STAB_DATA_SECTION +Define this macro if it is necessary to go to the data section before +outputting the @samp{.stabs} pseudo-op for a non-global static +variable. + +@item ASM_OUTPUT_LABEL (@var{stream}, @var{name}) +A C statement (sans semicolon) to output to the stdio stream +@var{stream} the assembler definition of a label named @var{name}. +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. + +@item ASM_DECLARE_FUNCTION_NAME (@var{stream}, @var{name}, @var{decl}) +A C statement (sans semicolon) to output to the stdio stream +@var{stream} any text necessary for declaring the name @var{name} of a +function which is being defined. This macro is responsible for +outputting the label definition (perhaps using +@code{ASM_OUTPUT_LABEL}). The argument @var{decl} is the +@code{FUNCTION_DECL} tree node representing the function. + +If this macro is not defined, then the function name is defined in the +usual manner as a label (by means of @code{ASM_OUTPUT_LABEL}). + +@item ASM_GLOBALIZE_LABEL (@var{stream}, @var{name}) +A C statement (sans semicolon) to output to the stdio stream +@var{stream} some commands that will make the label @var{name} global; +that is, available for reference from other files. 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 making that name global, and a newline. + +@item ASM_OUTPUT_EXTERNAL (@var{stream}, @var{decl}, @var{name}) +A C statement (sans semicolon) to output to the stdio stream +@var{stream} any text necessary for declaring the name of an external +symbol named @var{name} which is referenced in this compilation but +not defined. The value of @var{decl} is the tree node for the +declaration. + +This macro need not be defined if it does not need to output anything. +The GNU assembler and most Unix assemblers don't require anything. + +@item ASM_OUTPUT_LABELREF (@var{stream}, @var{name}) +A C statement to output to the stdio stream @var{stream} a reference +in assembler syntax to a label named @var{name}. The character +@samp{_} should be added to the front of the name, if that is +customary on your operating system, as it is in most Berkeley Unix +systems. This macro is used in @code{assemble_name}. + +@item ASM_GENERATE_INTERNAL_LABEL (@var{string}, @var{prefix}, @var{num}) +A C statement to store into the string @var{string} a label whose name +is made from the string @var{prefix} and the number @var{num}. + +This string, when output subsequently by @code{ASM_OUTPUT_LABELREF}, +should produce the same output that @code{ASM_OUTPUT_INTERNAL_LABEL} +would produce with the same @var{prefix} and @var{num}. + +@item ASM_OUTPUT_INTERNAL_LABEL (@var{stream}, @var{prefix}, @var{num}) +A C statement to output to the stdio stream @var{stream} a label whose +name is made from the string @var{prefix} and the number @var{num}. +These labels are used for internal purposes, and there is no reason +for them to appear in the symbol table of the object file. On many +systems, the letter @samp{L} at the beginning of a label has this +effect. The usual definition of this macro is as follows: + +@example +fprintf (@var{stream}, "L%s%d:\n", @var{prefix}, @var{num}) +@end example + +@item ASM_OUTPUT_CASE_LABEL (@var{stream}, @var{prefix}, @var{num}, @var{table}) +Define this if the label before a jump-table needs to be output +specially. The first three arguments are the same as for +@code{ASM_OUTPUT_INTERNAL_LABEL}; the fourth argument is the +jump-table which follows (a @code{jump_insn} containing an +@code{addr_vec} or @code{addr_diff_vec}). + +This feature is used on system V to output a @code{swbeg} statement +for the table. + +If this macro is not defined, these labels are output with +@code{ASM_OUTPUT_INTERNAL_LABEL}. + +@item ASM_OUTPUT_CASE_END (@var{stream}, @var{num}, @var{table}) +Define this if something special must be output at the end of a +jump-table. The definition should be a C statement to be executed +after the assembler code for the table is written. It should write +the appropriate code to stdio stream @var{stream}. The argument +@var{table} is the jump-table insn, and @var{num} is the label-number +of the preceding label. + +If this macro is not defined, nothing special is output at the end of +the jump-table. + +@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. + +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. + +@item ASM_FORMAT_PRIVATE_NAME (@var{outvar}, @var{name}, @var{number}) +A C expression to assign to @var{outvar} (which is a variable of type +@code{char *}) a newly allocated string made from the string +@var{name} and the number @var{number}, with some suitable punctuation +added. Use @code{alloca} to get space for the string. + +This string will be used as the argument to @code{ASM_OUTPUT_LABELREF} +to produce an assembler label for an internal static variable whose +name is @var{name}. Therefore, the string must be such as to result +in valid assembler code. The argument @var{number} is different each +time this macro is executed; it prevents conflicts between +similarly-named internal static variables in different scopes. + +Ideally this string should not be a valid C identifier, to prevent any +conflict with the user's own symbols. Most assemblers allow periods +or percent signs in assembler symbols; putting at least one of these +between the name and the number will suffice. + +@item ASM_OUTPUT_REG_PUSH (@var{stream}, @var{regno}) +A C expression to output to @var{stream} some assembler code +which will push hard register number @var{regno} onto the stack. +The code need not be optimal, since this macro is used only when +profiling. + +@item ASM_OUTPUT_REG_POP (@var{stream}, @var{regno}) +A C expression to output to @var{stream} some assembler code +which will pop hard register number @var{regno} off of the stack. +The code need not be optimal, since this macro is used only when +profiling. + +@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 +@code{ASM_OUTPUT_INTERNAL_LABEL}, and they must be printed in the same +way here. For example, + +@example +fprintf (@var{stream}, "\t.word L%d-L%d\n", + @var{value}, @var{rel}) +@end example + +@item ASM_OUTPUT_ADDR_VEC_ELT (@var{stream}, @var{value}) +This macro should be provided on machines where the addresses +in a dispatch table are absolute. + +The definition should be a C statement to output to the stdio stream +@var{stream} an assembler pseudo-instruction to generate a reference to +a label. @var{value} is the number of an internal label whose +definition is output using @code{ASM_OUTPUT_INTERNAL_LABEL}. +For example, + +@example +fprintf (@var{stream}, "\t.word L%d\n", @var{value}) +@end example + +@item ASM_OUTPUT_DOUBLE (@var{stream}, @var{value}) +A C statement to output to the stdio stream @var{stream} an assembler +instruction to assemble a @code{double} constant whose value is +@var{value}. @var{value} will be a C expression of type +@code{double}. + +@item ASM_OUTPUT_FLOAT (@var{stream}, @var{value}) +A C statement to output to the stdio stream @var{stream} an assembler +instruction to assemble a @code{float} constant whose value is +@var{value}. @var{value} will be a C expression of type @code{float}. + +@item ASM_OUTPUT_INT (@var{stream}, @var{exp}) +@itemx ASM_OUTPUT_SHORT (@var{stream}, @var{exp}) +@itemx ASM_OUTPUT_CHAR (@var{stream}, @var{exp}) +A C statement to output to the stdio stream @var{stream} an assembler +instruction to assemble a @code{int}, @code{short} or @code{char} +constant whose value is @var{value}. The argument @var{exp} will be an +RTL expression which represents a constant value. Use +@samp{output_addr_const (@var{stream}, @var{exp})} to output this value +as an assembler expression.@refill + +@item ASM_OUTPUT_DOUBLE_INT (@var{stream}, @var{exp}) +A C statement to output to the stdio stream @var{stream} an assembler +instruction to assemble a @code{long long} constant whose value is +@var{exp}. The argument @var{exp} will be an RTL expression which +represents a constant value. It may be a @code{const_double} RTX, +or it may be an ordinary single-precision constant. In the latter +case, you should zero-extend it. + +@item ASM_OUTPUT_BYTE (@var{stream}, @var{value}) +A C statement to output to the stdio stream @var{stream} an assembler +instruction to assemble a single byte containing the number @var{value}. + +@item ASM_OUTPUT_ASCII (@var{stream}, @var{ptr}, @var{len}) +A C statement to output to the stdio stream @var{stream} an assembler +instruction to assemble a string constant containing the @var{len} +bytes at @var{ptr}. @var{ptr} will be a C expression of type +@code{char *} and @var{len} a C expression of type @code{int}. + +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}. + +@item ASM_OUTPUT_SKIP (@var{stream}, @var{nbytes}) +A C statement to output to the stdio stream @var{stream} an assembler +instruction to advance the location counter by @var{nbytes} bytes. +@var{nbytes} will be a C expression of type @code{int}. + +@item ASM_OUTPUT_ALIGN (@var{stream}, @var{power}) +A C statement to output to the stdio stream @var{stream} an assembler +instruction to advance the location counter to a multiple of 2 to the +@var{power} bytes. @var{power} will be a C expression of type @code{int}. + +@item ASM_OUTPUT_COMMON (@var{stream}, @var{name}, @var{size}, @var{rounded}) +A C statement (sans semicolon) to output to the stdio stream +@var{stream} the assembler definition of a common-label named +@var{name} whose size is @var{size} bytes. The variable @var{rounded} +is the size rounded up to whatever alignment the caller wants. + +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. + +@item ASM_OUTPUT_LOCAL (@var{stream}, @var{name}, @var{size}, @var{rounded}) +A C statement (sans semicolon) to output to the stdio stream +@var{stream} the assembler definition of a local-common-label named +@var{name} whose size is @var{size} bytes. The variable @var{rounded} +is the size rounded up to whatever alignment the caller wants. + +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 +static variables are output. + +@item ASM_OUTPUT_SOURCE_FILENAME (@var{stream}, @var{name}) +A C statment to output DBX or SDB debugging information which indicates +that filename @var{name} is the current source file to the stdio stream +@var{stream}. + +This macro need not be defined if the standard form of debugging +information for the debugger in use is appropriate. + +@item ASM_OUTPUT_SOURCE_LINE (@var{stream}, @var{line}) +A C statment to output DBX or SDB debugging information before code +for line number @var{line} of the current source file to the +stdio stream @var{stream}. + +This macro need not be defined if the standard form of debugging +information for the debugger in use is appropriate. + +@item ASM_OUTPUT_IDENT (@var{stream}, @var{string}) +A C statement to output something to the assembler file to handle a +@samp{#ident} directive containing the text @var{string}. If this +macro is not defined, nothing is output for a @samp{#ident} directive. + +@item TARGET_BELL +A C constant expression for the integer value for escape sequence +@samp{\a}. + +@item TARGET_BS +@itemx TARGET_TAB +@itemx TARGET_NEWLINE +C constant expressions for the integer values for escape sequences +@samp{\b}, @samp{\t} and @samp{\n}. + +@item TARGET_VT +@itemx TARGET_FF +@itemx TARGET_CR +C constant expressions for the integer values for escape sequences +@samp{\v}, @samp{\f} and @samp{\r}. + +@item ASM_OUTPUT_OPCODE (@var{stream}, @var{ptr}) +Define this macro if you are using an unusual assembler that +requires different names for the machine instructions. + +The definition is a C statement or statements which output an +assembler instruction opcode to the stdio stream @var{stream}. The +macro-operand @var{ptr} is a variable of type @code{char *} which +points to the opcode name in its ``internal'' form---the form that is +written in the machine description. The definition should output the +opcode name to @var{stream}, performing any translation you desire, and +increment the variable @var{ptr} to point at the end of the opcode +so that it will not be output twice. + +In fact, your macro definition may process less than the entire opcode +name, or more than the opcode name; but if you want to process text +that includes @samp{%}-sequences to substitute operands, you must take +care of the substitution yourself. Just be sure to increment +@var{ptr} over whatever text should not be output normally. + +If you need to look at the operand values, they can be found as the +elements of @code{recog_operand}. + +If the macro definition does nothing, the instruction is output +in the usual way. + +@item FINAL_PRESCAN_INSN (@var{insn}, @var{opvec}, @var{noperands}) +If defined, a C statement to be executed just prior to the output of +assembler code for @var{insn}, to modify the extracted operands so +they will be output differently. + +Here the argument @var{opvec} is the vector containing the operands +extracted from @var{insn}, and @var{noperands} is the number of +elements of the vector which contain meaningful data for this insn. +The contents of this vector are what will be used to convert the insn +template into assembler code, so you can change the assembler output +by changing the contents of the vector. + +This macro is useful when various assembler syntaxes share a single +file of instruction patterns; by defining this macro differently, you +can cause a large class of instructions to be output differently (such +as with rearranged operands). Naturally, variations in assembler +syntax affecting individual insn patterns ought to be handled by +writing conditional output routines in those patterns. + +If this macro is not defined, it is equivalent to a null statement. + +@item PRINT_OPERAND (@var{stream}, @var{x}, @var{code}) +A C compound statement to output to stdio stream @var{stream} the +assembler syntax for an instruction operand @var{x}. @var{x} is an +RTL expression. + +@var{code} is a value that can be used to specify one of several ways +of printing the operand. It is used when identical operands must be +printed differently depending on the context. @var{code} comes from +the @samp{%} specification that was used to request printing of the +operand. If the specification was just @samp{%@var{digit}} then +@var{code} is 0; if the specification was @samp{%@var{ltr} +@var{digit}} then @var{code} is the ASCII code for @var{ltr}. + +If @var{x} is a register, this macro should print the register's name. +The names can be found in an array @code{reg_names} whose type is +@code{char *[]}. @code{reg_names} is initialized from +@code{REGISTER_NAMES}. + +When the machine description has a specification @samp{%@var{punct}} +(a @samp{%} followed by a punctuation character), this macro is called +with a null pointer for @var{x} and the punctuation character for +@var{code}. + +@item PRINT_OPERAND_PUNCT_VALID_P (@var{code}) +A C expression which evaluates to true if @var{code} is a valid +punctuation character for use in the @code{PRINT_OPERAND} macro. If +@code{PRINT_OPERAND_PUNCT_VALID_P} is not defined, it means that no +punctuation characters (except for the standard one, @samp{%}) are used +in this way. + +@item PRINT_OPERAND_ADDRESS (@var{stream}, @var{x}) +A C compound statement to output to stdio stream @var{stream} the +assembler syntax for an instruction operand that is a memory reference +whose address is @var{x}. @var{x} is an RTL expression. + +@item ASM_OPEN_PAREN +@itemx ASM_CLOSE_PAREN +These macros are defined as C string constant, describing the syntax +in the assembler for grouping arithmetic expressions. The following +definitions are correct for most assemblers: + +@example +#define ASM_OPEN_PAREN "(" +#define ASM_CLOSE_PAREN ")" +@end example +@end table + +@node Config,, Machine Macros, Top +@chapter The Configuration File + +The configuration file @file{xm-@var{machine}.h} contains macro definitions +that describe the machine and system on which the compiler is running. +Most of the values in it are actually the same on all machines that GNU CC +runs on, so large parts of all configuration files are identical. But +there are some macros that vary: + +@table @code +@item FAILURE_EXIT_CODE +A C expression for the status code to be returned when the compiler +exits after serious errors. + +@item SUCCESS_EXIT_CODE +A C expression for the status code to be returned when the compiler +exits without serious errors. + +@item USE_C_ALLOCA +Define this macro to indicate that the compiler is running with the +@code{alloca} implemented in C. This version of @code{alloca} can be +found in the file @file{alloca.c}; to use it, you must also alter the +@file{Makefile} variable @code{ALLOCA}. + +This macro, unlike most, describes the machine that the compiler is +running on, rather than the one the compiler is compiling for. +Therefore, it should be set in the @file{xm-@var{machine}.h} file +rather than in the @file{tm-@var{machine}.h} file. + +If you do define this macro, you should probably do it as follows: + +@example +#ifndef __GNUC__ +#define USE_C_ALLOCA +#else +#define alloca __builtin_alloca +#endif +@end example + +@noindent +so that when the compiler is compiled with GNU CC it uses the more +efficient built-in @code{alloca} function. +@end table + +In addition, configuration files for system V define @code{bcopy}, +@code{bzero} and @code{bcmp} as aliases. Some files define @code{alloca} +as a macro when compiled with GNU CC, in order to take advantage of the +benefit of GNU CC's built-in @code{alloca}. + +@contents +@bye diff --git a/gcc-1.40/gdbfiles.h b/gcc-1.40/gdbfiles.h new file mode 100644 index 0000000..f58d301 --- /dev/null +++ b/gcc-1.40/gdbfiles.h @@ -0,0 +1,15 @@ + +/* Alist matching source file names to GDB filenumbers. + Used in output_source_line. */ + +struct gdbfile +{ + struct gdbfile *next; + char *name; /* name of source file */ + int filenum; /* Assigned number */ + int nlines; /* # lines generated for this source file */ +}; + +/* Chain of all `struct gdbfile's. */ + +extern struct gdbfile *gdbfiles; diff --git a/gcc-1.40/gencodes.c b/gcc-1.40/gencodes.c new file mode 100644 index 0000000..183aead --- /dev/null +++ b/gcc-1.40/gencodes.c @@ -0,0 +1,154 @@ +/* Generate from machine description: + + - some macros CODE_FOR_... giving the insn_code_number value + for each of the defined standard insn names. + Copyright (C) 1987 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 1, 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 +#include "config.h" +#include "rtl.h" +#include "obstack.h" + +struct obstack obstack; +struct obstack *rtl_obstack = &obstack; + +#define obstack_chunk_alloc xmalloc +#define obstack_chunk_free free +extern int xmalloc (); +extern void free (); + +void fatal (); +void fancy_abort (); + +int insn_code_number; + +void +gen_insn (insn) + rtx insn; +{ + /* Don't mention instructions whose names are the null string. + They are in the machine description just to be recognized. */ + if (strlen (XSTR (insn, 0)) != 0) + printf (" CODE_FOR_%s = %d,\n", XSTR (insn, 0), + insn_code_number); +} + +int +xmalloc (size) +{ + register int val = malloc (size); + + if (val == 0) + fatal ("virtual memory exhausted"); + return val; +} + +int +xrealloc (ptr, size) + char *ptr; + int size; +{ + int result = realloc (ptr, size); + if (!result) + fatal ("virtual memory exhausted"); + return result; +} + +void +fatal (s, a1, a2) + char *s; +{ + fprintf (stderr, "gencodes: "); + fprintf (stderr, s, a1, a2); + fprintf (stderr, "\n"); + exit (FATAL_EXIT_CODE); +} + +/* 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; + char **argv; +{ + rtx desc; + FILE *infile; + extern rtx read_rtx (); + register int c; + + obstack_init (rtl_obstack); + + if (argc <= 1) + fatal ("No input file name."); + + infile = fopen (argv[1], "r"); + if (infile == 0) + { + perror (argv[1]); + exit (FATAL_EXIT_CODE); + } + + init_rtl (); + + printf ("/* Generated automatically by the program `gencodes'\n\ +from the machine description file `md'. */\n\n"); + + printf ("#ifndef MAX_INSN_CODE\n\n"); + + /* Read the machine description. */ + + insn_code_number = 0; + printf ("enum insn_code {\n"); + + while (1) + { + c = read_skip_spaces (infile); + if (c == EOF) + break; + ungetc (c, infile); + + desc = read_rtx (infile); + if (GET_CODE (desc) == DEFINE_INSN || GET_CODE (desc) == DEFINE_EXPAND) + { + gen_insn (desc); + insn_code_number++; + } + if (GET_CODE (desc) == DEFINE_PEEPHOLE) + { + insn_code_number++; + } + } + + printf (" CODE_FOR_nothing };\n"); + + printf ("\n#define MAX_INSN_CODE ((int) CODE_FOR_nothing)\n"); + + printf ("#endif /* MAX_INSN_CODE */\n"); + + fflush (stdout); + exit (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE); +} diff --git a/gcc-1.40/genconfig.c b/gcc-1.40/genconfig.c new file mode 100644 index 0000000..cb152ac --- /dev/null +++ b/gcc-1.40/genconfig.c @@ -0,0 +1,267 @@ +/* Generate from machine description: + + - some #define configuration flags. + Copyright (C) 1987 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 1, 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 +#include "config.h" +#include "rtl.h" +#include "obstack.h" + +struct obstack obstack; +struct obstack *rtl_obstack = &obstack; + +#define obstack_chunk_alloc xmalloc +#define obstack_chunk_free free +extern int xmalloc (); +extern void free (); + +/* flags to determine output of machine description dependent #define's. */ +int max_recog_operands_flag; +int max_dup_operands_flag; +int max_clobbers_per_insn_flag; +int register_constraint_flag; + +int clobbers_seen_this_insn; +int dup_operands_seen_this_insn; + +void fatal (); +void fancy_abort (); + +void +walk_insn_part (part) + rtx part; +{ + register int i, j; + register RTX_CODE code; + register char *format_ptr; + + if (part == 0) + return; + + code = GET_CODE (part); + switch (code) + { + case CLOBBER: + clobbers_seen_this_insn++; + break; + + case MATCH_OPERAND: + if (XINT (part, 0) > max_recog_operands_flag) + max_recog_operands_flag = XINT (part, 0); + if (XSTR (part, 2) && *XSTR (part, 2)) + register_constraint_flag = 1; + return; + + case MATCH_OPERATOR: + if (XINT (part, 0) > max_recog_operands_flag) + max_recog_operands_flag = XINT (part, 0); + /* Now scan the rtl'x in the vector inside the match_operator. */ + break; + + case LABEL_REF: + if (GET_CODE (XEXP (part, 0)) == MATCH_OPERAND) + break; + return; + + case MATCH_DUP: + ++dup_operands_seen_this_insn; + if (XINT (part, 0) > max_recog_operands_flag) + max_recog_operands_flag = XINT (part, 0); + + case REG: case CONST_INT: case SYMBOL_REF: + case PC: case CC0: + return; + } + + format_ptr = GET_RTX_FORMAT (GET_CODE (part)); + + for (i = 0; i < GET_RTX_LENGTH (GET_CODE (part)); i++) + switch (*format_ptr++) + { + case 'e': + case 'u': + walk_insn_part (XEXP (part, i)); + break; + case 'E': + if (XVEC (part, i) != NULL) + for (j = 0; j < XVECLEN (part, i); j++) + walk_insn_part (XVECEXP (part, i, j)); + break; + } +} + +void +gen_insn (insn) + rtx insn; +{ + int i; + + /* Walk the insn pattern to gather the #define's status. */ + clobbers_seen_this_insn = 0; + dup_operands_seen_this_insn = 0; + if (XVEC (insn, 1) != 0) + for (i = 0; i < XVECLEN (insn, 1); i++) + walk_insn_part (XVECEXP (insn, 1, i)); + + if (clobbers_seen_this_insn > max_clobbers_per_insn_flag) + max_clobbers_per_insn_flag = clobbers_seen_this_insn; + if (dup_operands_seen_this_insn > max_dup_operands_flag) + max_dup_operands_flag = dup_operands_seen_this_insn; +} + +/* Similar but scan a define_expand. */ + +void +gen_expand (insn) + rtx insn; +{ + int i; + + /* Walk the insn pattern to gather the #define's status. */ + + /* Note that we don't bother recording the number of MATCH_DUPs + that occur in a gen_expand, because only reload cares about that. */ + if (XVEC (insn, 1) != 0) + for (i = 0; i < XVECLEN (insn, 1); i++) + { + /* Compute the maximum SETs and CLOBBERS + in any one of the sub-insns; + don't sum across all of them. */ + clobbers_seen_this_insn = 0; + + walk_insn_part (XVECEXP (insn, 1, i)); + + if (clobbers_seen_this_insn > max_clobbers_per_insn_flag) + max_clobbers_per_insn_flag = clobbers_seen_this_insn; + } +} + +void +gen_peephole (peep) + rtx peep; +{ + int i; + + /* Look through the patterns that are matched + to compute the maximum operand number. */ + for (i = 0; i < XVECLEN (peep, 0); i++) + walk_insn_part (XVECEXP (peep, 0, i)); +} + +int +xmalloc (size) +{ + register int val = malloc (size); + + if (val == 0) + fatal ("virtual memory exhausted"); + + return val; +} + +int +xrealloc (ptr, size) + char *ptr; + int size; +{ + int result = realloc (ptr, size); + if (!result) + fatal ("virtual memory exhausted"); + return result; +} + +void +fatal (s, a1, a2) + char *s; +{ + fprintf (stderr, "genconfig: "); + fprintf (stderr, s, a1, a2); + fprintf (stderr, "\n"); + exit (FATAL_EXIT_CODE); +} + +/* 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; + char **argv; +{ + rtx desc; + FILE *infile; + extern rtx read_rtx (); + register int c; + + obstack_init (rtl_obstack); + + if (argc <= 1) + fatal ("No input file name."); + + infile = fopen (argv[1], "r"); + if (infile == 0) + { + perror (argv[1]); + exit (FATAL_EXIT_CODE); + } + + init_rtl (); + + printf ("/* Generated automatically by the program `genconfig'\n\ +from the machine description file `md'. */\n\n"); + + /* Read the machine description. */ + + while (1) + { + c = read_skip_spaces (infile); + if (c == EOF) + break; + ungetc (c, infile); + + desc = read_rtx (infile); + if (GET_CODE (desc) == DEFINE_INSN) + gen_insn (desc); + if (GET_CODE (desc) == DEFINE_EXPAND) + gen_expand (desc); + if (GET_CODE (desc) == DEFINE_PEEPHOLE) + gen_peephole (desc); + } + + /* 3 more than needed for this md file, for the sake of asm constructs. */ + printf ("\n#define MAX_RECOG_OPERANDS %d\n", max_recog_operands_flag + 4); + + if (max_dup_operands_flag == 0) + max_dup_operands_flag = 1; + printf ("\n#define MAX_DUP_OPERANDS %d\n", max_dup_operands_flag); + + if (register_constraint_flag) + printf ("#define REGISTER_CONSTRAINTS\n"); + + fflush (stdout); + exit (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE); +} diff --git a/gcc-1.40/genemit.c b/gcc-1.40/genemit.c new file mode 100644 index 0000000..9e8df57 --- /dev/null +++ b/gcc-1.40/genemit.c @@ -0,0 +1,480 @@ +/* Generate code from machine description to emit insns as rtl. + Copyright (C) 1987, 1988 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 1, 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 +#include "config.h" +#include "rtl.h" +#include "obstack.h" + +struct obstack obstack; +struct obstack *rtl_obstack = &obstack; + +#define obstack_chunk_alloc xmalloc +#define obstack_chunk_free free +extern int xmalloc (); +extern void free (); + +void fatal (); +void fancy_abort (); + +int max_opno; +int max_dup_opno; +int register_constraints; +int insn_code_number; + +#define max(a, b) ((a) > (b) ? (a) : (b)) + +void +max_operand_1 (x) + rtx x; +{ + register RTX_CODE code; + register int i; + register int len; + register char *fmt; + + if (x == 0) + return; + + code = GET_CODE (x); + + if (code == MATCH_OPERAND && XSTR (x, 2) != 0) + register_constraints = 1; + if (code == MATCH_OPERAND || code == MATCH_OPERATOR) + max_opno = max (max_opno, XINT (x, 0)); + if (code == MATCH_DUP) + max_dup_opno = max (max_dup_opno, XINT (x, 0)); + + fmt = GET_RTX_FORMAT (code); + len = GET_RTX_LENGTH (code); + for (i = 0; i < len; i++) + { + if (fmt[i] == 'e' || fmt[i] == 'u') + max_operand_1 (XEXP (x, i)); + else if (fmt[i] == 'E') + { + int j; + for (j = 0; j < XVECLEN (x, i); j++) + max_operand_1 (XVECEXP (x, i, j)); + } + } +} + +int +max_operand_vec (insn, arg) + rtx insn; + int arg; +{ + register int len = XVECLEN (insn, arg); + register int i; + + max_opno = -1; + max_dup_opno = -1; + + for (i = 0; i < len; i++) + max_operand_1 (XVECEXP (insn, arg, i)); + + return max_opno + 1; +} + +void +print_code (code) + RTX_CODE code; +{ + register char *p1; + for (p1 = GET_RTX_NAME (code); *p1; p1++) + { + if (*p1 >= 'a' && *p1 <= 'z') + putchar (*p1 + 'A' - 'a'); + else + putchar (*p1); + } +} + +/* Print a C expression to construct an RTX just like X, + substituting any operand references appearing within. */ + +void +gen_exp (x) + rtx x; +{ + register RTX_CODE code; + register int i; + register int len; + register char *fmt; + + if (x == 0) + { + printf ("0"); + return; + } + + code = GET_CODE (x); + + switch (code) + { + case MATCH_OPERAND: + case MATCH_DUP: + printf ("operand%d", XINT (x, 0)); + return; + + case MATCH_OPERATOR: + printf ("gen_rtx (GET_CODE (operand%d)", XINT (x, 0)); + printf (", %smode", GET_MODE_NAME (GET_MODE (x))); + for (i = 0; i < XVECLEN (x, 2); i++) + { + printf (",\n\t\t"); + gen_exp (XVECEXP (x, 2, i)); + } + printf (")"); + return; + + case ADDRESS: + fatal ("ADDRESS expression code used in named instruction pattern"); + + case PC: + printf ("pc_rtx"); + return; + + case CC0: + printf ("cc0_rtx"); + return; + + case CONST_INT: + if (INTVAL (x) == 0) + { + printf ("const0_rtx"); + return; + } + if (INTVAL (x) == 1) + { + printf ("const1_rtx"); + return; + } + } + + printf ("gen_rtx ("); + print_code (code); + printf (", %smode", GET_MODE_NAME (GET_MODE (x))); + + fmt = GET_RTX_FORMAT (code); + len = GET_RTX_LENGTH (code); + for (i = 0; i < len; i++) + { + if (fmt[i] == '0') + break; + printf (", "); + if (fmt[i] == 'e' || fmt[i] == 'u') + gen_exp (XEXP (x, i)); + else if (fmt[i] == 'i') + printf ("%d", XINT (x, i)); + else if (fmt[i] == 's') + printf ("\"%s\"", XSTR (x, i)); + else if (fmt[i] == 'E') + { + int j; + printf ("gen_rtvec (%d", XVECLEN (x, i)); + for (j = 0; j < XVECLEN (x, i); j++) + { + printf (",\n\t\t"); + gen_exp (XVECEXP (x, i, j)); + } + printf (")"); + } + else + abort (); + } + printf (")"); +} + +/* Generate the `gen_...' function for a DEFINE_INSN. */ + +void +gen_insn (insn) + rtx insn; +{ + int operands; + register int i; + + /* Don't mention instructions whose names are the null string. + They are in the machine description just to be recognized. */ + if (strlen (XSTR (insn, 0)) == 0) + return; + + /* Find out how many operands this function has, + and also whether any of them have register constraints. */ + register_constraints = 0; + operands = max_operand_vec (insn, 1); + if (max_dup_opno >= operands) + fatal ("match_dup operand number has no match_operand"); + + /* Output the function name and argument declarations. */ + printf ("rtx\ngen_%s (", XSTR (insn, 0)); + for (i = 0; i < operands; i++) + printf (i ? ", operand%d" : "operand%d", i); + printf (")\n"); + for (i = 0; i < operands; i++) + printf (" rtx operand%d;\n", i); + printf ("{\n"); + + /* Output code to construct and return the rtl for the instruction body */ + + if (XVECLEN (insn, 1) == 1) + { + printf (" return "); + gen_exp (XVECEXP (insn, 1, 0)); + printf (";\n}\n\n"); + } + else + { + printf (" return gen_rtx (PARALLEL, VOIDmode, gen_rtvec (%d", XVECLEN (insn, 1)); + for (i = 0; i < XVECLEN (insn, 1); i++) + { + printf (",\n\t\t"); + gen_exp (XVECEXP (insn, 1, i)); + } + printf ("));\n}\n\n"); + } +} + +/* Generate the `gen_...' function for a DEFINE_EXPAND. */ + +void +gen_expand (expand) + rtx expand; +{ + int operands; + register int i; + + if (strlen (XSTR (expand, 0)) == 0) + fatal ("define_expand lacks a name"); + if (XVEC (expand, 1) == 0) + fatal ("define_expand for %s lacks a pattern", XSTR (expand, 0)); + + /* Find out how many operands this function has, + and also whether any of them have register constraints. */ + register_constraints = 0; + + operands = max_operand_vec (expand, 1); + + /* Output the function name and argument declarations. */ + printf ("rtx\ngen_%s (", XSTR (expand, 0)); + for (i = 0; i < operands; i++) + printf (i ? ", operand%d" : "operand%d", i); + printf (")\n"); + for (i = 0; i < operands; i++) + printf (" rtx operand%d;\n", i); + printf ("{\n"); + + /* For each operand referred to only with MATCH_DUPs, + make a local variable. */ + for (i = operands; i <= max_dup_opno; i++) + printf (" rtx operand%d;\n", i); + printf (" rtx operands[%d];\n", max (operands, max_dup_opno + 1)); + printf (" rtx _val;\n"); + printf (" start_sequence ();\n"); + + /* The fourth operand of DEFINE_EXPAND is some code to be executed + before the actual construction. + This code expects to refer to `operands' + just as the output-code in a DEFINE_INSN does, + but here `operands' is an automatic array. + So copy the operand values there before executing it. */ + if (XSTR (expand, 3)) + { + /* Output code to copy the arguments into `operands'. */ + for (i = 0; i < operands; i++) + printf (" operands[%d] = operand%d;\n", i, i); + + /* Output the special code to be executed before the sequence + is generated. */ + printf ("%s\n", XSTR (expand, 3)); + + /* Output code to copy the arguments back out of `operands' + (unless we aren't going to use them at all). */ + if (XVEC (expand, 1) != 0) + { + for (i = 0; i < operands; i++) + printf (" operand%d = operands[%d];\n", i, i); + for (; i <= max_dup_opno; i++) + printf (" operand%d = operands[%d];\n", i, i); + } + } + + /* Output code to construct the rtl for the instruction bodies. + Use emit_insn to add them to the sequence being accumulated. + But don't do this if the user's code has set `no_more' nonzero. */ + + for (i = 0; i < XVECLEN (expand, 1); i++) + { + rtx next = XVECEXP (expand, 1, i); + if ((GET_CODE (next) == SET && GET_CODE (SET_DEST (next)) == PC) + || (GET_CODE (next) == PARALLEL + && GET_CODE (XVECEXP (next, 0, 0)) == SET + && GET_CODE (SET_DEST (XVECEXP (next, 0, 0))) == PC) + || GET_CODE (next) == RETURN) + printf (" emit_jump_insn ("); + else if ((GET_CODE (next) == SET && GET_CODE (SET_SRC (next)) == CALL) + || GET_CODE (next) == CALL + || (GET_CODE (next) == PARALLEL + && GET_CODE (XVECEXP (next, 0, 0)) == SET + && GET_CODE (SET_SRC (XVECEXP (next, 0, 0))) == CALL) + || (GET_CODE (next) == PARALLEL + && GET_CODE (XVECEXP (next, 0, 0)) == CALL)) + printf (" emit_call_insn ("); + else if (GET_CODE (next) == CODE_LABEL) + printf (" emit_label ("); + else if (GET_CODE (next) == MATCH_OPERAND + || GET_CODE (next) == MATCH_OPERATOR + || GET_CODE (next) == MATCH_DUP + || GET_CODE (next) == PARALLEL) + printf (" emit ("); + else + printf (" emit_insn ("); + gen_exp (next); + printf (");\n"); + if (GET_CODE (next) == SET && GET_CODE (SET_DEST (next)) == PC + && GET_CODE (SET_SRC (next)) == LABEL_REF) + printf (" emit_barrier ();"); + } + + /* 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 (" end_sequence ();\n"); + printf (" return _val;\n}\n\n"); +} + +int +xmalloc (size) +{ + register int val = malloc (size); + + if (val == 0) + fatal ("virtual memory exhausted"); + + return val; +} + +int +xrealloc (ptr, size) + char *ptr; + int size; +{ + int result = realloc (ptr, size); + if (!result) + fatal ("virtual memory exhausted"); + return result; +} + +void +fatal (s, a1, a2) + char *s; +{ + fprintf (stderr, "genemit: "); + fprintf (stderr, s, a1, a2); + fprintf (stderr, "\n"); + exit (FATAL_EXIT_CODE); +} + +/* 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; + char **argv; +{ + rtx desc; + FILE *infile; + extern rtx read_rtx (); + register int c; + + obstack_init (rtl_obstack); + + if (argc <= 1) + fatal ("No input file name."); + + infile = fopen (argv[1], "r"); + if (infile == 0) + { + perror (argv[1]); + exit (FATAL_EXIT_CODE); + } + + init_rtl (); + + /* Assign sequential codes to all entries in the machine description + in parallel with the tables in insn-output.c. */ + + insn_code_number = 0; + + printf ("/* Generated automatically by the program `genemit'\n\ +from the machine description file `md'. */\n\n"); + + printf ("#include \"config.h\"\n"); + printf ("#include \"rtl.h\"\n"); + printf ("#include \"expr.h\"\n"); + printf ("#include \"real.h\"\n"); + printf ("#include \"insn-config.h\"\n\n"); + printf ("#include \"insn-flags.h\"\n\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 do { end_sequence (); return 0;} while (0)\n\n"); + printf ("#define DONE goto _done\n\n"); + + /* Read the machine description. */ + + while (1) + { + c = read_skip_spaces (infile); + if (c == EOF) + break; + ungetc (c, infile); + + desc = read_rtx (infile); + if (GET_CODE (desc) == DEFINE_INSN) + { + gen_insn (desc); + ++insn_code_number; + } + if (GET_CODE (desc) == DEFINE_EXPAND) + { + gen_expand (desc); + ++insn_code_number; + } + if (GET_CODE (desc) == DEFINE_PEEPHOLE) + { + ++insn_code_number; + } + } + + fflush (stdout); + exit (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE); +} diff --git a/gcc-1.40/genextract.c b/gcc-1.40/genextract.c new file mode 100644 index 0000000..b98632f --- /dev/null +++ b/gcc-1.40/genextract.c @@ -0,0 +1,348 @@ +/* Generate code from machine description to extract operands from insn as rtl. + Copyright (C) 1987 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 1, 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 +#include "config.h" +#include "rtl.h" +#include "obstack.h" + +struct obstack obstack; +struct obstack *rtl_obstack = &obstack; + +#define obstack_chunk_alloc xmalloc +#define obstack_chunk_free free +extern int xmalloc (); +extern void free (); + +/* Number instruction patterns handled, starting at 0 for first one. */ + +int insn_code_number; + +/* Number the occurrences of MATCH_DUP in each instruction, + starting at 0 for the first occurrence. */ + +int dup_count; + +/* While tree-walking an instruction pattern, we keep a chain + of these `struct link's to record how to get down to the + current position. In each one, POS is the operand number, + and if the operand is a vector VEC is the element number. + VEC is -1 if the operand is not a vector. */ + +struct link +{ + struct link *next; + int pos; + int vecelt; +}; + +void walk_rtx (); +void print_path (); +void fatal (); +void fancy_abort (); + +void +gen_insn (insn) + rtx insn; +{ + register int i; + + dup_count = 0; + + /* Output the function name and argument declaration. */ + /* It would be cleaner to make `void' the return type + but 4.2 vax compiler doesn't accept that in the array + that these functions are supposed to go in. */ + printf ("VOID\nextract_%d (insn)\n rtx insn;\n", insn_code_number); + printf ("{\n"); + + /* Walk the insn's pattern, remembering at all times the path + down to the walking point. */ + + if (XVECLEN (insn, 1) == 1) + walk_rtx (XVECEXP (insn, 1, 0), 0); + else + for (i = XVECLEN (insn, 1) - 1; i >= 0; i--) + { + struct link link; + link.next = 0; + link.pos = 0; + link.vecelt = i; + walk_rtx (XVECEXP (insn, 1, i), &link); + } + printf ("}\n\n"); +} + +/* Like gen_insn but handles `define_peephole'. */ + +void +gen_peephole (peep) + rtx peep; +{ + /* Output the function name and argument declaration. */ + printf ("VOID\nextract_%d (insn)\n rtx insn;\n", insn_code_number); + printf ("{\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 ("\ + bcopy (&XVECEXP (insn, 0, 0), recog_operand,\ + sizeof (rtx) * XVECLEN (insn, 0));\n"); + printf ("}\n\n"); +} + +void +walk_rtx (x, path) + rtx x; + struct link *path; +{ + register RTX_CODE code; + register int i; + register int len; + register char *fmt; + struct link link; + + if (x == 0) + return; + + code = GET_CODE (x); + + switch (code) + { + case PC: + case CC0: + case CONST_INT: + case SYMBOL_REF: + return; + + case MATCH_OPERAND: + printf (" recog_operand[%d] = *(recog_operand_loc[%d]\n = &", + XINT (x, 0), XINT (x, 0)); + print_path (path); + printf (");\n"); + break; + + case MATCH_DUP: + printf (" recog_dup_loc[%d] = &", dup_count); + print_path (path); + printf (";\n"); + printf (" recog_dup_num[%d] = %d;\n", dup_count, XINT (x, 0)); + dup_count++; + break; + + case MATCH_OPERATOR: + printf (" recog_operand[%d] = *(recog_operand_loc[%d]\n = &", + XINT (x, 0), XINT (x, 0)); + print_path (path); + printf (");\n"); + link.next = path; + link.vecelt = -1; + for (i = XVECLEN (x, 2) - 1; i >= 0; i--) + { + link.pos = i; + walk_rtx (XVECEXP (x, 2, i), &link); + } + return; + + case ADDRESS: + walk_rtx (XEXP (x, 0), path); + return; + } + + link.next = path; + link.vecelt = -1; + fmt = GET_RTX_FORMAT (code); + len = GET_RTX_LENGTH (code); + for (i = 0; i < len; i++) + { + link.pos = i; + if (fmt[i] == 'e' || fmt[i] == 'u') + { + walk_rtx (XEXP (x, i), &link); + } + else if (fmt[i] == 'E') + { + int j; + for (j = XVECLEN (x, i) - 1; j >= 0; j--) + { + link.vecelt = j; + walk_rtx (XVECEXP (x, i, j), &link); + } + } + } +} + +/* Given a PATH, representing a path down the instruction's + pattern from the root to a certain point, output code to + evaluate to the rtx at that point. */ + +void +print_path (path) + struct link *path; +{ + if (path == 0) + printf ("insn"); + else if (path->vecelt >= 0) + { + printf ("XVECEXP ("); + print_path (path->next); + printf (", %d, %d)", path->pos, path->vecelt); + } + else + { + printf ("XEXP ("); + print_path (path->next); + printf (", %d)", path->pos); + } +} + +int +xmalloc (size) +{ + register int val = malloc (size); + + if (val == 0) + fatal ("virtual memory exhausted"); + return val; +} + +int +xrealloc (ptr, size) + char *ptr; + int size; +{ + int result = realloc (ptr, size); + if (!result) + fatal ("virtual memory exhausted"); + return result; +} + +void +fatal (s, a1, a2) + char *s; +{ + fprintf (stderr, "genextract: "); + fprintf (stderr, s, a1, a2); + fprintf (stderr, "\n"); + exit (FATAL_EXIT_CODE); +} + +/* 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; + char **argv; +{ + rtx desc; + FILE *infile; + extern rtx read_rtx (); + register int c, i; + + obstack_init (rtl_obstack); + + if (argc <= 1) + fatal ("No input file name."); + + infile = fopen (argv[1], "r"); + if (infile == 0) + { + perror (argv[1]); + exit (FATAL_EXIT_CODE); + } + + init_rtl (); + + /* Assign sequential codes to all entries in the machine description + in parallel with the tables in insn-output.c. */ + + insn_code_number = 0; + + printf ("/* Generated automatically by the program `genextract'\n\ +from the machine description file `md'. */\n\n"); + + printf ("#include \"config.h\"\n"); + printf ("#include \"rtl.h\"\n\n"); + + printf ("extern rtx recog_operand[];\n"); + printf ("extern rtx *recog_operand_loc[];\n"); + printf ("extern rtx *recog_dup_loc[];\n"); + printf ("extern char recog_dup_num[];\n\n"); + + /* The extractor functions really should return `void'; + but old C compilers don't seem to be able to handle the array + definition if `void' is used. So use `int' in non-ANSI C compilers. */ + + printf ("#ifdef __STDC__\n#define VOID void\n#else\n#define VOID int\n#endif\n\n"); + + /* Read the machine description. */ + + while (1) + { + c = read_skip_spaces (infile); + if (c == EOF) + break; + ungetc (c, infile); + + desc = read_rtx (infile); + if (GET_CODE (desc) == DEFINE_INSN) + { + gen_insn (desc); + ++insn_code_number; + } + if (GET_CODE (desc) == DEFINE_PEEPHOLE) + { + gen_peephole (desc); + ++insn_code_number; + } + if (GET_CODE (desc) == DEFINE_EXPAND) + { + printf ("VOID extract_%d () {}\n\n", insn_code_number); + ++insn_code_number; + } + } + + printf ("VOID (*insn_extract_fn[]) () =\n{ "); + for (i = 0; i < insn_code_number; i++) + { + if (i % 4 != 0) + printf (", "); + else if (i != 0) + printf (",\n "); + printf ("extract_%d", i); + } + printf ("\n};\n\n"); + + printf ("void fatal_insn_not_found ();\n\n"); + printf ("void\ninsn_extract (insn)\n"); + printf (" rtx insn;\n"); + printf ("{\n if (INSN_CODE (insn) == -1) fatal_insn_not_found (insn);\n"); + printf (" (*insn_extract_fn[INSN_CODE (insn)]) (PATTERN (insn));\n}\n"); + + fflush (stdout); + exit (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE); +} diff --git a/gcc-1.40/genflags.c b/gcc-1.40/genflags.c new file mode 100644 index 0000000..eb4ebb5 --- /dev/null +++ b/gcc-1.40/genflags.c @@ -0,0 +1,138 @@ +/* Generate from machine description: + + - some flags HAVE_... saying which simple standard instructions are + available for this machine. + Copyright (C) 1987 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 1, 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 +#include "config.h" +#include "rtl.h" +#include "obstack.h" + +struct obstack obstack; +struct obstack *rtl_obstack = &obstack; + +#define obstack_chunk_alloc xmalloc +#define obstack_chunk_free free +extern int xmalloc (); +extern void free (); + +void fatal (); +void fancy_abort (); + +void +gen_insn (insn) + rtx insn; +{ + /* Don't mention instructions whose names are the null string. + They are in the machine description just to be recognized. */ + if (strlen (XSTR (insn, 0)) == 0) + return; + + printf ("#define HAVE_%s (%s)\n", XSTR (insn, 0), + strlen (XSTR (insn, 2)) ? XSTR (insn, 2) : "1"); + printf ("extern rtx gen_%s ();\n", XSTR (insn, 0)); +} + +int +xmalloc (size) +{ + register int val = malloc (size); + + if (val == 0) + fatal ("virtual memory exhausted"); + + return val; +} + +int +xrealloc (ptr, size) + char *ptr; + int size; +{ + int result = realloc (ptr, size); + if (!result) + fatal ("virtual memory exhausted"); + return result; +} + +void +fatal (s, a1, a2) + char *s; +{ + fprintf (stderr, "genflags: "); + fprintf (stderr, s, a1, a2); + fprintf (stderr, "\n"); + exit (FATAL_EXIT_CODE); +} + +/* 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; + char **argv; +{ + rtx desc; + FILE *infile; + extern rtx read_rtx (); + register int c; + + obstack_init (rtl_obstack); + + if (argc <= 1) + fatal ("No input file name."); + + infile = fopen (argv[1], "r"); + if (infile == 0) + { + perror (argv[1]); + exit (FATAL_EXIT_CODE); + } + + init_rtl (); + + printf ("/* Generated automatically by the program `genflags'\n\ +from the machine description file `md'. */\n\n"); + + /* Read the machine description. */ + + while (1) + { + c = read_skip_spaces (infile); + if (c == EOF) + break; + ungetc (c, infile); + + desc = read_rtx (infile); + if (GET_CODE (desc) == DEFINE_INSN || GET_CODE (desc) == DEFINE_EXPAND) + gen_insn (desc); + } + + fflush (stdout); + exit (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE); +} diff --git a/gcc-1.40/genoutput.c b/gcc-1.40/genoutput.c new file mode 100644 index 0000000..da17e9e --- /dev/null +++ b/gcc-1.40/genoutput.c @@ -0,0 +1,786 @@ +/* Generate code from to output assembler insns as recognized from rtl. + Copyright (C) 1987, 1988 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 1, 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 program reads the machine description for the compiler target machine + and produces a file containing three things: + + 1, An array of strings `insn_template' which is indexed by insn code number + and contains the template for output of that insn, + + 2. An array of ints `insn_n_operands' which is indexed by insn code number + and contains the number of distinct operands in the pattern for that insn, + + 3. An array of ints `insn_n_dups' which is indexed by insn code number + and contains the number of match_dup's that appear in the insn's pattern. + This says how many elements of `recog_dup_loc' are significant + after an insn has been recognized. + + 4. An array of arrays of operand constraint strings, + `insn_operand_constraint', + indexed first by insn code number and second by operand number, + containing the constraint for that operand. + + This array is generated only if register constraints appear in + match_operand rtx's. + + 5. An array of arrays of chars which indicate which operands of + which insn patterns appear within ADDRESS rtx's. This array is + called `insn_operand_address_p' and is generated only if there + are *no* register constraints in the match_operand rtx's. + + 6. An array of arrays of machine modes, `insn_operand_mode', + indexed first by insn code number and second by operand number, + containing the machine mode that that operand is supposed to have. + Also `insn_operand_strict_low', which is nonzero for operands + contained in a STRICT_LOW_PART. + + 7. An array of arrays of int-valued functions, `insn_operand_predicate', + indexed first by insn code number and second by operand number, + containing the match_operand predicate for this operand. + + 8. An array of functions `insn_gen_function' which, indexed + by insn code number, gives the function to generate a body + for that patter, given operands as arguments. + + 9. A function `output_insn_hairy' which is called with two arguments + (an insn code number and a vector of operand value rtx's) + and returns a template to use for output of that insn. + This is used only in the cases where the template is not constant. + These cases are specified by a * at the beginning of the template string + in the machine description. They are identified for the sake of + other parts of the compiler by a zero element in `insn_template'. + + 10. An array of structures, `insn_machine_info', that gives machine-specific + information about the insn. + + 11. An array of ints, `insn_n_alternatives', that gives the number + of alternatives in the constraints of each pattern. + +The code number of an insn is simply its position in the machine description; +code numbers are assigned sequentially to entries in the description, +starting with code number 0. + +Thus, the following entry in the machine description + + (define_insn "clrdf" + [(set (match_operand:DF 0 "general_operand" "") + (const_int 0))] + "" + "clrd %0") + +assuming it is the 25th entry present, would cause +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 +#include "config.h" +#include "rtl.h" +#include "obstack.h" + +/* No instruction can have more operands than this. + Sorry for this arbitrary limit, but what machine will + have an instruction with this many operands? */ + +#define MAX_MAX_OPERANDS 40 + +struct obstack obstack; +struct obstack *rtl_obstack = &obstack; + +#define obstack_chunk_alloc xmalloc +#define obstack_chunk_free free +extern int xmalloc (); +extern void free (); + +void fatal (); +void fancy_abort (); +void error (); +void mybcopy (); +void mybzero (); + +/* insns in the machine description are assigned sequential code numbers + that are used by insn-recog.c (produced by genrecog) to communicate + to insn-output.c (produced by this program). */ + +int next_code_number; + +/* Record in this chain all information that we will output, + associated with the code number of the insn. */ + +struct data +{ + int code_number; + char *name; + char *template; /* string such as "movl %1,%0" */ + int n_operands; /* Number of operands this insn recognizes */ + int n_dups; /* Number times match_dup appears in pattern */ + int n_alternatives; /* Number of alternatives in each constraint */ + struct data *next; + char *constraints[MAX_MAX_OPERANDS]; + /* Number of alternatives in constraints of operand N. */ + int op_n_alternatives[MAX_MAX_OPERANDS]; + char *predicates[MAX_MAX_OPERANDS]; + char address_p[MAX_MAX_OPERANDS]; + enum machine_mode modes[MAX_MAX_OPERANDS]; + char strict_low[MAX_MAX_OPERANDS]; + char outfun; /* Nonzero means this has an output function */ + char *machine_info; /* machine-specific info string. */ +}; + +/* This variable points to the first link in the chain. */ + +struct data *insn_data; + +/* Pointer to the last link in the chain, so new elements + can be added at the end. */ + +struct data *end_of_insn_data; + +/* Nonzero if any match_operand has a constraint string; + implies that REGISTER_CONSTRAINTS will be defined + for this machine description. */ + +int have_constraints; + +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 \"rtl.h\"\n"); + printf ("#include \"regs.h\"\n"); + printf ("#include \"hard-reg-set.h\"\n"); + printf ("#include \"real.h\"\n"); + printf ("#include \"conditions.h\"\n"); + printf ("#include \"insn-flags.h\"\n"); + printf ("#include \"insn-config.h\"\n\n"); + + printf ("#ifndef __STDC__\n"); + printf ("#define const\n"); + printf ("#endif\n\n"); + + printf ("#include \"output.h\"\n"); + printf ("#include \"aux-output.c\"\n\n"); + + /* Make sure there is at least a dummy definition of INSN_MACHINE_INFO. */ + printf ("#ifndef INSN_MACHINE_INFO\n"); + printf ("#define INSN_MACHINE_INFO struct dummy1 {int i;}\n"); + printf ("#endif\n\n"); +} + +void +output_epilogue () +{ + register struct data *d; + + printf ("\nchar * const insn_template[] =\n {\n"); + for (d = insn_data; d; d = d->next) + { + if (d->template) + printf (" \"%s\",\n", d->template); + else + printf (" 0,\n"); + } + printf (" };\n"); + + printf ("\nchar *(*const insn_outfun[])() =\n {\n"); + for (d = insn_data; d; d = d->next) + { + if (d->outfun) + printf (" output_%d,\n", d->code_number); + else + printf (" 0,\n"); + } + printf (" };\n"); + + printf ("\nrtx (*const insn_gen_function[]) () =\n {\n"); + for (d = insn_data; d; d = d->next) + { + if (d->name) + printf (" gen_%s,\n", d->name); + else + printf (" 0,\n"); + } + printf (" };\n"); + + printf ("\nconst int insn_n_operands[] =\n {\n"); + for (d = insn_data; d; d = d->next) + { + printf (" %d,\n", d->n_operands); + } + printf (" };\n"); + + printf ("\nconst int insn_n_dups[] =\n {\n"); + for (d = insn_data; d; d = d->next) + { + printf (" %d,\n", d->n_dups); + } + printf (" };\n"); + + if (have_constraints) + { + printf ("\nchar *const insn_operand_constraint[][MAX_RECOG_OPERANDS] =\n {\n"); + for (d = insn_data; d; d = d->next) + { + register int i, n = 0, start; + printf (" {"); + /* Make sure all the operands have the same number of + alternatives in their constraints. + Let N be that number. */ + for (start = 0; start < d->n_operands; start++) + if (d->op_n_alternatives[start] > 0) + { + if (n == 0) + n = d->op_n_alternatives[start]; + else if (n != d->op_n_alternatives[start]) + error ("wrong number of alternatives in operand %d of insn number %d", + start, d->code_number); + } + /* Record the insn's overall number of alternatives. */ + d->n_alternatives = n; + + for (i = 0; i < d->n_operands; i++) + { + if (d->constraints[i] == 0) + printf (" \"\","); + else + printf (" \"%s\",", d->constraints[i]); + } + if (d->n_operands == 0) + printf (" 0"); + printf (" },\n"); + } + printf (" };\n"); + } + else + { + printf ("\nconst char insn_operand_address_p[][MAX_RECOG_OPERANDS] =\n {\n"); + for (d = insn_data; d; d = d->next) + { + register int i; + printf (" {"); + for (i = 0; i < d->n_operands; i++) + printf (" %d,", d->address_p[i]); + if (d->n_operands == 0) + printf (" 0"); + printf (" },\n"); + } + printf (" };\n"); + } + + printf ("\nconst enum machine_mode insn_operand_mode[][MAX_RECOG_OPERANDS] =\n {\n"); + for (d = insn_data; d; d = d->next) + { + register int i; + printf (" {"); + for (i = 0; i < d->n_operands; i++) + printf (" %smode,", GET_MODE_NAME (d->modes[i])); + if (d->n_operands == 0) + printf (" VOIDmode"); + printf (" },\n"); + } + printf (" };\n"); + + printf ("\nconst char insn_operand_strict_low[][MAX_RECOG_OPERANDS] =\n {\n"); + for (d = insn_data; d; d = d->next) + { + register int i; + printf (" {"); + for (i = 0; i < d->n_operands; i++) + printf (" %d,", d->strict_low[i]); + if (d->n_operands == 0) + printf (" 0"); + printf (" },\n"); + } + printf (" };\n"); + + printf ("\nint (*const insn_operand_predicate[][MAX_RECOG_OPERANDS])() =\n {\n"); + for (d = insn_data; d; d = d->next) + { + register int i; + printf (" {"); + for (i = 0; i < d->n_operands; i++) + printf (" %s,", ((d->predicates[i] && d->predicates[i][0]) + ? d->predicates[i] : "0")); + if (d->n_operands == 0) + printf (" 0"); + printf (" },\n"); + } + printf (" };\n"); + + printf ("\n#ifndef DEFAULT_MACHINE_INFO\n#define DEFAULT_MACHINE_INFO 0\n"); + printf ("#endif\n\nconst INSN_MACHINE_INFO insn_machine_info[] =\n {\n"); + for (d = insn_data; d; d = d->next) + { + if (d->machine_info) + printf (" {%s},\n", d->machine_info); + else + printf(" { DEFAULT_MACHINE_INFO },\n"); + } + printf(" };\n"); + + printf ("\nconst int insn_n_alternatives[] =\n {\n"); + for (d = insn_data; d; d = d->next) + { + if (d->n_alternatives) + printf (" %d,\n", d->n_alternatives); + else + printf(" 0,\n"); + } + printf(" };\n"); +} + +/* scan_operands (X) stores in max_opno the largest operand + number present in X, if that is larger than the previous + value of max_opno. It stores all the constraints in `constraints' + and all the machine modes in `modes'. + + THIS_ADDRESS_P is nonzero if the containing rtx was an ADDRESS. + THIS_STRICT_LOW is nonzero if the containing rtx was a STRICT_LOW_PART. */ + +int max_opno; +int num_dups; +char *constraints[MAX_MAX_OPERANDS]; +int op_n_alternatives[MAX_MAX_OPERANDS]; +char *predicates[MAX_MAX_OPERANDS]; +char address_p[MAX_MAX_OPERANDS]; +enum machine_mode modes[MAX_MAX_OPERANDS]; +char strict_low[MAX_MAX_OPERANDS]; + +void +scan_operands (part, this_address_p, this_strict_low) + rtx part; + int this_address_p; + int this_strict_low; +{ + register int i, j; + register RTX_CODE code; + register char *format_ptr; + + if (part == 0) + return; + + code = GET_CODE (part); + + if (code == MATCH_OPERAND) + { + int opno = XINT (part, 0); + if (opno > max_opno) + max_opno = opno; + if (max_opno >= MAX_MAX_OPERANDS) + error ("Too many operands (%d) in one instruction pattern.\n", + max_opno + 1); + modes[opno] = GET_MODE (part); + strict_low[opno] = this_strict_low; + predicates[opno] = XSTR (part, 1); + constraints[opno] = XSTR (part, 2); + if (XSTR (part, 2) != 0 && *XSTR (part, 2) != 0) + { + op_n_alternatives[opno] = n_occurrences (',', XSTR (part, 2)) + 1; + have_constraints = 1; + } + address_p[opno] = this_address_p; + return; + } + + if (code == MATCH_OPERATOR) + { + int opno = XINT (part, 0); + if (opno > max_opno) + max_opno = opno; + if (max_opno >= MAX_MAX_OPERANDS) + error ("Too many operands (%d) in one instruction pattern.\n", + max_opno + 1); + modes[opno] = GET_MODE (part); + strict_low[opno] = 0; + predicates[opno] = XSTR (part, 1); + constraints[opno] = 0; + address_p[opno] = 0; + for (i = 0; i < XVECLEN (part, 2); i++) + scan_operands (XVECEXP (part, 2, i), 0, 0); + return; + } + + if (code == MATCH_DUP) + { + ++num_dups; + return; + } + + if (code == ADDRESS) + { + scan_operands (XEXP (part, 0), 1, 0); + return; + } + + if (code == STRICT_LOW_PART) + { + scan_operands (XEXP (part, 0), 0, 1); + return; + } + + format_ptr = GET_RTX_FORMAT (GET_CODE (part)); + + for (i = 0; i < GET_RTX_LENGTH (GET_CODE (part)); i++) + switch (*format_ptr++) + { + case 'e': + scan_operands (XEXP (part, i), 0, 0); + break; + case 'E': + if (XVEC (part, i) != NULL) + for (j = 0; j < XVECLEN (part, i); j++) + scan_operands (XVECEXP (part, i, j), 0, 0); + break; + } +} + +/* Look at a define_insn just read. Assign its code number. + Record on insn_data the template and the number of arguments. + If the insn has a hairy output action, output a function for now. */ + +void +gen_insn (insn) + rtx insn; +{ + register struct data *d = (struct data *) xmalloc (sizeof (struct data)); + register int i; + + d->code_number = next_code_number++; + if (XSTR (insn, 0)[0]) + d->name = XSTR (insn, 0); + else + d->name = 0; + + /* Build up the list in the same order as the insns are seen + in the machine description. */ + d->next = 0; + if (end_of_insn_data) + end_of_insn_data->next = d; + else + insn_data = d; + + end_of_insn_data = d; + + max_opno = -1; + num_dups = 0; + + mybzero (constraints, sizeof constraints); + mybzero (op_n_alternatives, sizeof op_n_alternatives); + mybzero (predicates, sizeof predicates); + mybzero (address_p, sizeof address_p); + mybzero (modes, sizeof modes); + mybzero (strict_low, sizeof strict_low); + for (i = 0; i < XVECLEN (insn, 1); i++) + scan_operands (XVECEXP (insn, 1, i), 0, 0); + d->n_operands = max_opno + 1; + d->n_dups = num_dups; + mybcopy (constraints, d->constraints, sizeof constraints); + mybcopy (op_n_alternatives, d->op_n_alternatives, sizeof op_n_alternatives); + mybcopy (predicates, d->predicates, sizeof predicates); + mybcopy (address_p, d->address_p, sizeof address_p); + mybcopy (modes, d->modes, sizeof modes); + mybcopy (strict_low, d->strict_low, sizeof strict_low); + d->machine_info = XSTR (insn, 4); + + /* We need to consider only the instructions whose assembler code template + starts with a *. These are the ones where the template is really + C code to run to decide on a template to use. + So for all others just return now. */ + + if (XSTR (insn, 3)[0] != '*') + { + d->template = XSTR (insn, 3); + d->outfun = 0; + return; + } + + d->template = 0; + d->outfun = 1; + + printf ("\nstatic char *\n"); + printf ("output_%d (operands, insn)\n", d->code_number); + printf (" rtx *operands;\n"); + printf (" rtx insn;\n"); + printf ("{\n"); + /* The following is done in a funny way to get around problems in + VAX-11 "C" on VMS. It is the equivalent of: + printf ("%s\n", &(XSTR (insn, 3)[1])); */ + { + register char *cp = &(XSTR (insn, 3)[1]); + while (*cp) putchar (*cp++); + putchar ('\n'); + } + printf ("}\n"); +} + +/* Look at a define_peephole just read. Assign its code number. + Record on insn_data the template and the number of arguments. + If the insn has a hairy output action, output it now. */ + +void +gen_peephole (peep) + rtx peep; +{ + register struct data *d = (struct data *) xmalloc (sizeof (struct data)); + register int i; + + d->code_number = next_code_number++; + d->name = 0; + + /* Build up the list in the same order as the insns are seen + in the machine description. */ + d->next = 0; + if (end_of_insn_data) + end_of_insn_data->next = d; + else + insn_data = d; + + end_of_insn_data = d; + + max_opno = -1; + mybzero (constraints, sizeof constraints); + mybzero (op_n_alternatives, sizeof op_n_alternatives); + + /* Get the number of operands by scanning all the + patterns of the peephole optimizer. + But ignore all the rest of the information thus obtained. */ + for (i = 0; i < XVECLEN (peep, 0); i++) + scan_operands (XVECEXP (peep, 0, i), 0, 0); + + d->n_operands = max_opno + 1; + d->n_dups = 0; + mybcopy (constraints, d->constraints, sizeof constraints); + mybcopy (op_n_alternatives, d->op_n_alternatives, sizeof op_n_alternatives); + mybzero (d->predicates, sizeof predicates); + mybzero (d->address_p, sizeof address_p); + mybzero (d->modes, sizeof modes); + mybzero (d->strict_low, sizeof strict_low); + d->machine_info = XSTR (peep, 3); + + /* We need to consider only the instructions whose assembler code template + starts with a *. These are the ones where the template is really + C code to run to decide on a template to use. + So for all others just return now. */ + + if (XSTR (peep, 2)[0] != '*') + { + d->template = XSTR (peep, 2); + d->outfun = 0; + return; + } + + d->template = 0; + d->outfun = 1; + + printf ("\nstatic char *\n"); + printf ("output_%d (operands, insn)\n", d->code_number); + printf (" rtx *operands;\n"); + printf (" rtx insn;\n"); + printf ("{\n"); + printf ("%s\n", &(XSTR (peep, 2)[1])); + printf ("}\n"); +} + +/* Process a define_expand just read. Assign its code number, + only for the purposes of `insn_gen_function'. */ + +void +gen_expand (insn) + rtx insn; +{ + register struct data *d = (struct data *) xmalloc (sizeof (struct data)); + register int i; + + d->code_number = next_code_number++; + if (XSTR (insn, 0)[0]) + d->name = XSTR (insn, 0); + else + d->name = 0; + + /* Build up the list in the same order as the insns are seen + in the machine description. */ + d->next = 0; + if (end_of_insn_data) + end_of_insn_data->next = d; + else + insn_data = d; + + end_of_insn_data = d; + + max_opno = -1; + num_dups = 0; + + /* Scan the operands to get the specified predicates and modes, + since expand_binop needs to know them. */ + + mybzero (predicates, sizeof predicates); + mybzero (modes, sizeof modes); + if (XVEC (insn, 1)) + for (i = 0; i < XVECLEN (insn, 1); i++) + scan_operands (XVECEXP (insn, 1, i), 0, 0); + d->n_operands = max_opno + 1; + mybcopy (predicates, d->predicates, sizeof predicates); + mybcopy (modes, d->modes, sizeof modes); + + mybzero (d->constraints, sizeof constraints); + mybzero (d->op_n_alternatives, sizeof op_n_alternatives); + mybzero (d->address_p, sizeof address_p); + mybzero (d->strict_low, sizeof strict_low); + + d->n_dups = 0; + d->template = 0; + d->outfun = 0; + d->machine_info = 0; +} + +int +xmalloc (size) +{ + register int val = malloc (size); + + if (val == 0) + fatal ("virtual memory exhausted"); + return val; +} + +int +xrealloc (ptr, size) + char *ptr; + int size; +{ + int result = realloc (ptr, size); + if (!result) + fatal ("virtual memory exhausted"); + return result; +} + +void +mybzero (b, length) + register char *b; + register int length; +{ + while (length-- > 0) + *b++ = 0; +} + +void +mybcopy (b1, b2, length) + register char *b1; + register char *b2; + register int length; +{ + while (length-- > 0) + *b2++ = *b1++; +} + +void +fatal (s, a1, a2) + char *s; +{ + fprintf (stderr, "genoutput: "); + fprintf (stderr, s, a1, a2); + fprintf (stderr, "\n"); + exit (FATAL_EXIT_CODE); +} + +/* 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."); +} + +void +error (s, a1, a2) + char *s; +{ + fprintf (stderr, "genoutput: "); + fprintf (stderr, s, a1, a2); + fprintf (stderr, "\n"); +} + +int +main (argc, argv) + int argc; + char **argv; +{ + rtx desc; + FILE *infile; + extern rtx read_rtx (); + register int c; + + obstack_init (rtl_obstack); + + if (argc <= 1) + fatal ("No input file name."); + + infile = fopen (argv[1], "r"); + if (infile == 0) + { + perror (argv[1]); + exit (FATAL_EXIT_CODE); + } + + init_rtl (); + + output_prologue (); + next_code_number = 0; + have_constraints = 0; + + /* Read the machine description. */ + + while (1) + { + c = read_skip_spaces (infile); + if (c == EOF) + break; + ungetc (c, infile); + + desc = read_rtx (infile); + if (GET_CODE (desc) == DEFINE_INSN) + gen_insn (desc); + if (GET_CODE (desc) == DEFINE_PEEPHOLE) + gen_peephole (desc); + if (GET_CODE (desc) == DEFINE_EXPAND) + gen_expand (desc); + } + + output_epilogue (); + + fflush (stdout); + exit (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE); +} + +int +n_occurrences (c, s) + char c; + char *s; +{ + int n = 0; + while (*s) + n += (*s++ == c); + return n; +} diff --git a/gcc-1.40/genpeep.c b/gcc-1.40/genpeep.c new file mode 100644 index 0000000..7553485 --- /dev/null +++ b/gcc-1.40/genpeep.c @@ -0,0 +1,437 @@ +/* Generate code from machine description to perform peephole optimizations. + Copyright (C) 1987, 1989 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 1, 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 +#include "config.h" +#include "rtl.h" +#include "obstack.h" + +struct obstack obstack; +struct obstack *rtl_obstack = &obstack; + +#define obstack_chunk_alloc xmalloc +#define obstack_chunk_free free +extern int xmalloc (); +extern void free (); + +/* While tree-walking an instruction pattern, we keep a chain + of these `struct link's to record how to get down to the + current position. In each one, POS is the operand number, + and if the operand is a vector VEC is the element number. + VEC is -1 if the operand is not a vector. */ + +struct link +{ + struct link *next; + int pos; + int vecelt; +}; + +void match_rtx (); +void gen_exp (); +void fatal (); +void fancy_abort (); + +int max_opno; + +/* Number of operands used in current peephole definition. */ + +int n_operands; + +/* Peephole optimizations get insn codes just like insn patterns. + Count them so we know the code of the define_peephole we are handling. */ + +int insn_code_number = 0; + +void print_path (); +void print_code (); + +void +gen_peephole (peep) + rtx peep; +{ + int ninsns = XVECLEN (peep, 0); + int i; + + n_operands = 0; + + printf (" insn = ins1;\n"); +#if 0 + printf (" want_jump = 0;\n"); +#endif + + for (i = 0; i < ninsns; i++) + { + if (i > 0) + { + printf (" do { insn = NEXT_INSN (insn);\n"); + printf (" if (insn == 0) goto L%d; }\n", + insn_code_number); + printf (" while (GET_CODE (insn) == NOTE);\n"); + + printf (" if (GET_CODE (insn) == CODE_LABEL\n\ + || GET_CODE (insn) == BARRIER)\n goto L%d;\n", + insn_code_number); + } + +#if 0 + printf (" if (GET_CODE (insn) == JUMP_INSN)\n"); + printf (" want_jump = JUMP_LABEL (insn);\n"); +#endif + + printf (" pat = PATTERN (insn);\n"); + + /* Walk the insn's pattern, remembering at all times the path + down to the walking point. */ + + match_rtx (XVECEXP (peep, 0, i), 0, insn_code_number); + } + + /* We get this far if the pattern matches. + Now test the extra condition. */ + + if (XSTR (peep, 1) && XSTR (peep, 1)[0]) + printf (" if (! (%s)) goto L%d;\n", + XSTR (peep, 1), insn_code_number); + + /* If that matches, construct new pattern and put it in the first insn. + This new pattern will never be matched. + It exists only so that insn-extract can get the operands back. + 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); + +#if 0 + printf (" if (want_jump && GET_CODE (ins1) != JUMP_INSN)\n"); + printf (" {\n"); + printf (" rtx insn2 = emit_jump_insn_before (PATTERN (ins1), ins1);\n"); + printf (" delete_insn (ins1);\n"); + printf (" ins1 = ins2;\n"); + printf (" }\n"); +#endif + + /* Record this define_peephole's insn code in the insn, + as if it had been recognized to match this. */ + printf (" INSN_CODE (ins1) = %d;\n", + insn_code_number); + + /* Delete the remaining insns. */ + if (ninsns > 1) + printf (" delete_for_peephole (NEXT_INSN (ins1), insn);\n"); + + /* See reload1.c for insertion of NOTE which guarantees that this + cannot be zero. */ + printf (" return NEXT_INSN (insn);\n"); + + printf (" L%d:\n\n", insn_code_number); +} + +void +match_rtx (x, path, fail_label) + rtx x; + struct link *path; + int fail_label; +{ + register RTX_CODE code; + register int i; + register int len; + register char *fmt; + struct link link; + + if (x == 0) + return; + + + code = GET_CODE (x); + + switch (code) + { + case MATCH_OPERAND: + if (XINT (x, 0) > max_opno) + max_opno = XINT (x, 0); + if (XINT (x, 0) >= n_operands) + n_operands = 1 + XINT (x, 0); + + printf (" x = "); + print_path (path); + printf (";\n"); + + printf (" operands[%d] = x;\n", XINT (x, 0)); + if (XSTR (x, 1) && XSTR (x, 1)[0]) + printf (" if (! %s (x, %smode)) goto L%d;\n", + XSTR (x, 1), GET_MODE_NAME (GET_MODE (x)), fail_label); + return; + + case MATCH_DUP: + printf (" x = "); + print_path (path); + printf (";\n"); + + printf (" if (!rtx_equal_p (operands[%d], x)) goto L%d;\n", + XINT (x, 0), fail_label); + return; + + case MATCH_OPERATOR: + if (XINT (x, 0) > max_opno) + max_opno = XINT (x, 0); + if (XINT (x, 0) >= n_operands) + n_operands = 1 + XINT (x, 0); + + printf (" x = (rtx)"); + print_path (path); + printf (";\n"); + + printf (" operands[%d] = x;\n", XINT (x, 0)); + if (XSTR (x, 1) && XSTR (x, 1)[0]) + printf (" if (! %s (x, %smode)) goto L%d;\n", + XSTR (x, 1), GET_MODE_NAME (GET_MODE (x)), fail_label); + link.next = path; + link.vecelt = -1; + for (i = 0; i < XVECLEN (x, 2); i++) + { + link.pos = i; + match_rtx (XVECEXP (x, 2, i), &link, fail_label); + } + return; + + case ADDRESS: + match_rtx (XEXP (x, 0), path, fail_label); + return; + } + + printf (" x = "); + print_path (path); + printf (";\n"); + + printf (" if (GET_CODE (x) != "); + print_code (code); + printf (") goto L%d;\n", fail_label); + + if (GET_MODE (x) != VOIDmode) + { + printf (" if (GET_MODE (x) != %smode) goto L%d;\n", + GET_MODE_NAME (GET_MODE (x)), fail_label); + } + + link.next = path; + link.vecelt = -1; + fmt = GET_RTX_FORMAT (code); + len = GET_RTX_LENGTH (code); + for (i = 0; i < len; i++) + { + link.pos = i; + if (fmt[i] == 'e' || fmt[i] == 'u') + match_rtx (XEXP (x, i), &link, fail_label); + else if (fmt[i] == 'E') + { + int j; + printf (" if (XVECLEN (x, %d) != %d) goto L%d;\n", + i, XVECLEN (x, i), fail_label); + for (j = XVECLEN (x, i) - 1; j >= 0; j--) + { + link.vecelt = j; + match_rtx (XVECEXP (x, i, j), &link, fail_label); + } + } + else if (fmt[i] == 'i') + { + /* Make sure that at run time `x' is the RTX we want to test. */ + if (i != 0) + { + printf (" x = "); + print_path (path); + printf (";\n"); + } + + printf (" if (XINT (x, %d) != %d) goto L%d;\n", + i, XINT (x, i), fail_label); + } + else if (fmt[i] == 's') + { + /* Make sure that at run time `x' is the RTX we want to test. */ + if (i != 0) + { + printf (" x = "); + print_path (path); + printf (";\n"); + } + + printf (" if (strcmp (XSTR (x, %d), \"%s\")) goto L%d;\n", + i, XSTR (x, i), fail_label); + } + } +} + +/* Given a PATH, representing a path down the instruction's + pattern from the root to a certain point, output code to + evaluate to the rtx at that point. */ + +void +print_path (path) + struct link *path; +{ + if (path == 0) + printf ("pat"); + else if (path->vecelt >= 0) + { + printf ("XVECEXP ("); + print_path (path->next); + printf (", %d, %d)", path->pos, path->vecelt); + } + else + { + printf ("XEXP ("); + print_path (path->next); + printf (", %d)", path->pos); + } +} + +void +print_code (code) + RTX_CODE code; +{ + register char *p1; + for (p1 = GET_RTX_NAME (code); *p1; p1++) + { + if (*p1 >= 'a' && *p1 <= 'z') + putchar (*p1 + 'A' - 'a'); + else + putchar (*p1); + } +} + +int +xmalloc (size) +{ + register int val = malloc (size); + + if (val == 0) + fatal ("virtual memory exhausted"); + return val; +} + +int +xrealloc (ptr, size) + char *ptr; + int size; +{ + int result = realloc (ptr, size); + if (!result) + fatal ("virtual memory exhausted"); + return result; +} + +void +fatal (s, a1, a2) + char *s; +{ + fprintf (stderr, "genpeep: "); + fprintf (stderr, s, a1, a2); + fprintf (stderr, "\n"); + exit (FATAL_EXIT_CODE); +} + +/* 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; + char **argv; +{ + rtx desc; + FILE *infile; + extern rtx read_rtx (); + register int c; + + max_opno = -1; + + obstack_init (rtl_obstack); + + if (argc <= 1) + fatal ("No input file name."); + + infile = fopen (argv[1], "r"); + if (infile == 0) + { + perror (argv[1]); + exit (FATAL_EXIT_CODE); + } + + init_rtl (); + + printf ("/* Generated automatically by the program `genpeep'\n\ +from the machine description file `md'. */\n\n"); + + printf ("#include \"config.h\"\n"); + printf ("#include \"rtl.h\"\n"); + printf ("#include \"regs.h\"\n"); + printf ("#include \"real.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"); + + /* Early out: no peepholes for insns followed by barriers. */ + printf (" if (NEXT_INSN (ins1)\n"); + printf (" && GET_CODE (NEXT_INSN (ins1)) == BARRIER)\n"); + printf (" return 0;\n\n"); + + /* Read the machine description. */ + + while (1) + { + c = read_skip_spaces (infile); + if (c == EOF) + break; + ungetc (c, infile); + + desc = read_rtx (infile); + if (GET_CODE (desc) == DEFINE_PEEPHOLE) + { + gen_peephole (desc); + insn_code_number++; + } + if (GET_CODE (desc) == DEFINE_INSN || GET_CODE (desc) == DEFINE_EXPAND) + { + insn_code_number++; + } + } + + printf (" return 0;\n}\n\n"); + + if (max_opno == -1) + max_opno = 1; + + printf ("rtx peep_operand[%d];\n", max_opno + 1); + + fflush (stdout); + exit (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE); +} diff --git a/gcc-1.40/genrecog.c b/gcc-1.40/genrecog.c new file mode 100644 index 0000000..be759ba --- /dev/null +++ b/gcc-1.40/genrecog.c @@ -0,0 +1,1095 @@ +/* Generate code from machine description to emit insns as rtl. + Copyright (C) 1987,1988 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 1, 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 program is used to produce insn-recog.c, which contains + a function called `recog' plus its subroutines. + These functions contain a decision tree + that recognizes whether an rtx, the argument given to recog, + is a valid instruction. + + recog returns -1 if the rtx is not valid. + If the rtx is valid, recog returns a nonnegative number + which is the insn code number for the pattern that matched. + This is the same as the order in the machine description of the + entry that matched. This number can be used as an index into + insn_templates and insn_n_operands (found in insn-output.c) + or as an argument to output_insn_hairy (also in insn-output.c). */ + +#include +#include "config.h" +#include "rtl.h" +#include "obstack.h" + +struct obstack obstack; +struct obstack *rtl_obstack = &obstack; + +#define obstack_chunk_alloc xmalloc +#define obstack_chunk_free free +extern int xmalloc (); +extern void free (); + +/* Data structure for decision tree for recognizing + legitimate instructions. */ + +struct decision +{ + int number; + char *position; + RTX_CODE code; + char *exact; + enum machine_mode mode; + char *tests; + int insn_code_number; + struct decision *next; + struct decision *success; + int opno; + int dupno; + int dupcount; + int test_elt_zero_int; + int elt_zero_int; + int test_elt_one_int; + int elt_one_int; + int ignmode; + struct decision *afterward; + int label_needed; + char *c_test; + char *reg_class; + char enforce_mode; + int veclen; + int subroutine_number; +}; + +#define SUBROUTINE_THRESHOLD 50 + +int next_subroutine_number; + +/* +recognize (top) +{ + staten: + x = XVECEXP (top, 0, 3); + if (test_code (GET_CODE (x)) + && test_mode (MODE (x)) + && whatever_else) + goto statep; + else if (next one...) + goto statem: + goto stater; + + statep: + actions...; + return 1; + + statem: + x = stack[depth--]; + more tests...; + + stateq: + stack[++depth] = x; + x = XEXP (stack[depth], 0); + more tests...; + + stater: + x = XEXP (stack[depth], 1); +} + +*/ + +int next_number; + +int next_insn_code; + +/* Number of MATCH_DUP's seen so far in this instruction. */ +int dupcount; + +struct decision *add_to_sequence (); +struct decision *try_merge_2 (); +void write_subroutine (); +void print_code (); +void clear_codes (); +void clear_modes (); +void change_state (); +void write_tree (); +char *copystr (); +char *concat (); +void fatal (); +void fancy_abort (); +void mybzero (); + +struct decision *first; + +/* Construct and return a sequence of decisions + that will recognize INSN. */ + +struct decision * +make_insn_sequence (insn) + rtx insn; +{ + rtx x; + char *c_test = XSTR (insn, 2); + struct decision *last; + + dupcount = 0; + + if (XVECLEN (insn, 1) == 1) + x = XVECEXP (insn, 1, 0); + else + { + x = rtx_alloc (PARALLEL); + XVEC (x, 0) = XVEC (insn, 1); + PUT_MODE (x, VOIDmode); + } + + last = add_to_sequence (x, 0, ""); + + if (c_test[0]) + last->c_test = c_test; + last->insn_code_number = next_insn_code++; + + return first; +} + +struct decision * +add_to_sequence (pattern, last, position) + rtx pattern; + struct decision *last; + char *position; +{ + register RTX_CODE code; + register struct decision *new + = (struct decision *) xmalloc (sizeof (struct decision)); + struct decision *this; + char *newpos; + register char *fmt; + register int i; + int depth; + int len; + + new->number = next_number++; + new->position = copystr (position); + new->exact = 0; + new->next = 0; + new->success = 0; + new->insn_code_number = -1; + new->tests = 0; + new->opno = -1; + new->dupno = -1; + new->dupcount = -1; + new->test_elt_zero_int = 0; + new->test_elt_one_int = 0; + new->elt_zero_int = 0; + new->elt_one_int = 0; + new->enforce_mode = 0; + new->ignmode = 0; + new->afterward = 0; + new->label_needed = 0; + new->c_test = 0; + new->reg_class = 0; + new->veclen = 0; + new->subroutine_number = 0; + + this = new; + + if (last == 0) + first = new; + else + last->success = new; + + depth = strlen (position); + newpos = (char *) alloca (depth + 2); + strcpy (newpos, position); + newpos[depth + 1] = 0; + + restart: + + if (pattern == 0) + { + new->exact = "0"; + new->code = UNKNOWN; + new->mode = VOIDmode; + return new; + } + + switch (GET_MODE (pattern)) + { + case 0: + new->mode = VOIDmode; + break; + + default: + new->mode = GET_MODE (pattern); + break; + } + + new->code = code = GET_CODE (pattern); + + switch (code) + { + case MATCH_OPERAND: + new->opno = XINT (pattern, 0); + new->code = UNKNOWN; + new->tests = XSTR (pattern, 1); + if (*new->tests == 0) + new->tests = 0; + new->reg_class = XSTR (pattern, 2); + if (*new->reg_class == 0) + new->reg_class = 0; + return new; + + case MATCH_OPERATOR: + new->opno = XINT (pattern, 0); + new->code = UNKNOWN; + new->tests = XSTR (pattern, 1); + if (*new->tests == 0) + new->tests = 0; + for (i = 0; i < XVECLEN (pattern, 2); i++) + { + newpos[depth] = i + '0'; + new = add_to_sequence (XVECEXP (pattern, 2, i), new, newpos); + } + this->success->enforce_mode = 0; + return new; + + case MATCH_DUP: + new->dupno = XINT (pattern, 0); + new->dupcount = dupcount++; + new->code = UNKNOWN; + return new; + + case ADDRESS: + pattern = XEXP (pattern, 0); + goto restart; + + case PC: + new->exact = "pc_rtx"; + return new; + + case CC0: + new->exact = "cc0_rtx"; + return new; + + case CONST_INT: + if (INTVAL (pattern) == 0) + { + new->exact = "const0_rtx"; + return new; + } + if (INTVAL (pattern) == 1) + { + new->exact = "const1_rtx"; + return new; + } + break; + + case SET: + newpos[depth] = '0'; + new = add_to_sequence (SET_DEST (pattern), new, newpos); + this->success->enforce_mode = 1; + newpos[depth] = '1'; + new = add_to_sequence (SET_SRC (pattern), new, newpos); + return new; + + case STRICT_LOW_PART: + newpos[depth] = '0'; + new = add_to_sequence (XEXP (pattern, 0), new, newpos); + this->success->enforce_mode = 1; + return new; + + case SUBREG: + this->test_elt_one_int = 1; + this->elt_one_int = XINT (pattern, 1); + newpos[depth] = '0'; + new = add_to_sequence (XEXP (pattern, 0), new, newpos); + this->success->enforce_mode = 1; + return new; + + case ZERO_EXTRACT: + case SIGN_EXTRACT: + newpos[depth] = '0'; + new = add_to_sequence (XEXP (pattern, 0), new, newpos); + this->success->enforce_mode = 1; + newpos[depth] = '1'; + new = add_to_sequence (XEXP (pattern, 1), new, newpos); + newpos[depth] = '2'; + new = add_to_sequence (XEXP (pattern, 2), new, newpos); + return new; + } + + fmt = GET_RTX_FORMAT (code); + len = GET_RTX_LENGTH (code); + for (i = 0; i < len; i++) + { + newpos[depth] = '0' + i; + if (fmt[i] == 'e' || fmt[i] == 'u') + new = add_to_sequence (XEXP (pattern, i), new, newpos); + else if (fmt[i] == 'i' && i == 0) + { + this->test_elt_zero_int = 1; + this->elt_zero_int = XINT (pattern, i); + } + else if (fmt[i] == 'i' && i == 1) + { + this->test_elt_one_int = 1; + this->elt_one_int = XINT (pattern, i); + } + else if (fmt[i] == 'E') + { + register int j; + /* We do not handle a vector appearing as other than + the first item, just because nothing uses them + and by handling only the special case + we can use one element in newpos for either + the item number of a subexpression + or the element number in a vector. */ + if (i != 0) + abort (); + this->veclen = XVECLEN (pattern, i); + for (j = 0; j < XVECLEN (pattern, i); j++) + { + newpos[depth] = 'a' + j; + new = add_to_sequence (XVECEXP (pattern, i, j), + new, newpos); + } + } + else if (fmt[i] != '0') + abort (); + } + return new; +} + +/* Merge two decision trees OLD and ADD, + modifying OLD destructively, + and return the merged tree. */ + +struct decision * +merge_trees (old, add) + register struct decision *old, *add; +{ + while (add) + { + register struct decision *next = add->next; + add->next = 0; + if (!try_merge_1 (old, add)) + old = try_merge_2 (old, add); + add = next; + } + return old; +} + +/* Merge ADD into the next-chain starting with OLD + only if it overlaps a condition already tested in OLD. + Returns 1 if successful (OLD is modified), + 0 if nothing has been done. */ + +int +try_merge_1 (old, add) + register struct decision *old, *add; +{ + while (old) + { + if ((old->position == add->position + || (old->position && add->position + && !strcmp (old->position, add->position))) + && (old->tests == add->tests + || (old->tests && add->tests && !strcmp (old->tests, add->tests))) + && (old->c_test == add->c_test + || (old->c_test && add->c_test && !strcmp (old->c_test, add->c_test))) + && old->test_elt_zero_int == add->test_elt_zero_int + && old->elt_zero_int == add->elt_zero_int + && old->test_elt_one_int == add->test_elt_one_int + && old->elt_one_int == add->elt_one_int + && old->veclen == add->veclen + && old->dupno == add->dupno + && old->opno == add->opno + && (old->tests == 0 + || (add->enforce_mode ? no_same_mode (old) : old->next == 0)) + && old->code == add->code + && old->mode == add->mode) + { + old->success = merge_trees (old->success, add->success); + if (old->insn_code_number >= 0 && add->insn_code_number >= 0) + fatal ("Two actions at one point in tree."); + if (old->insn_code_number == -1) + old->insn_code_number = add->insn_code_number; + return 1; + } + old = old->next; + } + return 0; +} + +/* Merge ADD into the next-chain that starts with OLD, + preferably after something that tests the same place + that ADD does. + The next-chain of ADD itself is ignored, and it is set + up for entering ADD into the new chain. + Returns the new chain. */ + +struct decision * +try_merge_2 (old, add) + struct decision *old, *add; +{ + register struct decision *p; + struct decision *last = 0; + struct decision *last_same_place = 0; + + /* Put this in after the others that test the same place, + if there are any. If not, find the last chain element + and insert there. + + One modification: if this one is NOT a MATCH_OPERAND, + put it before any MATCH_OPERANDS that test the same place. + + Another: if enforce_mode (i.e. this is first operand of a SET), + put this after the last thing that tests the same place for + the same mode. */ + + int operand = 0 != add->tests; + + for (p = old; p; p = p->next) + { + if (p->position == add->position + || (p->position && add->position + && !strcmp (p->position, add->position))) + { + last_same_place = p; + /* If enforce_mode, segregate the modes in numerical order. */ + if (p->enforce_mode && (int) add->mode < (int) p->mode) + break; +#if 0 + /* Keep explicit decompositions before those that test predicates. + If enforce_mode, do this separately within each mode. */ + if (! p->enforce_mode || p->mode == add->mode) + if (!operand && p->tests) + break; +#endif + } + /* If this is past the end of the decisions at the same place as ADD, + stop looking now; add ADD before here. */ + else if (last_same_place) + break; + last = p; + } + + /* Insert before P, which means after LAST. */ + + if (last) + { + add->next = last->next; + last->next = add; + return old; + } + + add->next = old; + return add; +} + +int +no_same_mode (node) + struct decision *node; +{ + register struct decision *p; + register enum machine_mode mode = node->mode; + + for (p = node->next; p; p = p->next) + if (p->mode == mode) + return 0; + + return 1; +} + +/* Count the number of subnodes of node NODE, assumed to be the start + of a next-chain. If the number is high enough, make NODE start + a separate subroutine in the C code that is generated. */ + +int +break_out_subroutines (node) + struct decision *node; +{ + int size = 0; + struct decision *sub; + for (sub = node; sub; sub = sub->next) + size += 1 + break_out_subroutines (sub->success); + if (size > SUBROUTINE_THRESHOLD) + { + node->subroutine_number = ++next_subroutine_number; + write_subroutine (node); + size = 1; + } + return size; +} + +void +write_subroutine (tree) + struct decision *tree; +{ + printf ("int\nrecog_%d (x0, insn)\n register rtx x0;\n rtx insn;\n{\n", + tree->subroutine_number); + printf (" register rtx x1, x2, x3, x4, x5;\n rtx x6, x7, x8, x9, x10, x11;\n"); + printf (" int tem;\n"); + write_tree (tree, "", 0, "", 1); + printf (" ret0: return -1;\n}\n\n"); +} + +/* Write out C code to perform the decisions in the tree. */ + +void +write_tree (tree, prevpos, afterward, afterpos, initial) + struct decision *tree; + char *prevpos; + int afterward; + char *afterpos; + int initial; +{ + register struct decision *p, *p1; + char *pos; + register int depth; + int ignmode; + enum anon1 { NO_SWITCH, CODE_SWITCH, MODE_SWITCH } in_switch = NO_SWITCH; + char modemap[NUM_MACHINE_MODES]; + char codemap[NUM_RTX_CODE]; + + pos = prevpos; + + if (tree->subroutine_number > 0 && ! initial) + { + printf (" L%d:\n", tree->number); + + if (afterward) + { + printf (" tem = recog_%d (x0, insn);\n", + tree->subroutine_number); + printf (" if (tem >= 0) return tem;\n"); + change_state (pos, afterpos); + printf (" goto L%d;\n", afterward); + } + else + printf (" return recog_%d (x0, insn);\n", + tree->subroutine_number); + return; + } + + tree->label_needed = 1; + for (p = tree; p; p = p->next) + { + /* Find the next alternative to p + that might be true when p is true. + Test that one next if p's successors fail. + Note that when the `tests' field is nonzero + it is up to the specified test-function to compare machine modes + and some (such as general_operand) don't always do so. + But when inside a switch-on-modes we ignore this and + consider all modes mutually exclusive. */ + for (p1 = p->next; p1; p1 = p1->next) + if (((p->code == UNKNOWN || p1->code == UNKNOWN || p->code == p1->code) + && (p->mode == VOIDmode || p1->mode == VOIDmode + || p->mode == p1->mode + || (in_switch != MODE_SWITCH && (p->tests || p1->tests)))) + || strcmp (p1->position, p->position)) + break; + p->afterward = p1; + if (p1) p1->label_needed = 1; + + if (in_switch == MODE_SWITCH + && (p->mode == VOIDmode || (! p->enforce_mode && p->tests != 0))) + { + in_switch = NO_SWITCH; + printf (" }\n"); + } + if (in_switch == CODE_SWITCH && p->code == UNKNOWN) + { + in_switch = NO_SWITCH; + printf (" }\n"); + } + + if (p->label_needed) + printf (" L%d:\n", p->number); + + if (p->success == 0 && p->insn_code_number < 0) + abort (); + + change_state (pos, p->position); + pos = p->position; + depth = strlen (pos); + + ignmode = p->ignmode || pos[depth - 1] == '*' || p->tests; + + if (in_switch == NO_SWITCH) + { + /* If p and its alternatives all want the same mode, + reject all others at once, first, then ignore the mode. */ + if (!ignmode && p->mode != VOIDmode && p->next && same_modes (p, p->mode)) + { + printf (" if (GET_MODE (x%d) != %smode)\n", + depth, GET_MODE_NAME (p->mode)); + if (afterward) + { + printf (" {\n "); + change_state (pos, afterpos); + printf (" goto L%d;\n }\n", afterward); + } + else + printf (" goto ret0;\n"); + clear_modes (p); + ignmode = 1; + } + + /* If p and its alternatives all want the same code, + reject all others at once, first, then ignore the code. */ + if (p->code != UNKNOWN && p->next && same_codes (p, p->code)) + { + printf (" if (GET_CODE (x%d) != ", depth); + print_code (p->code); + printf (")\n"); + if (afterward) + { + printf (" {"); + change_state (pos, afterpos); + printf (" goto L%d; }\n", afterward); + } + else + printf (" goto ret0;\n"); + clear_codes (p); + } + } + + /* If p and its alternatives all have different modes + and there are at least 4 of them, make a switch. */ + if (in_switch == NO_SWITCH && pos[depth-1] != '*') + { + register int i; + int lose = 0; + + mybzero (modemap, sizeof modemap); + for (p1 = p, i = 0; + (p1 && p1->mode != VOIDmode + && (p1->tests == 0 || p1->enforce_mode)); + p1 = p1->next, i++) + { + if (! p->enforce_mode && modemap[(int) p1->mode]) + { + lose = 1; + break; + } + modemap[(int) p1->mode] = 1; + } + if (!lose && i >= 4) + { + in_switch = MODE_SWITCH; + printf (" switch (GET_MODE (x%d))\n {\n", depth); + } + } + + if (in_switch == NO_SWITCH) + { + register int i; + mybzero (codemap, sizeof codemap); + for (p1 = p, i = 0; p1 && p1->code != UNKNOWN; p1 = p1->next, i++) + { + if (codemap[(int) p1->code]) + break; + codemap[(int) p1->code] = 1; + } + if ((p1 == 0 || p1->code == UNKNOWN) && i >= 4) + { + in_switch = CODE_SWITCH; + printf (" switch (GET_CODE (x%d))\n {\n", depth); + } + } + + if (in_switch == MODE_SWITCH) + { + if (modemap[(int) p->mode]) + { + printf (" case %smode:\n", GET_MODE_NAME (p->mode)); + modemap[(int) p->mode] = 0; + } + } + if (in_switch == CODE_SWITCH) + { + if (codemap[(int) p->code]) + { + printf (" case "); + print_code (p->code); + printf (":\n"); + codemap[(int) p->code] = 0; + } + } + + printf (" if ("); + if (p->exact || (p->code != UNKNOWN && in_switch != CODE_SWITCH)) + { + if (p->exact) + printf ("x%d == %s", depth, p->exact); + else + { + printf ("GET_CODE (x%d) == ", depth); + print_code (p->code); + } + printf (" && "); + } + if (p->mode != VOIDmode && !ignmode && in_switch != MODE_SWITCH) + printf ("GET_MODE (x%d) == %smode && ", + depth, GET_MODE_NAME (p->mode)); + if (p->test_elt_zero_int) + printf ("XINT (x%d, 0) == %d && ", depth, p->elt_zero_int); + if (p->veclen) + printf ("XVECLEN (x%d, 0) == %d && ", depth, p->veclen); + if (p->test_elt_one_int) + printf ("XINT (x%d, 1) == %d && ", depth, p->elt_one_int); + if (p->dupno >= 0) + printf ("rtx_equal_p (x%d, recog_operand[%d]) && ", depth, p->dupno); + if (p->tests) + printf ("%s (x%d, %smode)", p->tests, depth, + GET_MODE_NAME (p->mode)); + else + printf ("1"); + + if (p->opno >= 0) + printf (")\n { recog_operand[%d] = x%d; ", + p->opno, depth); + else + printf (")\n "); + + if (p->c_test) + printf ("if (%s) ", p->c_test); + + if (p->insn_code_number >= 0) + printf ("return %d;", p->insn_code_number); + else + printf ("goto L%d;", p->success->number); + + if (p->opno >= 0) + printf (" }\n"); + else + printf ("\n"); + + /* Now, if inside a switch, branch to next switch member + that might also need to be tested if this one fails. */ + + if (in_switch == CODE_SWITCH) + { + /* Find the next alternative to p + that might be applicable if p was applicable. */ + for (p1 = p->next; p1; p1 = p1->next) + if (p1->code == UNKNOWN || p->code == p1->code) + break; + if (p1 == 0 || p1->code == UNKNOWN) + printf (" break;\n"); + else if (p1 != p->next) + { + printf (" goto L%d;\n", p1->number); + p1->label_needed = 1; + } + } + + if (in_switch == MODE_SWITCH) + { + /* Find the next alternative to p + that might be applicable if p was applicable. */ + for (p1 = p->next; p1; p1 = p1->next) + if (p1->mode == VOIDmode || p->mode == p1->mode) + break; + if (p1 == 0 || p1->mode == VOIDmode) + printf (" break;\n"); + else if (p1 != p->next) + { + printf (" goto L%d;\n", p1->number); + p1->label_needed = 1; + } + } + } + + if (in_switch != NO_SWITCH) + printf (" }\n"); + + if (afterward) + { + change_state (pos, afterpos); + printf (" goto L%d;\n", afterward); + } + else + printf (" goto ret0;\n"); + + for (p = tree; p; p = p->next) + if (p->success) + { + { + pos = p->position; + write_tree (p->success, pos, + p->afterward ? p->afterward->number : afterward, + p->afterward ? pos : afterpos, + 0); + } + } +} + +void +print_code (code) + RTX_CODE code; +{ + register char *p1; + for (p1 = GET_RTX_NAME (code); *p1; p1++) + { + if (*p1 >= 'a' && *p1 <= 'z') + putchar (*p1 + 'A' - 'a'); + else + putchar (*p1); + } +} + +int +same_codes (p, code) + register struct decision *p; + register RTX_CODE code; +{ + for (; p; p = p->next) + if (p->code != code) + return 0; + + return 1; +} + +void +clear_codes (p) + register struct decision *p; +{ + for (; p; p = p->next) + p->code = UNKNOWN; +} + +int +same_modes (p, mode) + register struct decision *p; + register enum machine_mode mode; +{ + for (; p; p = p->next) + if (p->mode != mode || p->tests) + return 0; + + return 1; +} + +void +clear_modes (p) + register struct decision *p; +{ + for (; p; p = p->next) + p->ignmode = 1; +} + +void +change_state (oldpos, newpos) + char *oldpos; + char *newpos; +{ + int odepth = strlen (oldpos); + int depth = odepth; + int ndepth = strlen (newpos); + + /* Pop up as many levels as necessary. */ + + while (strncmp (oldpos, newpos, depth)) + --depth; + + /* Go down to desired level. */ + + while (depth < ndepth) + { + if (newpos[depth] == '*') + printf (" x%d = recog_addr_dummy;\n XEXP (x%d, 0) = x%d;\n", + depth + 1, depth + 1, depth); + else if (newpos[depth] >= 'a' && newpos[depth] <= 'z') + printf (" x%d = XVECEXP (x%d, 0, %d);\n", + depth + 1, depth, newpos[depth] - 'a'); + else + printf (" x%d = XEXP (x%d, %c);\n", + depth + 1, depth, newpos[depth]); + ++depth; + } +} + +char * +copystr (s1) + char *s1; +{ + register char *tem; + + if (s1 == 0) + return 0; + + tem = (char *) xmalloc (strlen (s1) + 1); + strcpy (tem, s1); + + return tem; +} + +void +mybzero (b, length) + register char *b; + register int length; +{ + while (length-- > 0) + *b++ = 0; +} + +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; +} + +int +xrealloc (ptr, size) + char *ptr; + int size; +{ + int result = realloc (ptr, size); + if (!result) + fatal ("virtual memory exhausted"); + return result; +} + +int +xmalloc (size) +{ + register int val = malloc (size); + + if (val == 0) + fatal ("virtual memory exhausted"); + return val; +} + +void +fatal (s, a1, a2) + char *s; +{ + fprintf (stderr, "genrecog: "); + fprintf (stderr, s, a1, a2); + fprintf (stderr, "\n"); + fprintf (stderr, "after %d instruction definitions\n", + next_insn_code); + exit (FATAL_EXIT_CODE); +} + +/* 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; + char **argv; +{ + rtx desc; + struct decision *tree = 0; + FILE *infile; + extern rtx read_rtx (); + register int c; + + obstack_init (rtl_obstack); + + if (argc <= 1) + fatal ("No input file name."); + + infile = fopen (argv[1], "r"); + if (infile == 0) + { + perror (argv[1]); + exit (FATAL_EXIT_CODE); + } + + init_rtl (); + next_insn_code = 0; + + printf ("/* Generated automatically by the program `genrecog'\n\ +from the machine description file `md'. */\n\n"); + + /* Read the machine description. */ + + while (1) + { + c = read_skip_spaces (infile); + if (c == EOF) + break; + ungetc (c, infile); + + desc = read_rtx (infile); + if (GET_CODE (desc) == DEFINE_INSN) + tree = merge_trees (tree, make_insn_sequence (desc)); + if (GET_CODE (desc) == DEFINE_PEEPHOLE + || GET_CODE (desc) == DEFINE_EXPAND) + next_insn_code++; + } + + printf ("#include \"config.h\"\n"); + printf ("#include \"rtl.h\"\n"); + printf ("#include \"insn-config.h\"\n"); + printf ("#include \"recog.h\"\n"); + printf ("#include \"real.h\"\n"); + printf ("\n\ +/* `recog' contains a decision tree\n\ + that recognizes whether the rtx X0 is a valid instruction.\n\ +\n\ + recog returns -1 if the rtx is not valid.\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\ + insn_templates and insn_n_operands (found in insn-output.c)\n\ + or as an argument to output_insn_hairy (also in insn-output.c). */\n\n"); + + printf ("rtx recog_operand[MAX_RECOG_OPERANDS];\n\n"); + printf ("rtx *recog_operand_loc[MAX_RECOG_OPERANDS];\n\n"); + printf ("rtx *recog_dup_loc[MAX_DUP_OPERANDS];\n\n"); + printf ("char recog_dup_num[MAX_DUP_OPERANDS];\n\n"); + printf ("extern rtx recog_addr_dummy;\n\n"); + printf ("#define operands recog_operand\n\n"); + + break_out_subroutines (tree); + + printf ("int\nrecog (x0, insn)\n register rtx x0;\n rtx insn;\n{\n"); + printf (" register rtx x1, x2, x3, x4, x5;\n rtx x6, x7, x8, x9, x10, x11;\n"); + printf (" int tem;\n"); + + write_tree (tree, "", 0, "", 1); + printf (" ret0: return -1;\n}\n"); + + fflush (stdout); + exit (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE); +} diff --git a/gcc-1.40/global-alloc.c b/gcc-1.40/global-alloc.c new file mode 100644 index 0000000..8c6d7a3 --- /dev/null +++ b/gcc-1.40/global-alloc.c @@ -0,0 +1,1091 @@ +/* Allocate registers for pseudo-registers that span basic blocks. + Copyright (C) 1987, 1988 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 1, 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 +#include "config.h" +#include "rtl.h" +#include "flags.h" +#include "basic-block.h" +#include "hard-reg-set.h" +#include "regs.h" +#include "insn-config.h" + +/* This pass of the compiler performs global register allocation. + It assigns hard register numbers to all the pseudo registers + that were not handled in local_alloc. Assignments are recorded + in the vector reg_renumber, not by changing the rtl code. + (Such changes are made by final). The entry point is + the function global_alloc. + + After allocation is complete, the reload pass is run as a subroutine + of this pass, so that when a pseudo reg loses its hard reg due to + spilling it is possible to make a second attempt to find a hard + reg for it. The reload pass is independent in other respects + and it is run even when stupid register allocation is in use. + + 1. count the pseudo-registers still needing allocation + and assign allocation-numbers (allocnos) to them. + Set up tables reg_allocno and allocno_reg to map + reg numbers to allocnos and vice versa. + max_allocno gets the number of allocnos in use. + + 2. Allocate a max_allocno by max_allocno conflict bit matrix and clear it. + Allocate a max_allocno by FIRST_PSEUDO_REGISTER conflict matrix + for conflicts between allocnos and explicit hard register use + (which includes use of pseudo-registers allocated by local_alloc). + + 3. for each basic block + walk forward through the block, recording which + unallocated registers and which hardware registers are live. + Build the conflict matrix between the unallocated registers + and another of unallocated registers versus hardware registers. + Also record the preferred hardware registers + for each unallocated one. + + 4. Sort a table of the allocnos into order of + desirability of the variables. + + 5. Allocate the variables in that order; each if possible into + a preferred register, else into another register. */ + +/* Number of pseudo-registers still requiring allocation + (not allocated by local_allocate). */ + +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; + +/* Indexed by allocno, gives the reg number. */ + +static int *allocno_reg; + +/* A vector of the integers from 0 to max_allocno-1, + sorted in the order of first-to-be-allocated first. */ + +static int *allocno_order; + +/* Indexed by an allocno, gives the number of consecutive + hard registers needed by that pseudo reg. */ + +static int *allocno_size; + +/* max_allocno by max_allocno array of bits, + recording whether two allocno's conflict (can't go in the same + hardware register). + + `conflicts' is not symmetric; a conflict between allocno's i and j + is recorded either in element i,j or in element j,i. */ + +static int *conflicts; + +/* Number of ints require to hold max_allocno bits. + This is the length of a row in `conflicts'. */ + +static int allocno_row_words; + +/* Two macros to test or store 1 in an element of `conflicts'. */ + +#define CONFLICTP(I, J) \ + (conflicts[(I) * allocno_row_words + (J) / INT_BITS] \ + & (1 << ((J) % INT_BITS))) + +#define SET_CONFLICT(I, J) \ + (conflicts[(I) * allocno_row_words + (J) / INT_BITS] \ + |= (1 << ((J) % INT_BITS))) + +/* Set of hard regs currently live (during scan of all insns). */ + +static HARD_REG_SET hard_regs_live; + +/* Indexed by N, set of hard regs conflicting with allocno N. */ + +static HARD_REG_SET *hard_reg_conflicts; + +/* Indexed by N, set of hard regs preferred by allocno N. + This is used to make allocnos go into regs that are copied to or from them, + when possible, to reduce register shuffling. */ + +static HARD_REG_SET *hard_reg_preferences; + +/* Set of registers that some allocno has a preference for. */ + +static HARD_REG_SET regs_someone_prefers; + +/* Set of registers that global-alloc isn't supposed to use. */ + +static HARD_REG_SET no_global_alloc_regs; + +/* Test a bit in TABLE, a vector of HARD_REG_SETs, + for vector element I, and hard register number J. */ + +#define REGBITP(TABLE, I, J) TEST_HARD_REG_BIT (TABLE[I], J) + +/* Set to 1 a bit in a vector of HARD_REG_SETs. Works like REGBITP. */ + +#define SET_REGBIT(TABLE, I, J) SET_HARD_REG_BIT (TABLE[I], J) + +/* Bit mask for allocnos live at current point in the scan. */ + +static int *allocnos_live; + +#define INT_BITS HOST_BITS_PER_INT + +/* Test, set or clear bit number I in allocnos_live, + a bit vector indexed by allocno. */ + +#define ALLOCNO_LIVE_P(I) \ + (allocnos_live[(I) / INT_BITS] & (1 << ((I) % INT_BITS))) + +#define SET_ALLOCNO_LIVE(I) \ + (allocnos_live[(I) / INT_BITS] |= (1 << ((I) % INT_BITS))) + +#define CLEAR_ALLOCNO_LIVE(I) \ + (allocnos_live[(I) / INT_BITS] &= ~(1 << ((I) % INT_BITS))) + +/* Record all regs that are set in any one insn. + Communication from mark_reg_{store,clobber} and global_conflicts. */ + +static rtx *regs_set; +static int n_regs_set; + +static int allocno_compare (); +static void mark_reg_store (); +static void mark_reg_clobber (); +static void mark_reg_live_nc (); +static void mark_reg_death (); +static void dump_conflicts (); +static void find_reg (); +static void global_conflicts (); +static void record_conflicts (); +static void set_preference (); + +/* Perform allocation of pseudo-registers not allocated by local_alloc. + FILE is a file to output debugging information on, + or zero if such output is not desired. */ + +void +global_alloc (file) + FILE *file; +{ + register int i; + + max_allocno = 0; + + CLEAR_HARD_REG_SET (regs_someone_prefers); + + /* A machine may have certain hard registers that + are safe to use only within a basic block. */ + + CLEAR_HARD_REG_SET (no_global_alloc_regs); +#ifdef OVERLAPPING_REGNO_P + for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) + if (OVERLAPPING_REGNO_P (i)) + SET_HARD_REG_BIT (no_global_alloc_regs, i); +#endif + + /* Establish mappings from register number to allocation number + and vice versa. In the process, count the allocnos. */ + + reg_allocno = (int *) alloca (max_regno * sizeof (int)); + + for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) + reg_allocno[i] = -1; + + for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++) + /* 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) + { + reg_allocno[i] = max_allocno++; + if (reg_live_length[i] == 0) + abort (); + } + else + reg_allocno[i] = -1; + + allocno_reg = (int *) alloca (max_allocno * sizeof (int)); + allocno_size = (int *) alloca (max_allocno * sizeof (int)); + bzero (allocno_size, max_allocno * sizeof (int)); + + for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++) + if (reg_allocno[i] >= 0) + { + allocno_reg[reg_allocno[i]] = i; + allocno_size[reg_allocno[i]] = PSEUDO_REGNO_SIZE (i); + } + + /* Allocate the space for the conflict tables. */ + + hard_reg_conflicts = (HARD_REG_SET *) + alloca (max_allocno * sizeof (HARD_REG_SET)); + bzero (hard_reg_conflicts, max_allocno * sizeof (HARD_REG_SET)); + + hard_reg_preferences = (HARD_REG_SET *) + alloca (max_allocno * sizeof (HARD_REG_SET)); + bzero (hard_reg_preferences, max_allocno * sizeof (HARD_REG_SET)); + + allocno_row_words = (max_allocno + INT_BITS - 1) / INT_BITS; + + conflicts = (int *) + alloca (max_allocno * allocno_row_words * sizeof (int)); + bzero (conflicts, max_allocno * allocno_row_words * sizeof (int)); + + allocnos_live = (int *) alloca (allocno_row_words * sizeof (int)); + + /* If there is work to be done (at least one reg to allocate), + perform global conflict analysis and allocate the regs. */ + + if (max_allocno > 0) + { + /* Scan all the insns and compute the conflicts among allocnos + and between allocnos and hard regs. */ + + global_conflicts (); + + /* Determine the order to allocate the remaining pseudo registers. */ + + allocno_order = (int *) alloca (max_allocno * sizeof (int)); + for (i = 0; i < max_allocno; i++) + allocno_order[i] = i; + + /* Default the size to 1, since allocno_compare uses it to divide by. */ + + for (i = 0; i < max_allocno; i++) + if (allocno_size[i] == 0) + allocno_size[i] = 1; + + qsort (allocno_order, max_allocno, sizeof (int), allocno_compare); + + if (file) + dump_conflicts (file); + + /* Try allocating them, one by one, in that order, + 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 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], 0, 0, 0, + hard_reg_preferences[allocno_order[i]]); + if (reg_renumber[allocno_reg[allocno_order[i]]] >= 0) + continue; + } + if (!reg_preferred_or_nothing (allocno_reg[allocno_order[i]])) + find_reg (allocno_order[i], 0, 1, 0, + hard_reg_preferences[allocno_order[i]]); + } + } + + /* Do the reloads now while the allocno data still exist, so that we can + try to assign new hard regs to any pseudo regs that are spilled. */ + + if (n_basic_blocks > 0) + reload (basic_block_head[0], 1, file); +} + +/* 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; +{ + register int r1 = allocno_reg[*v1]; + register int r2 = allocno_reg[*v2]; + /* 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 (reg_n_refs[r1]) * reg_n_refs[r1]) + / (reg_live_length[r1] * allocno_size[*v1])) + * 10000); + register int pri2 + = (((double) (floor_log2 (reg_n_refs[r2]) * reg_n_refs[r2]) + / (reg_live_length[r2] * allocno_size[*v2])) + * 10000); + 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; +} + +/* Scan the rtl code and record all conflicts in the conflict matrices. */ + +static void +global_conflicts () +{ + register int b, i; + register rtx insn; + short *block_start_allocnos; + + /* Make a vector that mark_reg_{store,clobber} will store in. */ + regs_set = (rtx *) alloca (max_parallel * sizeof (rtx) * 2); + + block_start_allocnos = (short *) alloca (max_allocno * sizeof (short)); + + for (b = 0; b < n_basic_blocks; b++) + { + bzero (allocnos_live, allocno_row_words * sizeof (int)); + + /* Initialize table of registers currently live + to the state at the beginning of this basic block. + This also marks the conflicts among them. + + For pseudo-regs, there is only one bit for each one + no matter how many hard regs it occupies. + This is ok; we know the size from PSEUDO_REGNO_SIZE. + For explicit hard regs, we cannot know the size that way + since one hard reg can be used with various sizes. + Therefore, we must require that all the hard regs + implicitly live as part of a multi-word hard reg + are explicitly marked in basic_block_live_at_start. */ + + { + register int offset, 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 += HOST_BITS_PER_INT; + 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)); + } + } + + /* 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); + } + + insn = basic_block_head[b]; + + /* Scan the code of this basic block, noting which allocnos + and hard regs are born or die. When one is born, + record a conflict with all others currently live. */ + + while (1) + { + register RTX_CODE code = GET_CODE (insn); + register rtx link; + + /* Make regs_set an empty set. */ + + n_regs_set = 0; + + if (code == INSN || code == CALL_INSN || code == JUMP_INSN) + { + /* Mark any registers clobbered by INSN as live, + so they conflict with the inputs. */ + + note_stores (PATTERN (insn), mark_reg_clobber); + + /* Mark any registers dead after INSN as dead now. */ + + for (link = REG_NOTES (insn); link; link = XEXP (link, 1)) + if (REG_NOTE_KIND (link) == REG_DEAD) + mark_reg_death (XEXP (link, 0)); + + /* Mark any registers set in INSN as live, + and mark them as conflicting with all other live regs. + Clobbers are processed again, so they conflict with + the registers that are set. */ + + note_stores (PATTERN (insn), mark_reg_store); + + /* Mark any registers both set and dead after INSN as dead. + This is not redundant! + A register may be set and killed in the same insn. + It is necessary to mark them as live, above, to get + the right conflicts within the insn. */ + + while (n_regs_set > 0) + if (find_regno_note (insn, REG_DEAD, REGNO (regs_set[--n_regs_set]))) + mark_reg_death (regs_set[n_regs_set]); + + /*???The following seems to be incorrect. */ + /* Likewise for regs set by incrementation. */ + + for (link = REG_NOTES (insn); link; link = XEXP (link, 1)) + if (REG_NOTE_KIND (link) == REG_INC + && find_regno_note (insn, REG_DEAD, REGNO (XEXP (link, 0)))) + mark_reg_death (XEXP (link, 0)); + } + + if (insn == basic_block_end[b]) + break; + insn = NEXT_INSN (insn); + } + } +} + +/* Assign a hard register to ALLOCNO; look for one that is the beginning + of a long enough stretch of hard regs none of which conflicts with ALLOCNO. + The registers marked in PREFREGS are tried first. + + If ALL_REGS_P is zero, consider only the preferred class of ALLOCNO's reg. + Otherwise ignore that preferred class. + + If ACCEPT_CALL_CLOBBERED is nonzero, accept a call-clobbered hard reg that + will have to be saved and restored at calls. + + If we find one, record it in reg_renumber. + If not, do nothing. */ + +static void +find_reg (allocno, losers, all_regs_p, accept_call_clobbered, prefregs) + int allocno; + register short *losers; + int all_regs_p; + int accept_call_clobbered; + HARD_REG_SET prefregs; +{ + register int i, prefreg, pass; +#ifdef HARD_REG_SET + register /* Declare it register if it's a scalar. */ +#endif + HARD_REG_SET used; + + enum reg_class class + = all_regs_p ? GENERAL_REGS : reg_preferred_class (allocno_reg[allocno]); + enum machine_mode mode = PSEUDO_REGNO_MODE (allocno_reg[allocno]); + + if (accept_call_clobbered) + COPY_HARD_REG_SET (used, call_fixed_reg_set); + else if (reg_n_calls_crossed[allocno_reg[allocno]] == 0) + COPY_HARD_REG_SET (used, fixed_reg_set); + else + COPY_HARD_REG_SET (used, call_used_reg_set); + + /* Some registers should not be allocated in global-alloc. */ + IOR_HARD_REG_SET (used, no_global_alloc_regs); + + IOR_COMPL_HARD_REG_SET (used, reg_class_contents[(int) class]); + IOR_HARD_REG_SET (used, hard_reg_conflicts[allocno]); + if (frame_pointer_needed) + SET_HARD_REG_BIT (used, FRAME_POINTER_REGNUM); + + AND_COMPL_HARD_REG_SET (prefregs, used); + + /* Try to find a register from the preferred set first. */ + + i = -1; + for (prefreg = 0; prefreg < FIRST_PSEUDO_REGISTER; prefreg++) + if (TEST_HARD_REG_BIT (prefregs, prefreg) + && (losers == 0 || losers[prefreg] < 0) + && HARD_REGNO_MODE_OK (prefreg, mode)) + { + register int j; + register int lim = prefreg + HARD_REGNO_NREGS (prefreg, mode); + for (j = prefreg + 1; + (j < lim + && ! TEST_HARD_REG_BIT (used, j) + && (losers == 0 || losers[j] < 0)); + j++); + if (j == lim) + { + i = prefreg; + break; + } + } + +#if 0 + /* Otherwise try each hard reg to see if it fits. Do this in two passes. + In the first pass, skip registers that are prefered by some pseudo to + give it a better chance of getting one of those registers. Only if + we can't get a register when excluding those do we take one of them. */ + + /* This is turned off because it makes worse allocation on the 68020. */ + for (pass = 0; pass <= 1 && i < 0; pass++) +#endif + pass = 1; + for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) + { +#ifdef REG_ALLOC_ORDER + int regno = reg_alloc_order[i]; +#else + int regno = i; +#endif + if (! TEST_HARD_REG_BIT (used, regno) + && (losers == 0 || losers[regno] < 0) + && (pass == 1 || ! TEST_HARD_REG_BIT (regs_someone_prefers, regno)) + && HARD_REGNO_MODE_OK (regno, mode)) + { + register int j; + register int lim = regno + HARD_REGNO_NREGS (regno, mode); + for (j = regno + 1; + (j < lim + && ! TEST_HARD_REG_BIT (used, j) + && (losers == 0 || losers[j] < 0)); + j++); + if (j == lim) + { + i = regno; + break; + } +#ifndef REG_ALLOC_ORDER + i = j; /* Skip starting points we know will lose */ +#endif + } + } + + /* Did we find a register? */ + + if (i < FIRST_PSEUDO_REGISTER) + { + register int lim, j; + HARD_REG_SET this_reg; + + /* Yes. Record it as the hard register of this pseudo-reg. */ + reg_renumber[allocno_reg[allocno]] = i; + /* For each other pseudo-reg conflicting with this one, + mark it as conflicting with the hard regs this one occupies. */ + CLEAR_HARD_REG_SET (this_reg); + lim = i + HARD_REGNO_NREGS (i, mode); + for (j = i; j < lim; j++) + SET_HARD_REG_BIT (this_reg, j); + lim = allocno; + for (j = 0; j < max_allocno; j++) + if (CONFLICTP (lim, j) || CONFLICTP (j, lim)) + { + IOR_HARD_REG_SET (hard_reg_conflicts[j], this_reg); + } + } + else if (flag_caller_saves) + { + /* Did not find a register. If it would be profitable to + allocate a call-clobbered register and save and restore it + around calls, do that. */ + if (! accept_call_clobbered + && reg_n_calls_crossed[allocno_reg[allocno]] != 0 + && CALLER_SAVE_PROFITABLE (reg_n_refs[allocno_reg[allocno]], + reg_n_calls_crossed[allocno_reg[allocno]])) + { + find_reg (allocno, losers, all_regs_p, 1, prefregs); + if (reg_renumber[allocno_reg[allocno]] >= 0) + caller_save_needed = 1; + } + } +} + +/* Called from `reload' to look for a hard reg to put pseudo reg REGNO in. + Perhaps it had previously seemed not worth a hard reg, + or perhaps its old hard reg has been commandeered for reloads. + FORBIDDEN_REGS is a vector that indicates certain hard regs + that may not be used, even if they do not appear to be allocated. + A nonnegative element means the corresponding hard reg is forbidden. + If FORBIDDEN_REGS is zero, no regs are forbidden. */ + +void +retry_global_alloc (regno, forbidden_regs) + int regno; + short *forbidden_regs; +{ + int allocno = reg_allocno[regno]; + if (allocno >= 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, forbidden_regs, 0, 0, + hard_reg_preferences[allocno]); + if (reg_renumber[regno] < 0 + && !reg_preferred_or_nothing (regno)) + find_reg (allocno, forbidden_regs, 1, 0, + hard_reg_preferences[allocno]); + } +} + +/* Called from reload pass to see if current function's pseudo regs + require a frame pointer to be allocated and set up. + + Return 1 if so, 0 otherwise. + We may alter the hard-reg allocation of the pseudo regs + in order to make the frame pointer unnecessary. + However, if the value is 1, nothing has been altered. + + Args grant access to some tables used in reload1.c. + See there for info on them. */ + +int +check_frame_pointer_required (reg_equiv_constant, reg_equiv_mem, reg_equiv_address) + rtx *reg_equiv_constant, *reg_equiv_mem, *reg_equiv_address; +{ + register int i; + HARD_REG_SET *old_hard_reg_conflicts; + short *old_reg_renumber; + char old_regs_ever_live[FIRST_PSEUDO_REGISTER]; + + /* If any pseudo reg has no hard reg and no equivalent, + we must have a frame pointer. */ + + for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++) + if (reg_renumber[i] < 0 && reg_n_refs[i] > 0 + && reg_equiv_mem[i] == 0 && reg_equiv_constant[i] == 0 + && reg_equiv_address[i] == 0) + return 1; + + /* If we might not need a frame pointer, + try finding a hard reg for any pseudo that has a memory equivalent. + That is because the memory equivalent probably refers to a frame + pointer. */ + + old_reg_renumber = (short *) alloca (max_regno * sizeof (short)); + old_hard_reg_conflicts = (HARD_REG_SET *) + alloca (max_allocno * sizeof (HARD_REG_SET)); + + bcopy (reg_renumber, old_reg_renumber, max_regno * sizeof (short)); + bcopy (hard_reg_conflicts, old_hard_reg_conflicts, + max_allocno * sizeof (HARD_REG_SET)); + bcopy (regs_ever_live, old_regs_ever_live, sizeof regs_ever_live); + + for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++) + if (reg_renumber[i] < 0 + && ((reg_equiv_mem[i] + && reg_mentioned_p (frame_pointer_rtx, reg_equiv_mem[i])) + || (reg_equiv_address[i] + && reg_mentioned_p (frame_pointer_rtx, reg_equiv_address[i])))) + { + retry_global_alloc (i, 0); + /* If we can't find a hard reg for ALL of them, + or if a previously unneeded hard reg is used that requires saving, + we fail: set all those pseudos back as they were. */ + if (reg_renumber[i] < 0 + || (! old_regs_ever_live[reg_renumber[i]] + && ! call_used_regs[reg_renumber[i]])) + { + bcopy (old_reg_renumber, reg_renumber, + max_regno * sizeof (short)); + bcopy (old_hard_reg_conflicts, hard_reg_conflicts, + max_allocno * sizeof (HARD_REG_SET)); + bcopy (old_regs_ever_live, regs_ever_live, sizeof regs_ever_live); + return 1; + } + mark_home_live (i); + } + + return 0; +} + +/* Record a conflict between register REGNO + and everything currently live. + REGNO must not be a pseudo reg that was allocated + by local_alloc; such numbers must be translated through + reg_renumber before calling here. */ + +static void +record_one_conflict (regno) + int regno; +{ + register int j; + + if (regno < FIRST_PSEUDO_REGISTER) + /* When a hard register becomes live, + record conflicts with live pseudo regs. */ + for (j = 0; j < max_allocno; j++) + { + if (ALLOCNO_LIVE_P (j)) + SET_HARD_REG_BIT (hard_reg_conflicts[j], regno); + } + else + /* When a pseudo-register becomes live, + record conflicts first with hard regs, + then with other pseudo regs. */ + { + register int ialloc = reg_allocno[regno]; + register int ialloc_prod = ialloc * allocno_row_words; + IOR_HARD_REG_SET (hard_reg_conflicts[ialloc], hard_regs_live); + for (j = allocno_row_words - 1; j >= 0; j--) + conflicts[ialloc_prod + j] |= allocnos_live[j]; + } +} + +/* Record all allocnos currently live as conflicting + with each other and with all hard regs currently live. + ALLOCNO_VEC is a vector of LEN allocnos, all allocnos that + are currently live. Their bits are also flagged in allocnos_live. */ + +static void +record_conflicts (allocno_vec, len) + register short *allocno_vec; + register int len; +{ + register int allocno; + register int j; + register int ialloc_prod; + + while (--len >= 0) + { + allocno = allocno_vec[len]; + ialloc_prod = allocno * allocno_row_words; + IOR_HARD_REG_SET (hard_reg_conflicts[allocno], hard_regs_live); + for (j = allocno_row_words - 1; j >= 0; j--) + conflicts[ialloc_prod + j] |= allocnos_live[j]; + } +} + +/* Handle the case where REG is set by the insn being scanned, + during the forward scan to accumulate conflicts. + Store a 1 in regs_live or allocnos_live for this register, record how many + consecutive hardware registers it actually needs, + and record a conflict with all other registers already live. + + Note that even if REG does not remain alive after this insn, + we must mark it here as live, to ensure a conflict between + REG and any other regs set in this insn that really do live. + This is because those other regs could be considered after this. + + REG might actually be something other than a register; + if so, we do nothing. + + CLOBBERs are processed here by calling mark_reg_clobber. */ + +static void +mark_reg_store (orig_reg, setter) + rtx orig_reg, setter; +{ + register int regno; + register rtx reg = orig_reg; + + /* WORD is which word of a multi-register group is being stored. + For the case where the store is actually into a SUBREG of REG. + Except we don't use it; I believe the entire REG needs to be + made live. */ + int word = 0; + + if (GET_CODE (reg) == SUBREG) + { + word = SUBREG_WORD (reg); + reg = SUBREG_REG (reg); + } + + if (GET_CODE (reg) != REG) + return; + + if (GET_CODE (setter) != SET) + { + /* A clobber of a register should be processed here too. */ + mark_reg_clobber (orig_reg, setter); + return; + } + + regs_set[n_regs_set++] = reg; + + set_preference (reg, SET_SRC (setter)); + + regno = REGNO (reg); + + if (reg_renumber[regno] >= 0) + regno = reg_renumber[regno] /* + word */; + + /* Either this is one of the max_allocno pseudo regs not allocated, + or it is or has a hardware reg. First handle the pseudo-regs. */ + if (regno >= FIRST_PSEUDO_REGISTER) + { + if (reg_allocno[regno] >= 0) + { + SET_ALLOCNO_LIVE (reg_allocno[regno]); + record_one_conflict (regno); + } + } + /* Handle hardware regs (and pseudos allocated to hard regs). */ + else if (! fixed_regs[regno]) + { + register int last = regno + HARD_REGNO_NREGS (regno, GET_MODE (reg)); + while (regno < last) + { + record_one_conflict (regno); + SET_HARD_REG_BIT (hard_regs_live, regno); + regno++; + } + } +} + +/* Like mark_reg_set except notice just CLOBBERs; ignore SETs. */ + +static void +mark_reg_clobber (reg, setter) + rtx reg, setter; +{ + register int regno; + + /* WORD is which word of a multi-register group is being stored. + For the case where the store is actually into a SUBREG of REG. + Except we don't use it; I believe the entire REG needs to be + made live. */ + int word = 0; + + if (GET_CODE (setter) != CLOBBER) + return; + + if (GET_CODE (reg) == SUBREG) + { + word = SUBREG_WORD (reg); + reg = SUBREG_REG (reg); + } + + if (GET_CODE (reg) != REG) + return; + + regs_set[n_regs_set++] = reg; + + regno = REGNO (reg); + + if (reg_renumber[regno] >= 0) + regno = reg_renumber[regno] /* + word */; + + /* Either this is one of the max_allocno pseudo regs not allocated, + or it is or has a hardware reg. First handle the pseudo-regs. */ + if (regno >= FIRST_PSEUDO_REGISTER) + { + if (reg_allocno[regno] >= 0) + { + SET_ALLOCNO_LIVE (reg_allocno[regno]); + record_one_conflict (regno); + } + } + /* Handle hardware regs (and pseudos allocated to hard regs). */ + else if (! fixed_regs[regno]) + { + register int last = regno + HARD_REGNO_NREGS (regno, GET_MODE (reg)); + while (regno < last) + { + record_one_conflict (regno); + SET_HARD_REG_BIT (hard_regs_live, regno); + regno++; + } + } +} + +/* Mark REG as being dead (following the insn being scanned now). + Store a 0 in regs_live or allocnos_live for this register. */ + +static void +mark_reg_death (reg) + rtx reg; +{ + register int regno = REGNO (reg); + + /* For pseudo reg, see if it has been assigned a hardware reg. */ + if (reg_renumber[regno] >= 0) + regno = reg_renumber[regno]; + + /* Either this is one of the max_allocno pseudo regs not allocated, + or it is a hardware reg. First handle the pseudo-regs. */ + if (regno >= FIRST_PSEUDO_REGISTER) + { + if (reg_allocno[regno] >= 0) + CLEAR_ALLOCNO_LIVE (reg_allocno[regno]); + } + /* Handle hardware regs (and pseudos allocated to hard regs). */ + else if (! fixed_regs[regno]) + { + /* Pseudo regs already assigned hardware regs are treated + almost the same as explicit hardware regs. */ + register int last = regno + HARD_REGNO_NREGS (regno, GET_MODE (reg)); + while (regno < last) + { + CLEAR_HARD_REG_BIT (hard_regs_live, regno); + regno++; + } + } +} + +/* Mark hard reg REGNO as currently live, assuming machine mode MODE + for the value stored in it. MODE determines how many consecutive + registers are actually in use. Do not record conflicts; + it is assumed that the caller will do that. */ + +static void +mark_reg_live_nc (regno, mode) + register int regno; + enum machine_mode mode; +{ + register int last = regno + HARD_REGNO_NREGS (regno, mode); + while (regno < last) + { + SET_HARD_REG_BIT (hard_regs_live, regno); + regno++; + } +} + +/* Try to set a preference for an allocno to a hard register. + We are passed DEST and SRC which are the operands of a SET. It is known + that SRC is a register. If SRC or the first operand of SRC is a register, + try to set a preference. If one of the two is a hard register and the other + is a pseudo-register, mark the preference. + + Note that we are not as agressive as local-alloc in trying to tie a + pseudo-register to a hard register. */ + +static void +set_preference (dest, src) + rtx dest, src; +{ + int src_regno, dest_regno; + /* Amount to add to the hard regno for SRC, or subtract from that for DEST, + to compensate for subregs in SRC or DEST. */ + int offset = 0; + + if (GET_RTX_FORMAT (GET_CODE (src))[0] == 'e') + src = XEXP (src, 0); + + /* Get the reg number for both SRC and DEST. + If neither is a reg, give up. */ + + if (GET_CODE (src) == REG) + src_regno = REGNO (src); + else if (GET_CODE (src) == SUBREG && GET_CODE (SUBREG_REG (src)) == REG) + { + src_regno = REGNO (SUBREG_REG (src)); + offset += SUBREG_WORD (src); + } + else + return; + + if (GET_CODE (dest) == REG) + dest_regno = REGNO (dest); + else if (GET_CODE (dest) == SUBREG && GET_CODE (SUBREG_REG (dest)) == REG) + { + dest_regno = REGNO (SUBREG_REG (dest)); + offset -= SUBREG_WORD (dest); + } + else + return; + + /* Convert either or both to hard reg numbers. */ + + if (reg_renumber[src_regno] >= 0) + src_regno = reg_renumber[src_regno]; + + if (reg_renumber[dest_regno] >= 0) + dest_regno = reg_renumber[dest_regno]; + + /* Now if one is a hard reg and the other is a global pseudo + then give the other a preference. */ + + if (dest_regno < FIRST_PSEUDO_REGISTER && src_regno >= FIRST_PSEUDO_REGISTER + && reg_allocno[src_regno] >= 0) + { + dest_regno -= offset; + if (dest_regno >= 0 && dest_regno < FIRST_PSEUDO_REGISTER) + { + SET_REGBIT (hard_reg_preferences, + reg_allocno[src_regno], dest_regno); + SET_HARD_REG_BIT (regs_someone_prefers, dest_regno); + } + } + + if (src_regno < FIRST_PSEUDO_REGISTER && dest_regno >= FIRST_PSEUDO_REGISTER + && reg_allocno[dest_regno] >= 0) + { + src_regno += offset; + if (src_regno >= 0 && src_regno < FIRST_PSEUDO_REGISTER) + { + SET_REGBIT (hard_reg_preferences, + reg_allocno[dest_regno], src_regno); + SET_HARD_REG_BIT (regs_someone_prefers, src_regno); + } + } +} + +/* Print debugging trace information if -greg switch is given, + showing the information on which the allocation decisions are based. */ + +static void +dump_conflicts (file) + FILE *file; +{ + register int i; + fprintf (file, ";; %d regs to allocate:", max_allocno); + for (i = 0; i < max_allocno; i++) + { + fprintf (file, " %d", allocno_reg[allocno_order[i]]); + if (allocno_size[allocno_order[i]] != 1) + fprintf (file, " (%d)", allocno_size[allocno_order[i]]); + } + fprintf (file, "\n"); + + for (i = 0; i < max_allocno; i++) + { + register int j; + fprintf (file, ";; %d conflicts:", allocno_reg[i]); + for (j = 0; j < max_allocno; j++) + if (CONFLICTP (i, j) || CONFLICTP (j, i)) + fprintf (file, " %d", allocno_reg[j]); + for (j = 0; j < FIRST_PSEUDO_REGISTER; j++) + if (TEST_HARD_REG_BIT (hard_reg_conflicts[i], j)) + fprintf (file, " %d", j); + fprintf (file, "\n"); + } + fprintf (file, "\n"); +} + +void +dump_global_regs (file) + FILE *file; +{ + register int i; + + fprintf (file, ";; Register dispositions:"); + for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++) + { + if (reg_renumber[i] >= 0) + fprintf (file, " %d in %d ", i, reg_renumber[i]); + } + + fprintf (file, "\n\n;; Hard regs used: "); + for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) + if (regs_ever_live[i]) + fprintf (file, " %d", i); + fprintf (file, "\n\n"); +} diff --git a/gcc-1.40/gnulib.c b/gcc-1.40/gnulib.c new file mode 100644 index 0000000..74045c8 --- /dev/null +++ b/gcc-1.40/gnulib.c @@ -0,0 +1,465 @@ +/* Subroutines needed by GCC output code on some machines. */ +/* Compile this file with the Unix C compiler! */ + +#include "config.h" + +/* Define the C data type to use for an SImode value. */ + +#ifndef SItype +#define SItype long int +#endif + +/* Define the type to be used for returning an SF mode value + and the method for turning a float into that type. + These definitions work for machines where an SF value is + returned in the same register as an int. */ + +#ifndef SFVALUE +#define SFVALUE int +#endif + +#ifndef INTIFY +#define INTIFY(FLOATVAL) (intify.f = (FLOATVAL), intify.i) +#endif + +#ifdef GNULIB_NEEDS_DOUBLE +#define FLOAT_ARG_TYPE double +#define FLOATIFY(ARG) ((float) (ARG)) +#endif + +#ifndef FLOATIFY +#define FLOATIFY(INTVAL) ((INTVAL).f) +#endif + +#ifndef FLOAT_ARG_TYPE +#define FLOAT_ARG_TYPE union flt_or_int +#endif + +union flt_or_int { int i; float f; }; + + +#ifdef L_eprintf +#include +/* This is used by the `assert' macro. */ +void +__eprintf (string, expression, line, filename) + char *string; + char *expression; + int line; + char *filename; +{ + fprintf (stderr, string, expression, line, filename); + fflush (stderr); + abort (); +} +#endif + +#ifdef L_umulsi3 +SItype +__umulsi3 (a, b) + unsigned SItype a, b; +{ + return a * b; +} +#endif + +#ifdef L_mulsi3 +SItype +__mulsi3 (a, b) + SItype a, b; +{ + return a * b; +} +#endif + +#ifdef L_udivsi3 +SItype +__udivsi3 (a, b) + unsigned SItype a, b; +{ + return a / b; +} +#endif + +#ifdef L_divsi3 +SItype +__divsi3 (a, b) + SItype a, b; +{ + return a / b; +} +#endif + +#ifdef L_umodsi3 +SItype +__umodsi3 (a, b) + unsigned SItype a, b; +{ + return a % b; +} +#endif + +#ifdef L_modsi3 +SItype +__modsi3 (a, b) + SItype a, b; +{ + return a % b; +} +#endif + +#ifdef L_lshrsi3 +SItype +__lshrsi3 (a, b) + unsigned SItype a, b; +{ + return a >> b; +} +#endif + +#ifdef L_lshlsi3 +SItype +__lshlsi3 (a, b) + unsigned SItype a, b; +{ + return a << b; +} +#endif + +#ifdef L_ashrsi3 +SItype +__ashrsi3 (a, b) + SItype a, b; +{ + return a >> b; +} +#endif + +#ifdef L_ashlsi3 +SItype +__ashlsi3 (a, b) + SItype a, b; +{ + return a << b; +} +#endif + +#ifdef L_divdf3 +double +__divdf3 (a, b) + double a, b; +{ + return a / b; +} +#endif + +#ifdef L_muldf3 +double +__muldf3 (a, b) + double a, b; +{ + return a * b; +} +#endif + +#ifdef L_negdf2 +double +__negdf2 (a) + double a; +{ + return -a; +} +#endif + +#ifdef L_adddf3 +double +__adddf3 (a, b) + double a, b; +{ + return a + b; +} +#endif + +#ifdef L_subdf3 +double +__subdf3 (a, b) + double a, b; +{ + return a - b; +} +#endif + +#ifdef L_cmpdf2 +SItype +__cmpdf2 (a, b) + double a, b; +{ + if (a > b) + return 1; + else if (a < b) + return -1; + return 0; +} +#endif + +#ifdef L_fixunsdfsi +#define HIGH_BIT_INT_COEFF (1 << (BITS_PER_WORD - 1)) +#define HIGH_BIT_COEFF (2 * (double) (1 << (BITS_PER_WORD - 2))) + +SItype +__fixunsdfsi (a) + double a; +{ + if (a < HIGH_BIT_COEFF) + return (SItype)a; + /* Convert large positive numbers to smaller ones, + then increase again after you have a fixed point number. */ + else + return ((SItype) (a - HIGH_BIT_COEFF)) + HIGH_BIT_INT_COEFF; +} +#endif + +#ifdef L_fixdfsi +SItype +__fixdfsi (a) + double a; +{ + return (SItype) a; +} +#endif + +#ifdef L_floatsidf +double +__floatsidf (a) + SItype a; +{ + return (double) a; +} +#endif + +#ifdef L_addsf3 +SFVALUE +__addsf3 (a, b) + FLOAT_ARG_TYPE a, b; +{ + union flt_or_int intify; + return INTIFY (FLOATIFY (a) + FLOATIFY (b)); +} +#endif + +#ifdef L_negsf2 +SFVALUE +__negsf2 (a) + FLOAT_ARG_TYPE a; +{ + union flt_or_int intify; + return INTIFY (-FLOATIFY (a)); +} +#endif + +#ifdef L_subsf3 +SFVALUE +__subsf3 (a, b) + FLOAT_ARG_TYPE a, b; +{ + union flt_or_int intify; + return INTIFY (FLOATIFY (a) - FLOATIFY (b)); +} +#endif + +#ifdef L_cmpsf2 +SItype +__cmpsf2 (a, b) + FLOAT_ARG_TYPE a, b; +{ + if (FLOATIFY (a) > FLOATIFY (b)) + return 1; + else if (FLOATIFY (a) < FLOATIFY (b)) + return -1; + return 0; +} +#endif + +#ifdef L_mulsf3 +SFVALUE +__mulsf3 (a, b) + FLOAT_ARG_TYPE a, b; +{ + union flt_or_int intify; + return INTIFY (FLOATIFY (a) * FLOATIFY (b)); +} +#endif + +#ifdef L_divsf3 +SFVALUE +__divsf3 (a, b) + FLOAT_ARG_TYPE a, b; +{ + union flt_or_int intify; + + return INTIFY (FLOATIFY (a) / FLOATIFY (b)); +} +#endif + +#ifdef L_truncdfsf2 +SFVALUE +__truncdfsf2 (a) + double a; +{ + union flt_or_int intify; + return INTIFY (a); +} +#endif + +#ifdef L_extendsfdf2 +double +__extendsfdf2 (a) + FLOAT_ARG_TYPE a; +{ + return FLOATIFY (a); +} +#endif + +#ifdef L_bb +int __avoid_ranlib_warning; /* Don't let symbol table be empty. */ + +#if defined (sun) && defined (mc68000) +struct bb +{ + int initialized; + char *filename; + int *counts; + int ncounts; + int zero_word; + int *addresses; +}; + +__bb_init_func (blocks) + struct bb *blocks; +{ + extern int ___tcov_init; + + if (! ___tcov_init) + ___tcov_init_func (); + + ___bb_link (blocks->filename, blocks->counts, blocks->ncounts); +} + +#endif +#endif + +/* frills for C++ */ + +#ifdef L_builtin_new +typedef void (*vfp)(); + +extern vfp __new_handler; + +char * +__builtin_new (sz) + long sz; +{ + char *p; + + p = (char *)malloc (sz); + if (p == 0) + (*__new_handler) (); + return p; +} +#endif + +#ifdef L_builtin_New +typedef void (*vfp)(); + +static void +default_new_handler (); + +vfp __new_handler = default_new_handler; + +char * +__builtin_vec_new (p, maxindex, size, ctor) + char *p; + int maxindex, size; + void (*ctor)(); +{ + int i, nelts = maxindex + 1; + char *rval; + + if (p == 0) + p = (char *)__builtin_new (nelts * size); + + rval = p; + + for (i = 0; i < nelts; i++) + { + (*ctor) (p); + p += size; + } + + return rval; +} + +vfp +__set_new_handler (handler) + vfp handler; +{ + vfp prev_handler; + + prev_handler = __new_handler; + if (handler == 0) handler = default_new_handler; + __new_handler = handler; + return prev_handler; +} + +vfp +set_new_handler (handler) + vfp handler; +{ + return __set_new_handler (handler); +} + +static void +default_new_handler () +{ + /* don't use fprintf (stderr, ...) because it may need to call malloc. */ + write (2, "default_new_handler: out of memory... aaaiiiiiieeeeeeeeeeeeee!\n", 65); + /* don't call exit () because that may call global destructors which + may cause a loop. */ + _exit (-1); +} +#endif + +#ifdef L_builtin_del +typedef void (*vfp)(); + +void +__builtin_delete (ptr) + char *ptr; +{ + if (ptr) + free (ptr); +} + +void +__builtin_vec_delete (ptr, maxindex, size, dtor, auto_delete_vec, auto_delete) + char *ptr; + int maxindex, size; + void (*dtor)(); + int auto_delete; +{ + int i, nelts = maxindex + 1; + char *p = ptr; + + ptr += nelts * size; + + for (i = 0; i < nelts; i++) + { + ptr -= size; + (*dtor) (ptr, auto_delete); + } + + if (auto_delete_vec) + free (p); +} + +#endif diff --git a/gcc-1.40/gnulib2.c b/gcc-1.40/gnulib2.c new file mode 100644 index 0000000..b31b8f6 --- /dev/null +++ b/gcc-1.40/gnulib2.c @@ -0,0 +1,922 @@ +/* More subroutines needed by GCC output code on some machines. */ +/* Compile this one with gcc. */ + +#include "config.h" +#include + +#ifndef SItype +#define SItype long int +#endif + +/* long long ints are pairs of long ints in the order determined by + WORDS_BIG_ENDIAN. */ + +#ifdef WORDS_BIG_ENDIAN + struct longlong {long high, low;}; +#else + struct longlong {long low, high;}; +#endif + +/* We need this union to unpack/pack longlongs, since we don't have + any arithmetic yet. Incoming long long parameters are stored + into the `ll' field, and the unpacked result is read from the struct + longlong. */ + +typedef union +{ + struct longlong s; + long long ll; + SItype i[2]; + unsigned SItype ui[2]; +} long_long; + +/* Internally, long long ints are strings of unsigned shorts in the + order determined by BYTES_BIG_ENDIAN. */ + +#define B 0x10000 +#define low16 (B - 1) + +#ifdef BYTES_BIG_ENDIAN + +/* Note that HIGH and LOW do not describe the order + of words in a long long. They describe the order of words + in vectors ordered according to the byte order. */ + +#define HIGH 0 +#define LOW 1 + +#define big_end(n) 0 +#define little_end(n) ((n) - 1) +#define next_msd(i) ((i) - 1) +#define next_lsd(i) ((i) + 1) +#define is_not_msd(i,n) ((i) >= 0) +#define is_not_lsd(i,n) ((i) < (n)) + +#else + +#define LOW 0 +#define HIGH 1 + +#define big_end(n) ((n) - 1) +#define little_end(n) 0 +#define next_msd(i) ((i) + 1) +#define next_lsd(i) ((i) - 1) +#define is_not_msd(i,n) ((i) < (n)) +#define is_not_lsd(i,n) ((i) >= 0) + +#endif + +/* These algorithms are all straight out of Knuth, vol. 2, sec. 4.3.1. */ + +static int badd (); +static int bsub (); +static void bmul (); +static int bneg (); +static int bshift (); + +#ifdef L_adddi3 +long long +__adddi3 (u, v) + long long u, v; +{ + long a[2], b[2], c[2]; + long_long w; + long_long uu, vv; + + uu.ll = u; + vv.ll = v; + + a[HIGH] = uu.s.high; + a[LOW] = uu.s.low; + b[HIGH] = vv.s.high; + b[LOW] = vv.s.low; + + badd (a, b, c, sizeof c); + + w.s.high = c[HIGH]; + w.s.low = c[LOW]; + return w.ll; +} + +static int +badd (a, b, c, n) + unsigned short *a, *b, *c; + size_t n; +{ + unsigned long acc; + int i; + + n /= sizeof *c; + + acc = 0; + for (i = little_end (n); is_not_msd (i, n); i = next_msd (i)) + { + /* Widen before adding to avoid loss of high bits. */ + acc += (unsigned long) a[i] + b[i]; + c[i] = acc & low16; + acc = acc >> 16; + } + return acc; +} +#endif + +#ifdef L_anddi3 +long long +__anddi3 (u, v) + long long u, v; +{ + long_long w; + long_long uu, vv; + + uu.ll = u; + vv.ll = v; + + w.s.high = uu.s.high & vv.s.high; + w.s.low = uu.s.low & vv.s.low; + + return w.ll; +} +#endif + +#ifdef L_iordi3 +long long +__iordi3 (u, v) + long long u, v; +{ + long_long w; + long_long uu, vv; + + uu.ll = u; + vv.ll = v; + + w.s.high = uu.s.high | vv.s.high; + w.s.low = uu.s.low | vv.s.low; + + return w.ll; +} +#endif + +#ifdef L_xordi3 +long long +__xordi3 (u, v) + long long u, v; +{ + long_long w; + long_long uu, vv; + + uu.ll = u; + vv.ll = v; + + w.s.high = uu.s.high ^ vv.s.high; + w.s.low = uu.s.low ^ vv.s.low; + + return w.ll; +} +#endif + +#ifdef L_one_cmpldi2 +long long +__one_cmpldi2 (u) + long long u; +{ + long_long w; + long_long uu; + + uu.ll = u; + + w.s.high = ~uu.s.high; + w.s.low = ~uu.s.low; + + return w.ll; +} +#endif + +#ifdef L_lshldi3 +long long +__lshldi3 (u, b1) + long long u; + long long b1; +{ + long_long w; + unsigned long carries; + int bm; + long_long uu; + int b = b1; + + if (b == 0) + return u; + + uu.ll = u; + + bm = (sizeof (int) * BITS_PER_UNIT) - b; + if (bm <= 0) + { + w.s.low = 0; + w.s.high = (unsigned long)uu.s.low << -bm; + } + else + { + carries = (unsigned long)uu.s.low >> bm; + w.s.low = (unsigned long)uu.s.low << b; + w.s.high = ((unsigned long)uu.s.high << b) | carries; + } + + return w.ll; +} +#endif + +#ifdef L_lshrdi3 +long long +__lshrdi3 (u, b1) + long long u; + long long b1; +{ + long_long w; + unsigned long carries; + int bm; + long_long uu; + int b = b1; + + if (b == 0) + return u; + + uu.ll = u; + + bm = (sizeof (int) * BITS_PER_UNIT) - b; + if (bm <= 0) + { + w.s.high = 0; + w.s.low = (unsigned long)uu.s.high >> -bm; + } + else + { + carries = (unsigned long)uu.s.high << bm; + w.s.high = (unsigned long)uu.s.high >> b; + w.s.low = ((unsigned long)uu.s.low >> b) | carries; + } + + return w.ll; +} +#endif + +#ifdef L_ashldi3 +long long +__ashldi3 (u, b1) + long long u; + long long b1; +{ + long_long w; + unsigned long carries; + int bm; + long_long uu; + int b = b1; + + if (b == 0) + return u; + + uu.ll = u; + + bm = (sizeof (int) * BITS_PER_UNIT) - b; + if (bm <= 0) + { + w.s.low = 0; + w.s.high = (unsigned long)uu.s.low << -bm; + } + else + { + carries = (unsigned long)uu.s.low >> bm; + w.s.low = (unsigned long)uu.s.low << b; + w.s.high = ((unsigned long)uu.s.high << b) | carries; + } + + return w.ll; +} +#endif + +#ifdef L_ashrdi3 +long long +__ashrdi3 (u, b1) + long long u; + long long b1; +{ + long_long w; + unsigned long carries; + int bm; + long_long uu; + int b = b1; + + if (b == 0) + return u; + + uu.ll = u; + + bm = (sizeof (int) * BITS_PER_UNIT) - b; + if (bm <= 0) + { + w.s.high = uu.s.high >> 31; /* just to make w.s.high 1..1 or 0..0 */ + w.s.low = uu.s.high >> -bm; + } + else + { + carries = (unsigned long)uu.s.high << bm; + w.s.high = uu.s.high >> b; + w.s.low = ((unsigned long)uu.s.low >> b) | carries; + } + + return w.ll; +} +#endif + +#ifdef L_subdi3 +long long +__subdi3 (u, v) + long long u, v; +{ + long a[2], b[2], c[2]; + long_long w; + long_long uu, vv; + + uu.ll = u; + vv.ll = v; + + a[HIGH] = uu.s.high; + a[LOW] = uu.s.low; + b[HIGH] = vv.s.high; + b[LOW] = vv.s.low; + + bsub (a, b, c, sizeof c); + + w.s.high = c[HIGH]; + w.s.low = c[LOW]; + return w.ll; +} + +static int +bsub (a, b, c, n) + unsigned short *a, *b, *c; + size_t n; +{ + signed long acc; + int i; + + n /= sizeof *c; + + acc = 0; + for (i = little_end (n); is_not_msd (i, n); i = next_msd (i)) + { + /* Widen before subtracting to avoid loss of high bits. */ + acc += (long) a[i] - b[i]; + c[i] = acc & low16; + acc = acc >> 16; + } + return acc; +} +#endif + +#ifdef L_muldi3 +long long +__muldi3 (u, v) + long long u, v; +{ + long a[2], b[2], c[2][2]; + long_long w; + long_long uu, vv; + + uu.ll = u; + vv.ll = v; + + a[HIGH] = uu.s.high; + a[LOW] = uu.s.low; + b[HIGH] = vv.s.high; + b[LOW] = vv.s.low; + + bmul (a, b, c, sizeof a, sizeof b); + + w.s.high = c[LOW][HIGH]; + w.s.low = c[LOW][LOW]; + return w.ll; +} + +static void +bmul (a, b, c, m, n) + unsigned short *a, *b, *c; + size_t m, n; +{ + int i, j; + unsigned long acc; + + bzero (c, m + n); + + m /= sizeof *a; + n /= sizeof *b; + + for (j = little_end (n); is_not_msd (j, n); j = next_msd (j)) + { + unsigned short *c1 = c + j + little_end (2); + acc = 0; + for (i = little_end (m); is_not_msd (i, m); i = next_msd (i)) + { + /* Widen before arithmetic to avoid loss of high bits. */ + acc += (unsigned long) a[i] * b[j] + c1[i]; + c1[i] = acc & low16; + acc = acc >> 16; + } + c1[i] = acc; + } +} +#endif + +#ifdef L_divdi3 +long long +__divdi3 (u, v) + long long u, v; +{ + if (u < 0) + if (v < 0) + return (unsigned long long) -u / (unsigned long long) -v; + else + return - ((unsigned long long) -u / (unsigned long long) v); + else + if (v < 0) + return - ((unsigned long long) u / (unsigned long long) -v); + else + return (unsigned long long) u / (unsigned long long) v; +} +#endif + +#ifdef L_moddi3 +long long +__moddi3 (u, v) + long long u, v; +{ + if (u < 0) + if (v < 0) + return - ((unsigned long long) -u % (unsigned long long) -v); + else + return - ((unsigned long long) -u % (unsigned long long) v); + else + if (v < 0) + return (unsigned long long) u % (unsigned long long) -v; + else + return (unsigned long long) u % (unsigned long long) v; +} +#endif + +#ifdef L_udivdi3 +long long +__udivdi3 (u, v) + long long u, v; +{ + unsigned long a[2][2], b[2], q[2], r[2]; + long_long w; + long_long uu, vv; + + uu.ll = u; + vv.ll = v; + + a[HIGH][HIGH] = 0; + a[HIGH][LOW] = 0; + a[LOW][HIGH] = uu.s.high; + a[LOW][LOW] = uu.s.low; + b[HIGH] = vv.s.high; + b[LOW] = vv.s.low; + + __bdiv (a, b, q, r, sizeof a, sizeof b); + + w.s.high = q[HIGH]; + w.s.low = q[LOW]; + return w.ll; +} +#endif + +#ifdef L_umoddi3 +long long +__umoddi3 (u, v) + long long u, v; +{ + unsigned long a[2][2], b[2], q[2], r[2]; + long_long w; + long_long uu, vv; + + uu.ll = u; + vv.ll = v; + + a[HIGH][HIGH] = 0; + a[HIGH][LOW] = 0; + a[LOW][HIGH] = uu.s.high; + a[LOW][LOW] = uu.s.low; + b[HIGH] = vv.s.high; + b[LOW] = vv.s.low; + + __bdiv (a, b, q, r, sizeof a, sizeof b); + + w.s.high = r[HIGH]; + w.s.low = r[LOW]; + return w.ll; +} +#endif + +#ifdef L_negdi2 +long long +__negdi2 (u) + long long u; +{ + unsigned long a[2], b[2]; + long_long w; + long_long uu; + + uu.ll = u; + + a[HIGH] = uu.s.high; + a[LOW] = uu.s.low; + + bneg (a, b, sizeof b); + + w.s.high = b[HIGH]; + w.s.low = b[LOW]; + return w.ll; +} + +static int +bneg (a, b, n) + unsigned short *a, *b; + size_t n; +{ + signed long acc; + int i; + + n /= sizeof (short); + + acc = 0; + for (i = little_end (n); is_not_msd (i, n); i = next_msd (i)) + { + acc -= a[i]; + b[i] = acc & low16; + acc = acc >> 16; + } + return acc; +} +#endif + +/* Divide a by b, producing quotient q and remainder r. + + sizeof a is m + sizeof b is n + sizeof q is m - n + sizeof r is n + + The quotient must fit in m - n bytes, i.e., the most significant + n digits of a must be less than b, and m must be greater than n. */ + +/* The name of this used to be __div_internal, + but that is too long for SYSV. */ + +#ifdef L_bdiv +void +__bdiv (a, b, q, r, m, n) + unsigned short *a, *b, *q, *r; + size_t m, n; +{ + unsigned long qhat, rhat; + unsigned long acc; + unsigned short *u = (unsigned short *) alloca (m); + unsigned short *v = (unsigned short *) alloca (n); + unsigned short *u0, *u1, *u2; + unsigned short *v0; + int d, qn; + int i, j; + + m /= sizeof *a; + n /= sizeof *b; + qn = m - n; + + /* Remove leading zero digits from divisor, and the same number of + digits (which must be zero) from dividend. */ + + while (b[big_end (n)] == 0) + { + r[big_end (n)] = 0; + + a += little_end (2); + b += little_end (2); + r += little_end (2); + m--; + n--; + + /* Check for zero divisor. */ + if (n == 0) + abort (); + } + + /* If divisor is a single digit, do short division. */ + + if (n == 1) + { + acc = a[big_end (m)]; + a += little_end (2); + for (j = big_end (qn); is_not_lsd (j, qn); j = next_lsd (j)) + { + acc = (acc << 16) | a[j]; + q[j] = acc / *b; + acc = acc % *b; + } + *r = acc; + return; + } + + /* No such luck, must do long division. Shift divisor and dividend + left until the high bit of the divisor is 1. */ + + for (d = 0; d < 16; d++) + if (b[big_end (n)] & (1 << (16 - 1 - d))) + break; + + bshift (a, d, u, 0, m); + bshift (b, d, v, 0, n); + + /* Get pointers to the high dividend and divisor digits. */ + + u0 = u + big_end (m) - big_end (qn); + u1 = next_lsd (u0); + u2 = next_lsd (u1); + u += little_end (2); + + v0 = v + big_end (n); + + /* Main loop: find a quotient digit, multiply it by the divisor, + and subtract that from the dividend, shifted over the right amount. */ + + for (j = big_end (qn); is_not_lsd (j, qn); j = next_lsd (j)) + { + /* Quotient digit initial guess: high 2 dividend digits over high + divisor digit. */ + + if (u0[j] == *v0) + { + qhat = B - 1; + rhat = (unsigned long) *v0 + u1[j]; + } + else + { + unsigned long numerator = ((unsigned long) u0[j] << 16) | u1[j]; + qhat = numerator / *v0; + rhat = numerator % *v0; + } + + /* Now get the quotient right for high 3 dividend digits over + high 2 divisor digits. */ + + while (rhat < B && qhat * *next_lsd (v0) > ((rhat << 16) | u2[j])) + { + qhat -= 1; + rhat += *v0; + } + + /* Multiply quotient by divisor, subtract from dividend. */ + + acc = 0; + for (i = little_end (n); is_not_msd (i, n); i = next_msd (i)) + { + acc += (unsigned long) (u + j)[i] - v[i] * qhat; + (u + j)[i] = acc & low16; + if (acc < B) + acc = 0; + else + acc = (acc >> 16) | -B; + } + + q[j] = qhat; + + /* Quotient may have been too high by 1. If dividend went negative, + decrement the quotient by 1 and add the divisor back. */ + + if ((signed long) (acc + u0[j]) < 0) + { + q[j] -= 1; + acc = 0; + for (i = little_end (n); is_not_msd (i, n); i = next_msd (i)) + { + acc += (unsigned long) (u + j)[i] + v[i]; + (u + j)[i] = acc & low16; + acc = acc >> 16; + } + } + } + + /* Now the remainder is what's left of the dividend, shifted right + by the amount of the normalizing left shift at the top. */ + + r[big_end (n)] = bshift (u + 1 + little_end (j - 1), + 16 - d, + r + little_end (2), + u[little_end (m - 1)] >> d, + n - 1); +} + +/* Left shift U by K giving W; fill the introduced low-order bits with + CARRY_IN. Length of U and W is N. Return carry out. K must be + in 0 .. 16. */ + +static int +bshift (u, k, w, carry_in, n) + unsigned short *u, *w, carry_in; + int k, n; +{ + unsigned long acc; + int i; + + if (k == 0) + { + bcopy (u, w, n * sizeof *u); + return 0; + } + + acc = carry_in; + for (i = little_end (n); is_not_msd (i, n); i = next_msd (i)) + { + acc |= (unsigned long) u[i] << k; + w[i] = acc & low16; + acc = acc >> 16; + } + return acc; +} +#endif + +#ifdef L_cmpdi2 +SItype +__cmpdi2 (a, b) + long long a, b; +{ + long_long au, bu; + + au.ll = a, bu.ll = b; + + if (au.s.high < bu.s.high) + return 0; + else if (au.s.high > bu.s.high) + return 2; + if ((unsigned) au.s.low < (unsigned) bu.s.low) + return 0; + else if ((unsigned) au.s.low > (unsigned) bu.s.low) + return 2; + return 1; +} +#endif + +#ifdef L_ucmpdi2 +SItype +__ucmpdi2 (a, b) + long long a, b; +{ + long_long au, bu; + + au.ll = a, bu.ll = b; + + if ((unsigned) au.s.high < (unsigned) bu.s.high) + return 0; + else if ((unsigned) au.s.high > (unsigned) bu.s.high) + return 2; + if ((unsigned) au.s.low < (unsigned) bu.s.low) + return 0; + else if ((unsigned) au.s.low > (unsigned) bu.s.low) + return 2; + return 1; +} +#endif + +#ifdef L_fixunsdfdi +#define HIGH_WORD_COEFF (((long long) 1) << BITS_PER_WORD) + +long long +__fixunsdfdi (a) + double a; +{ + double b; + unsigned long long v; + + if (a < 0) + return 0; + + /* Compute high word of result, as a flonum. */ + b = (a / HIGH_WORD_COEFF); + /* Convert that to fixed (but not to long long!), + and shift it into the high word. */ + v = (unsigned long int) b; + v <<= BITS_PER_WORD; + /* Remove high part from the double, leaving the low part as flonum. */ + a -= (double)v; + /* Convert that to fixed (but not to long long!) and add it in. + Sometimes A comes out negative. This is significant, since + A has more bits than a long int does. */ + if (a < 0) + v -= (unsigned long int) (- a); + else + v += (unsigned long int) a; + return v; +} +#endif + +#ifdef L_fixdfdi +long long +__fixdfdi (a) + double a; +{ + long long __fixunsdfdi (double a); + + if (a < 0) + return - __fixunsdfdi (-a); + return __fixunsdfdi (a); +} +#endif + +#ifdef L_floatdidf +#define HIGH_HALFWORD_COEFF (((long long) 1) << (BITS_PER_WORD / 2)) +#define HIGH_WORD_COEFF (((long long) 1) << BITS_PER_WORD) + +double +__floatdidf (u) + long long u; +{ + double d; + int negate = 0; + + if (u < 0) + u = -u, negate = 1; + + d = (unsigned int) (u >> BITS_PER_WORD); + d *= HIGH_HALFWORD_COEFF; + d *= HIGH_HALFWORD_COEFF; + d += (unsigned int) (u & (HIGH_WORD_COEFF - 1)); + + return (negate ? -d : d); +} +#endif + +#ifdef L_varargs +#ifdef i860 + asm (" .text"); + asm (" .align 4"); + + asm ("___builtin_saveregs::"); + asm (" mov sp,r30"); + asm (" andnot 0x0f,sp,sp"); + asm (" adds -96,sp,sp"); /* allocate sufficient space on the stack */ + + asm (" st.l r16, 0(sp)"); /* save integer regs (r16-r27) */ + asm (" st.l r17, 4(sp)"); /* int fixed[12] */ + asm (" st.l r18, 8(sp)"); + asm (" st.l r19,12(sp)"); + asm (" st.l r20,16(sp)"); + asm (" st.l r21,20(sp)"); + asm (" st.l r22,24(sp)"); + asm (" st.l r23,28(sp)"); + asm (" st.l r24,32(sp)"); + asm (" st.l r25,36(sp)"); + asm (" st.l r26,40(sp)"); + asm (" st.l r27,44(sp)"); + + asm (" fst.q f8, 48(sp)"); /* save floating regs (f8-f15) */ + asm (" fst.q f12,64(sp)"); /* int floating[8] */ + + asm (" st.l r28,80(sp)"); /* pointer to more args */ + asm (" st.l r0, 84(sp)"); /* nfixed */ + asm (" st.l r0, 88(sp)"); /* nfloating */ + asm (" st.l r0, 92(sp)"); /* pad */ + + asm (" mov sp,r16"); + asm (" bri r1"); + asm (" mov r30,sp"); + /* recover stack and pass address to start + of data. */ +#endif +#ifdef sparc + asm (".global ___builtin_saveregs"); + asm ("___builtin_saveregs:"); + asm ("st %i0,[%fp+68]"); + asm ("st %i1,[%fp+72]"); + asm ("st %i2,[%fp+76]"); + asm ("st %i3,[%fp+80]"); + asm ("st %i4,[%fp+84]"); + asm ("retl"); + asm ("st %i5,[%fp+88]"); +#else /* not sparc */ +#if defined(MIPSEL) | defined(R3000) | defined(R2000) | defined(mips) + + asm (" .text"); + asm (" .ent __builtin_saveregs"); + asm (" .globl __builtin_saveregs"); + asm ("__builtin_saveregs:"); + asm (" sw $4,0($30)"); + asm (" sw $5,4($30)"); + asm (" sw $6,8($30)"); + asm (" sw $7,12($30)"); + asm (" j $31"); + asm (" .end __builtin_saveregs"); +#else /* not mips */ +__builtin_saveregs () +{ + abort (); +} +#endif /* not mips */ +#endif /* not sparc */ +#endif diff --git a/gcc-1.40/gstab.h b/gcc-1.40/gstab.h new file mode 100644 index 0000000..77f2d41 --- /dev/null +++ b/gcc-1.40/gstab.h @@ -0,0 +1,16 @@ +#ifndef __GNU_STAB__ + +/* Indicate the GNU stab.h is in use. */ + +#define __GNU_STAB__ + +#define __define_stab(NAME, CODE, STRING) NAME=CODE, + +enum __stab_debug_code +{ +#include "stab.def" +}; + +#undef __define_stab + +#endif /* __GNU_STAB_ */ diff --git a/gcc-1.40/gstdarg.h b/gcc-1.40/gstdarg.h new file mode 100644 index 0000000..bae4985 --- /dev/null +++ b/gcc-1.40/gstdarg.h @@ -0,0 +1,44 @@ +/* stdarg.h for GNU. + Note that the type used in va_arg is supposed to match the + actual type **after default promotions**. + Thus, va_arg (..., short) is not valid. */ + +#ifndef _STDARG_H +#define _STDARG_H + +/* The macro _VA_LIST_ is the same thing used by this file in Ultrix. */ +#ifndef _VA_LIST_ +#define _VA_LIST_ +typedef char *va_list; +#endif + +/* Amount of space required in an argument list for an arg of type TYPE. + TYPE may alternatively be an expression whose type is used. */ + +#define __va_rounded_size(TYPE) \ + (((sizeof (TYPE) + sizeof (int) - 1) / sizeof (int)) * sizeof (int)) + +#ifndef __sparc__ +#define va_start(AP, LASTARG) \ + (AP = ((char *) __builtin_next_arg ())) +#else +#define va_start(AP, LASTARG) \ + (__builtin_saveregs (), \ + AP = ((char *) __builtin_next_arg ())) +#endif + +void va_end (va_list); /* Defined in gnulib */ +#define va_end(AP) + +#ifdef __mips__ +#define va_arg(AP, mode) ((mode *)(AP = \ + (char *) (sizeof(mode) > 4 ? ((int)AP + 2*8 - 1) & -8 \ + : ((int)AP + 2*4 - 1) & -4)))[-1] +#else /* not __mips__ */ +#define va_arg(AP, TYPE) \ + (*((TYPE *) (AP += __va_rounded_size (TYPE), \ + AP - (sizeof (TYPE) < 4 ? sizeof (TYPE) \ + : __va_rounded_size (TYPE))))) +#endif /* not __mips__ */ + +#endif /* _STDARG_H */ diff --git a/gcc-1.40/gvarargs.h b/gcc-1.40/gvarargs.h new file mode 100644 index 0000000..dc9c4ef --- /dev/null +++ b/gcc-1.40/gvarargs.h @@ -0,0 +1,68 @@ +#ifndef __GNUC__ +/* Use the system's macros with the system's compiler. */ +#include +#else +/* Record that varargs.h is defined; this turns off stdarg.h. */ + +#ifndef _VARARGS_H +#define _VARARGS_H + +#ifdef __sparc__ +#include "va-sparc.h" +#else +#ifdef __spur__ +#include "va-spur.h" +#else +#ifdef __mips__ +#include "va-mips.h" +#else +#ifdef __i860__ +#include "va-i860.h" +#else +#ifdef __pyr__ +#include "va-pyr.h" +#else + +#ifdef __NeXT__ + +/* On Next, erase any vestiges of stdarg.h. */ + +#undef va_alist +#undef va_dcl +#undef va_list +#undef va_start +#undef va_end +#undef __va_rounded_size +#undef va_arg +#endif /* __NeXT__ */ + +/* These macros implement traditional (non-ANSI) varargs + for GNU C. */ + +#define va_alist __builtin_va_alist +#define va_dcl int __builtin_va_alist; +#define va_list char * + +#ifdef __sparc__ +#define va_start(AP) \ + (__builtin_saveregs (), \ + AP = ((void *) &__builtin_va_alist)) +#else +#define va_start(AP) AP=(char *) &__builtin_va_alist +#endif +#define va_end(AP) + +#define __va_rounded_size(TYPE) \ + (((sizeof (TYPE) + sizeof (int) - 1) / sizeof (int)) * sizeof (int)) + +#define va_arg(AP, TYPE) \ + (*((TYPE *) (AP += __va_rounded_size (TYPE), \ + AP - __va_rounded_size (TYPE)))) + +#endif /* not pyr */ +#endif /* not i860 */ +#endif /* not mips */ +#endif /* not spur */ +#endif /* not sparc */ +#endif /* not _VARARGS_H */ +#endif /* __GNUC__ */ diff --git a/gcc-1.40/hard-params.c b/gcc-1.40/hard-params.c new file mode 100644 index 0000000..589277c --- /dev/null +++ b/gcc-1.40/hard-params.c @@ -0,0 +1,1734 @@ +/* Everything you wanted to know about your machine and C compiler, + but didn't know who to ask. + Author: Steven Pemberton, CWI, Amsterdam; steven@cwi.nl + Bugfixes and upgrades gratefully received. + + Name changed to `hard-params' by Richard Stallman, April 89. + xmalloc function defined, Richard Stallman, June 89. + Avoid macro in #include, Richard Stallman, Jan 90. + Undef CHAR_BIT, etc., if defined in stdio.h, Richard Stallman, Aug 90. + In EPROP, don't compare a with old if bad is already set. Stallman, May 91. + Don't handle long doubles if -DNO_LONG_DOUBLE. Stallman, May 91. + + Copyright (c) 1988, 1989 Steven Pemberton, CWI, Amsterdam. + All rights reserved. + + COMPILING + With luck and a following wind, just the following will work: + cc hard-params.c -o hard-params + + If your compiler doesn't support: add flag: + signed char (eg pcc) -DNO_SC + unsigned char -DNO_UC + unsigned short and long -DNO_UI + signal(), or setjmp/longjmp() -DNO_SIG + + Try it first with no flags, and see if you get any errors - you might be + surprised. (Most non-ANSI compilers need -DNO_SC, though.) + Some compilers need a -f flag for floating point. + + Don't use any optimisation flags: the program may not work if you do. + Though "while (a+1.0-a-1.0 == 0.0)" may look like "while(1)" to an + optimiser, to a floating-point unit there's a world of difference. + + Some compilers offer various flags for different floating point + modes; it's worth trying all possible combinations of these. + + Add -DID=\"name\" if you want the machine/flags identified in the output. + + SYSTEM DEPENDENCIES + You may possibly need to add some calls to signal() for other sorts of + exception on your machine than SIGFPE, and SIGOVER. See lines beginning + #ifdef SIGxxx in main() (and communicate the differences to me!). + + If your C preprocessor doesn't have the predefined __FILE__ macro, and + you want to call this file anything other than hard-params.c, change the + #define command for __FILE__ accordingly. If it doesn't accept macro + names at all in #include lines, order a new C compiler. While you're + waiting for it to arrive, change the last #include in this file (the + last but one line) accordingly. + + OUTPUT + Run without argument to get the information as English text. If run + with argument -l (e.g. hard-params -l), output is a series of #define's for + the ANSI standard limits.h include file, excluding MB_MAX_CHAR. If run + with argument -f, output is a series of #define's for the ANSI standard + float.h include file. Flag -v gives verbose output: output includes the + English text above as C comments. The program exit(0)'s if everything + went ok, otherwise it exits with a positive number, telling how many + problems there were. + + VERIFYING THE COMPILER + If, having produced the float.h and limits.h header files, you want to + verify that the compiler reads them back correctly (there are a lot of + boundary cases, of course, like minimum and maximum numbers), you can + recompile hard-params.c with -DVERIFY set (plus the other flags that you used + when compiling the version that produced the header files). This then + recompiles the program so that it #includes "limits.h" and "float.h", + and checks that the constants it finds there are the same as the + constants it produces. Run the resulting program with hard-params -fl. As of + this writing, of 21 compiler/flags combinations only 1 compiler has + passed without error! (The honour goes to 'pcc' on an IBM RT.) + + You can also use this option if your compiler already has both files, + and you want to confirm that this program produces the right results. + + TROUBLE SHOOTING. + This program is now quite trustworthy, and suspicious and wrong output + may well be caused by bugs in the compiler, not in the program (however + of course, this is not guaranteed, and no responsibility can be + accepted, etc.) + + The program only works if overflows are ignored by the C system or + are catchable with signal(). + + If the program fails to run to completion (often with the error message + "Unexpected signal at point x"), this often turns out to be a bug in the + C compiler's run-time system. Check what was about to be printed, and + try to narrow the problem down. + + Another possible problem is that you have compiled the program to produce + loss-of-precision arithmetic traps. The program cannot cope with these, + and you should re-compile without them. (They should never be the default). + + Make sure you compiled with optimisation turned off. + + Output preceded by *** WARNING: identifies behaviour of the C system + deemed incorrect by the program. Likely problems are that printf or + scanf don't cope properly with certain boundary numbers. For each float + and double that is printed, the printed value is checked that it is + correct by using sscanf to read it back. Care is taken that numbers are + printed with enough digits to uniquely identify them, and therefore that + they can be read back identically. If the number read back is different, + the program prints a warning message. If the two numbers in the warning + look identical, then printf is more than likely rounding the last + digit(s) incorrectly. To put you at ease that the two really are + different, the bit patterns of the two numbers are also printed. The + difference is very likely in the last bit. Many scanf's read the + minimum double back as 0.0, and similarly cause overflow when reading + the maximum double. The program quite ruthlessly declares all these + behaviours faulty. + + The warning that "a cast didn't work" refers to cases like this: + + float f; + #define C 1.234567890123456789 + f= C; + if (f != (float) C) printf ("Wrong!"); + + A faulty compiler will widen f to double and ignore the cast to float, + and because there is more accuracy in a double than a float, fail to + recognise that they are the same. In the actual case in point, f and C + are passed as parameters to a function that discovers they are not equal, + so it's just possible that the error was in the parameter passing, + not in the cast (see function Validate()). + For ANSI C, which has float constants, the error message is "constant has + wrong precision". + + REPORTING PROBLEMS + If the program doesn't work for you for any reason that can't be + narrowed down to a problem in the C compiler, or it has to be changed in + order to get it to compile, or it produces suspicious output (like a very + low maximum float, for instance), please mail the problem and an example + of the incorrect output to steven@cwi.nl or mcvax!steven.uucp, so that + improvements can be worked into future versions; mcvax/cwi.nl is the + European backbone, and is connected to uunet and other fine hosts. + + This version of the program is the first to try to catch and diagnose + bugs in the compiler/run-time system. I would be especially pleased to + have reports of failures so that I can improve this service. + + I apologise unreservedly for the contorted use of the preprocessor... + + THE SMALL PRINT + You may copy and distribute verbatim copies of this source file. + + You may modify this source file, and copy and distribute such + modified versions, provided that you leave the copyright notice + at the top of the file and also cause the modified file to carry + prominent notices stating that you changed the files and the date + of any change; and cause the whole of any work that you distribute + or publish, that in whole or in part contains or is a derivative of + this program or any part thereof, to be licensed at no charge to + all third parties on terms identical to those here. + + If you do have a fix to any problem, please send it to me, so that + other people can have the benefits. + + While every effort has been taken to make this program as reliable as + possible, no responsibility can be taken for the correctness of the + output, or suitability for any particular use. + + ACKNOWLEDGEMENTS + Many people have given time and ideas to making this program what it is. + To all of them thanks, and apologies for not mentioning them by name. +*/ + +#ifndef __FILE__ +#define __FILE__ "hard-params.c" +#endif + +#ifndef PASS +#define PASS 1 +#define PASS1 1 +#define VERSION "4.1" + +/* Procedure just marks the functions that don't return a result */ +#ifdef Procedure +#undef Procedure +#endif +#define Procedure + +#define Vprintf if (V) printf + +/* stdc is used in tests like if (stdc) */ +#ifdef __STDC__ +#define stdc 1 +#else +#define stdc 0 +#endif + +/* volatile is used to reduce the chance of optimisation, + and to prevent variables being put in registers (when setjmp/longjmp + wouldn't work as we want) */ +#ifndef __STDC__ +#define volatile static +#endif + +#include + +/* Kludge around the possiblity that includes */ +#ifdef CHAR_BIT +#undef CHAR_BIT +#undef CHAR_MAX +#undef CHAR_MIN +#undef SCHAR_MAX +#undef SCHAR_MIN +#undef UCHAR_MAX +#undef UCHAR_MIN +#endif + +#ifdef VERIFY +#include "limits.h" +#include "float.h" +#endif + +#ifdef NO_SIG /* There's no signal(), or setjmp/longjmp() */ + + /* Dummy routines instead */ + int lab=1; + int setjmp(lab) int lab; { return(0); } + signal(i, p) int i, (*p)(); {} + +#else + +#include +#include + + jmp_buf lab; + overflow(sig) int sig; { /* what to do on overflow/underflow */ + signal(sig, overflow); + longjmp(lab, 1); + } + +#endif /*NO_SIG*/ + +#define Unexpected(place) if (setjmp(lab)!=0) croak(place) + +int V= 0, /* verbose */ + L= 0, /* produce limits.h */ + F= 0, /* produce float.h */ + bugs=0; /* The number of (possible) bugs in the output */ + +char co[4], oc[4]; /* Comment starter and ender symbols */ + +int bits_per_byte; /* the number of bits per unit returned by sizeof() */ + +#ifdef TEST +/* Set the fp modes on a SUN with 68881 chip, to check that different + rounding modes etc. get properly detected. + Compile with additional flag -DTEST, and run with additional parameter + +hex-number, to set the 68881 mode register to hex-number +*/ + +/* Bits 0x30 = rounding mode: */ +#define ROUND_BITS 0x30 +#define TO_NEAREST 0x00 +#define TO_ZERO 0x10 +#define TO_MINUS_INF 0x20 +#define TO_PLUS_INF 0x30 /* The SUN FP user's guide seems to be wrong here */ + +/* Bits 0xc0 = extended rounding: */ +#define EXT_BITS 0xc0 +#define ROUND_EXTENDED 0x00 +#define ROUND_SINGLE 0x40 +#define ROUND_DOUBLE 0x80 + +/* Enabled traps: */ +#define EXE_INEX1 0x100 +#define EXE_INEX2 0x200 +#define EXE_DZ 0x400 +#define EXE_UNFL 0x800 +#define EXE_OVFL 0x1000 +#define EXE_OPERR 0x2000 +#define EXE_SNAN 0x4000 +#define EXE_BSUN 0x8000 + +printmode(new) unsigned new; { + fpmode_(&new); + printf("New fp mode:\n"); + printf(" Round toward "); + switch (new & ROUND_BITS) { + case TO_NEAREST: printf("nearest"); break; + case TO_ZERO: printf("zero"); break; + case TO_MINUS_INF: printf("minus infinity"); break; + case TO_PLUS_INF: printf("plus infinity"); break; + default: printf("???"); break; + } + + printf("\n Extended rounding precision: "); + + switch (new & EXT_BITS) { + case ROUND_EXTENDED: printf("extended"); break; + case ROUND_SINGLE: printf("single"); break; + case ROUND_DOUBLE: printf("double"); break; + default: printf("???"); break; + } + + printf("\n Enabled exceptions:"); + if (new & (unsigned) EXE_INEX1) printf(" inex1"); + if (new & (unsigned) EXE_INEX2) printf(" inex2"); + if (new & (unsigned) EXE_DZ) printf(" dz"); + if (new & (unsigned) EXE_UNFL) printf(" unfl"); + if (new & (unsigned) EXE_OVFL) printf(" ovfl"); + if (new & (unsigned) EXE_OPERR) printf(" operr"); + if (new & (unsigned) EXE_SNAN) printf(" snan"); + if (new & (unsigned) EXE_BSUN) printf(" bsun"); + printf("\n"); +} + +int setmode(s) char *s; { + unsigned mode=0, dig; + char c; + + while (*s) { + c= *s++; + if (c>='0' && c<='9') dig= c-'0'; + else if (c>='a' && c<='f') dig= c-'a'+10; + else if (c>='A' && c<='F') dig= c-'A'+10; + else return 1; + mode= mode<<4 | dig; + } + printmode(mode); + return 0; +} +#else +int setmode(s) char *s; { + fprintf(stderr, "Can't set mode: not compiled with TEST\n"); + return(1); +} +#endif + +croak(place) int place; { + printf("*** Unexpected signal at point %d\n", place); + exit(bugs+1); /* An exit isn't essential here, but avoids loops */ +} + +/* This is here in case alloca.c is used. That wants to call this. */ + +char * +xmalloc(size) unsigned size; { + char *malloc(); + char *value = malloc(size); + if (value == 0) { + fprintf(stderr, "Virtual memory exceeded\n"); + exit(bugs+1); + } + return value; +} + +main(argc, argv) int argc; char *argv[]; { + int dprec, fprec, lprec, basic(), fprop(), dprop(), efprop(), edprop(); + char *malloc(); + unsigned int size; + long total; + int i; char *s; int bad; + +#ifdef SIGFPE + signal(SIGFPE, overflow); +#endif +#ifdef SIGOVER + signal(SIGOVER, overflow); +#endif +/* Add more calls as necessary */ + + Unexpected(1); + + bad=0; + for (i=1; i < argc; i++) { + s= argv[i]; + if (*s == '-') { + s++; + while (*s) { + switch (*(s++)) { + case 'v': V=1; break; + case 'l': L=1; break; + case 'f': F=1; break; + default: bad=1; break; + } + } + } else if (*s == '+') { + s++; + bad= setmode(s); + } else bad= 1; + } + if (bad) { + fprintf(stderr, + "Usage: %s [-vlf]\n v=Verbose l=Limits.h f=Float.h\n", + argv[0]); + exit(1); + } + if (L || F) { + co[0]= '/'; oc[0]= ' '; + co[1]= '*'; oc[1]= '*'; + co[2]= ' '; oc[2]= '/'; + co[3]= '\0'; oc[3]= '\0'; + } else { + co[0]= '\0'; oc[0]= '\0'; + V=1; + } + + if (L) printf("%slimits.h%s\n", co, oc); + if (F) printf("%sfloat.h%s\n", co, oc); +#ifdef ID + printf("%sProduced on %s by hard-params version %s, CWI, Amsterdam%s\n", + co, ID, VERSION, oc); +#else + printf("%sProduced by hard-params version %s, CWI, Amsterdam%s\n", + co, VERSION, oc); +#endif + +#ifdef VERIFY + printf("%sVerification phase%s\n", co, oc); +#endif + +#ifdef NO_SIG + Vprintf("%sCompiled without signal(): %s%s\n", + co, + "there's nothing that can be done if overflow occurs", + oc); +#endif +#ifdef NO_SC + Vprintf("%sCompiled without signed char%s\n", co, oc); +#endif +#ifdef NO_UC + Vprintf("%Compiled without unsigned char%s\n", co, oc); +#endif +#ifdef NO_UI + Vprintf("%Compiled without unsigned short or long%s\n", co, oc); +#endif +#ifdef __STDC__ + Vprintf("%sCompiler claims to be ANSI C level %d%s\n", + co, __STDC__, oc); +#else + Vprintf("%sCompiler does not claim to be ANSI C%s\n", co, oc); +#endif + printf("\n"); + bits_per_byte= basic(); + Vprintf("\n"); + if (F||V) { + fprec= fprop(bits_per_byte); + dprec= dprop(bits_per_byte); + lprec= ldprop(bits_per_byte); + efprop(fprec, dprec, lprec); + edprop(fprec, dprec, lprec); + eldprop(fprec, dprec, lprec); + } + if (V) { + /* An extra goody: the approximate amount of data-space */ + /* Allocate store until no more available */ + size=1<<((bits_per_byte*sizeof(int))-2); + total=0; + while (size!=0) { + while (malloc(size)!=(char *)NULL) total+=(size/2); + size/=2; + } + + Vprintf("%sMemory mallocatable ~= %ld Kbytes%s\n", + co, (total+511)/512, oc); + } + exit(bugs); +} + +Procedure eek_a_bug(problem) char *problem; { + printf("\n%s*** WARNING: %s%s\n", co, problem, oc); + bugs++; +} + +Procedure i_define(sort, name, val, req) char *sort, *name; long val, req; { + if (val >= 0) { + printf("#define %s%s %ld\n", sort, name, val); + } else { + printf("#define %s%s (%ld)\n", sort, name, val); + } + if (val != req) { + printf("%s*** Verify failed for above #define!\n", co); + printf(" Compiler has %ld for value%s\n\n", req, oc); + bugs++; + } + Vprintf("\n"); +} + +#ifndef NO_UI + +#ifdef __STDC__ +#define U "U" +#else +#define U "" +#endif + +Procedure u_define(sort, name, val, req) char *sort, *name; unsigned long val, req; { + printf("#define %s%s %lu%s\n", sort, name, val, U); + if (val != req) { + printf("%s*** Verify failed for above #define!\n", co); + printf(" Compiler has %lu for value%s\n\n", req, oc); + bugs++; + } + Vprintf("\n"); +} +#endif + +/* Long_double is the longest floating point type available: */ +#if defined(__STDC__) && !defined(NO_LONG_DOUBLE) +#define Long_double long double +#else +#define Long_double double +#endif + +char *f_rep(); + +Procedure f_define(sort, name, precision, val, mark) + char *sort, *name; int precision; Long_double val; char *mark; { + if (stdc) { + printf("#define %s%s %s%s\n", + sort, name, f_rep(precision, val), mark); + } else if (*mark == 'F') { + /* non-ANSI C has no float constants, so cast the constant */ + printf("#define %s%s ((float)%s)\n", + sort, name, f_rep(precision, val)); + } else { + printf("#define %s%s %s\n", sort, name, f_rep(precision, val)); + } + Vprintf("\n"); +} + +int floor_log(base, x) int base; Long_double x; { /* return floor(log base(x)) */ + int r=0; + while (x>=base) { r++; x/=base; } + return r; +} + +int ceil_log(base, x) int base; Long_double x; { + int r=0; + while (x>1.0) { r++; x/=base; } + return r; +} + +int exponent(x, fract, exp) Long_double x; double *fract; int *exp; { + /* Split x into a fraction and a power of ten; + returns 0 if x is unusable, 1 otherwise. + Only used for error messages about faulty output. + */ + int r=0, neg=0; + Long_double old; + *fract=0.0; *exp=0; + if (x<0.0) { + x= -x; + neg= 1; + } + if (x==0.0) return 1; + if (x>=10.0) { + while (x>=10.0) { + old=x; r++; x/=10.0; + if (old==x) return 0; + } + } else { + while (x<1.0) { + old=x; r--; x*=10.0; + if (old==x) return 0; + } + } + if (neg) *fract= -x; + else *fract=x; + *exp=r; + return 1; +} + +#define fabs(x) (((x)<0.0)?(-x):(x)) + +char *f_rep(precision, val) int precision; Long_double val; { + static char buf[1024]; + char *f1; + if (sizeof(double) == sizeof(Long_double)) { + /* Assume they're the same, and use non-stdc format */ + /* This is for stdc compilers using non-stdc libraries */ + f1= "%.*e"; + } else { + /* It had better support Le then */ + f1= "%.*Le"; + } + sprintf(buf, f1, precision, val); + return buf; +} + +Procedure bitpattern(p, size) char *p; int size; { + char c; + int i, j; + + for (i=1; i<=size; i++) { + c= *p; + p++; + for (j=bits_per_byte-1; j>=0; j--) + printf("%c", (c>>j)&1 ? '1' : '0'); + if (i!=size) printf(" "); + } +} + +#define Order(x, px, mode)\ + printf("%s %s ", co, mode); for (i=0; i>(bits_per_byte*(sizeof(x)-i)))&mask)); }\ + printf("%s\n", oc); + +Procedure endian(bits_per_byte) int bits_per_byte; { + /*unsigned*/ short s=0; + /*unsigned*/ int j=0; + /*unsigned*/ long l=0; + + char *ps= (char *) &s, + *pj= (char *) &j, + *pl= (char *) &l, + *c= "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + unsigned int mask, i; + + mask=0; + for (i=1; i<=bits_per_byte; i++) mask= (mask<<1)|1; + + if (V) { + printf("%sCharacter order:%s\n", co, oc); + Order(s, ps, "short:"); + Order(j, pj, "int: "); + Order(l, pl, "long: "); + } +} + +#ifdef VERIFY +#ifndef SCHAR_MAX +#define SCHAR_MAX char_max +#define SCHAR_MIN char_min +#endif +#ifndef UCHAR_MAX +#define UCHAR_MAX char_max +#endif +#else +#define CHAR_BIT char_bit +#define CHAR_MAX char_max +#define CHAR_MIN char_min +#define SCHAR_MAX char_max +#define SCHAR_MIN char_min +#define UCHAR_MAX char_max +#endif /* VERIFY */ + +int cprop() { /* Properties of character */ + volatile char c, char_max, char_min; + volatile int bits_per_byte, is_signed; + long char_bit; + + Unexpected(2); + + /* Calculate number of bits per character *************************/ + c=1; bits_per_byte=0; + do { c=c<<1; bits_per_byte++; } while(c!=0); + c= (char)(-1); + if (((int)c)<0) is_signed=1; + else is_signed=0; + Vprintf("%sChar = %d bits, %ssigned%s\n", + co, (int)sizeof(c)*bits_per_byte, (is_signed?"":"un"), oc); + char_bit=(long)(sizeof(c)*bits_per_byte); + if (L) i_define("CHAR", "_BIT", char_bit, (long) CHAR_BIT); + + c=0; char_max=0; + c++; + 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 (cchar_max) { + char_max=c; + c++; + } + } + Unexpected(4); + i_define("UCHAR", "_MAX", (long) char_max, + (long) UCHAR_MAX); +#endif + } else { +#ifndef NO_SC /* Define NO_SC if the next line gives a syntax error */ + volatile signed char c, char_max, char_min; + c=0; char_max=0; + c++; + if (setjmp(lab)==0) { /* Yields char_max */ + while (c>char_max) { + char_max=c; + c++; + } + } + c=0; char_min=0; + c--; + if (setjmp(lab)==0) { /* Yields char_min */ + while (csizeof(int)?" BEWARE! larger than int!":"", + oc); + Vprintf("%sInt pointers = %d bits%s%s\n", + co, (int)sizeof(int *)*bits_per_byte, + sizeof(int *)>sizeof(int)?" BEWARE! larger than int!":"", + oc); + sprop(); + iprop(); + lprop(); + usprop(); + uiprop(); + ulprop(); + + Unexpected(6); + + /* Alignment constants ********************************************/ + Vprintf("%sAlignments used for char=%d short=%d int=%d long=%d%s\n", + co, + (int)sizeof(struct{char i1; char c1;})-(int)sizeof(char), + (int)sizeof(struct{short i2; char c2;})-(int)sizeof(short), + (int)sizeof(struct{int i3; char c3;})-(int)sizeof(int), + (int)sizeof(struct{long i4; char c4;})-(int)sizeof(long), + oc); + + /* Ten little endians *********************************************/ + + endian(bits_per_byte); + + /* Pointers *******************************************************/ + if (V) { + if ("abcd"=="abcd") + printf("%sStrings are shared%s\n", co, oc); + else printf("%sStrings are not shared%s\n", co, oc); + } + + return bits_per_byte; +} + +#endif /* ifndef PASS */ + +/* As I said, I apologise for the contortions below. The functions are + expanded by the preprocessor twice or three times (for float and double, + and maybe for long double, and for short, int and long). That way, + I never make a change to one that I forget to make to the other. + You can look on it as C's fault for not supporting multi-line macro's. + This whole file is read 3 times by the preprocessor, with PASSn set for + n=1, 2 or 3, to decide which parts to reprocess. +*/ + +/* #undef on an already undefined thing is (wrongly) flagged as an error + by some compilers, therefore the #ifdef that follows: +*/ +#ifdef Number +#undef Number +#undef THING +#undef Thing +#undef thing +#undef FPROP +#undef Fname +#undef Store +#undef Sum +#undef Diff +#undef Mul +#undef Div +#undef Self +#undef F_check +#undef Validate +#undef EPROP +#undef MARK + +#undef F_RADIX +#undef F_MANT_DIG +#undef F_DIG +#undef F_ROUNDS +#undef F_EPSILON +#undef F_MIN_EXP +#undef F_MIN +#undef F_MIN_10_EXP +#undef F_MAX_EXP +#undef F_MAX +#undef F_MAX_10_EXP +#endif + +#ifdef Integer +#undef Integer +#undef INT +#undef IPROP +#undef Iname +#undef UPROP +#undef Uname +#undef OK_UI + +#undef I_MAX +#undef I_MIN +#undef U_MAX +#endif + +#ifdef PASS1 + +#define Number float +#define THING "FLOAT" +#define Thing "Float" +#define thing "float" +#define Fname "FLT" +#define FPROP fprop +#define Store fStore +#define Sum fSum +#define Diff fDiff +#define Mul fMul +#define Div fDiv +#define Self fSelf +#define F_check fCheck +#define Validate fValidate +#define MARK "F" + +#define EPROP efprop + +#define Integer short +#define INT "short" +#define IPROP sprop +#define Iname "SHRT" +#ifndef NO_UI +#define OK_UI 1 +#endif + +#define UPROP usprop +#define Uname "USHRT" + +#ifdef VERIFY +#define I_MAX SHRT_MAX +#define I_MIN SHRT_MIN +#define U_MAX USHRT_MAX + +#define F_RADIX FLT_RADIX +#define F_MANT_DIG FLT_MANT_DIG +#define F_DIG FLT_DIG +#define F_ROUNDS FLT_ROUNDS +#define F_EPSILON FLT_EPSILON +#define F_MIN_EXP FLT_MIN_EXP +#define F_MIN FLT_MIN +#define F_MIN_10_EXP FLT_MIN_10_EXP +#define F_MAX_EXP FLT_MAX_EXP +#define F_MAX FLT_MAX +#define F_MAX_10_EXP FLT_MAX_10_EXP +#endif /* VERIFY */ + +#endif /* PASS1 */ + +#ifdef PASS2 + +#define Number double +#define THING "DOUBLE" +#define Thing "Double" +#define thing "double" +#define Fname "DBL" +#define FPROP dprop +#define Store dStore +#define Sum dSum +#define Diff dDiff +#define Mul dMul +#define Div dDiv +#define Self dSelf +#define F_check dCheck +#define Validate dValidate +#define MARK "" + +#define EPROP edprop + +#define Integer int +#define INT "int" +#define IPROP iprop +#define Iname "INT" +#define OK_UI 1 /* Unsigned int is always possible */ + +#define UPROP uiprop +#define Uname "UINT" + +#ifdef VERIFY +#define I_MAX INT_MAX +#define I_MIN INT_MIN +#define U_MAX UINT_MAX + +#define F_MANT_DIG DBL_MANT_DIG +#define F_DIG DBL_DIG +#define F_EPSILON DBL_EPSILON +#define F_MIN_EXP DBL_MIN_EXP +#define F_MIN DBL_MIN +#define F_MIN_10_EXP DBL_MIN_10_EXP +#define F_MAX_EXP DBL_MAX_EXP +#define F_MAX DBL_MAX +#define F_MAX_10_EXP DBL_MAX_10_EXP +#endif /* VERIFY */ + +#endif /* PASS2 */ + +#ifdef PASS3 + +#if defined(__STDC__) && !defined(NO_LONG_DOUBLE) +#define Number long double +#endif + +#define THING "LONG DOUBLE" +#define Thing "Long double" +#define thing "long double" +#define Fname "LDBL" +#define FPROP ldprop +#define Store ldStore +#define Sum ldSum +#define Diff ldDiff +#define Mul ldMul +#define Div ldDiv +#define Self ldSelf +#define F_check ldCheck +#define Validate ldValidate +#define MARK "L" + +#define EPROP eldprop + +#define Integer long +#define INT "long" +#define IPROP lprop +#define Iname "LONG" +#ifndef NO_UI +#define OK_UI 1 +#endif + +#define UPROP ulprop +#define Uname "ULONG" + +#ifdef VERIFY +#define I_MAX LONG_MAX +#define I_MIN LONG_MIN +#define U_MAX ULONG_MAX + +#define F_MANT_DIG LDBL_MANT_DIG +#define F_DIG LDBL_DIG +#define F_EPSILON LDBL_EPSILON +#define F_MIN_EXP LDBL_MIN_EXP +#define F_MIN LDBL_MIN +#define F_MIN_10_EXP LDBL_MIN_10_EXP +#define F_MAX_EXP LDBL_MAX_EXP +#define F_MAX LDBL_MAX +#define F_MAX_10_EXP LDBL_MAX_10_EXP +#endif /* VERIFY */ + +#endif /* PASS3 */ + +#ifndef VERIFY +#define I_MAX int_max +#define I_MIN int_min +#define U_MAX int_max + +#define F_RADIX f_radix +#define F_MANT_DIG f_mant_dig +#define F_DIG f_dig +#define F_ROUNDS f_rounds +#define F_EPSILON f_epsilon +#define F_MIN_EXP f_min_exp +#define F_MIN f_min +#define F_MIN_10_EXP f_min_10_exp +#define F_MAX_EXP f_max_exp +#define F_MAX f_max +#define F_MAX_10_EXP f_max_10_exp +#endif + +Procedure IPROP() { /* for short, int, and long */ + volatile Integer newi, int_max, maxeri, int_min, minneri; + volatile int ibits, ipower, two=2; + + /* Calculate max short/int/long ***********************************/ + /* Calculate 2**n-1 until overflow - then use the previous value */ + + newi=1; int_max=0; + + if (setjmp(lab)==0) { /* Yields int_max */ + for(ipower=0; newi>int_max; ipower++) { + int_max=newi; + newi=newi*two+1; + } + Vprintf("%sOverflow of a%s %s does not generate a trap%s\n", + co, INT[0]=='i'?"n":"", INT, oc); + } else { + Vprintf("%sOverflow of a%s %s generates a trap%s\n", + co, INT[0]=='i'?"n":"", INT, oc); + } + Unexpected(7); + + /* Minimum value: assume either two's or one's complement *********/ + int_min= -int_max; + if (setjmp(lab)==0) { /* Yields int_min */ + if (int_min-1 < int_min) int_min--; + } + Unexpected(8); + + /* Now for those daft Cybers: */ + + maxeri=0; newi=int_max; + + if (setjmp(lab)==0) { /* Yields maxeri */ + for(ibits=ipower; newi>maxeri; ibits++) { + maxeri=newi; + newi=newi+newi+1; + } + } + Unexpected(9); + + minneri= -maxeri; + if (setjmp(lab)==0) { /* Yields minneri */ + if (minneri-1 < minneri) minneri--; + } + Unexpected(10); + + Vprintf("%sMaximum %s = %ld (= 2**%d-1)%s\n", + co, INT, (long)int_max, ipower, oc); + Vprintf("%sMinimum %s = %ld%s\n", co, INT, (long)int_min, oc); + + if (L) i_define(Iname, "_MAX", (long) int_max, (long) I_MAX); + if (L) i_define(Iname, "_MIN", (long) int_min, (long) I_MIN); + + if (maxeri>int_max) { + Vprintf("%sThere is a larger %s, %ld (= 2**%d-1), %s %s%s\n", + co, INT, (long)maxeri, ibits, + "but only for addition, not multiplication", + "(I smell a Cyber!)", + oc); + } + + if (minneriint_max) { + int_max=newi; + newi=newi*two+1; + } + } + Unexpected(11); + Vprintf("%sMaximum unsigned %s = %lu%s\n", + co, INT, (unsigned long) int_max, oc); + if (L) u_define(Uname, "_MAX", (unsigned long) int_max, + (unsigned long) U_MAX); +#endif +} + + +#ifdef Number + +/* These routines are intended to defeat any attempt at optimisation + or use of extended precision, and to defeat faulty narrowing casts: +*/ +Procedure Store(a, b) Number a, *b; { *b=a; } +Number Sum(a, b) Number a, b; { Number r; Store(a+b, &r); return (r); } +Number Diff(a, b) Number a, b; { Number r; Store(a-b, &r); return (r); } +Number Mul(a, b) Number a, b; { Number r; Store(a*b, &r); return (r); } +Number Div(a, b) Number a, b; { Number r; Store(a/b, &r); return (r); } +Number Self(a) Number a; { Number r; Store(a, &r); return (r); } + +Procedure F_check(precision, val1) int precision; Long_double val1; { + /* You don't think I'm going to go to all the trouble of writing + a program that works out what all sorts of values are, only to + have printf go and print the wrong values out, do you? + No, you're right, so this function tries to see if printf + has written the right value, by reading it back again. + This introduces a new problem of course: suppose printf writes + the correct value, and scanf reads it back wrong... oh well. + But I'm adamant about this: the precision given is enough + to uniquely identify the printed number, therefore I insist + that sscanf read the number back identically. Harsh yes, but + sometimes you've got to be cruel to be kind. + */ + Long_double new1; + Number val, new, diff; + double rem; + int e; + char *rep; + char *f2; + + if (sizeof(double) == sizeof(Long_double)) { + /* Assume they're the same, and use non-stdc format */ + /* This is for stdc compilers using non-stdc libraries */ + f2= "%le"; /* Input */ + } else { + /* It had better support Le then */ + f2= "%Le"; + } + val= val1; + rep= f_rep(precision, (Long_double) val); + if (setjmp(lab)==0) { + sscanf(rep, f2, &new1); + } else { + eek_a_bug("sscanf caused a trap"); + printf("%s scanning: %s format: %s%s\n\n", co, rep, f2, oc); + Unexpected(12); + return; + } + + if (setjmp(lab)==0) { /* See if new is usable */ + new= new1; + if (new != 0.0) { + diff= val/new - 1.0; + if (diff < 0.1) diff= 1.0; + /* That should be enough to generate a trap */ + } + } else { + eek_a_bug("sscanf returned an unusable number"); + printf("%s scanning: %s with format: %s%s\n\n", + co, rep, f2, oc); + Unexpected(13); + return; + } + + Unexpected(14); + if (new != val) { + eek_a_bug("Possibly bad output from printf above"); + if (!exponent(val, &rem, &e)) { + printf("%s but value was an unusable number%s\n\n", + co, oc); + return; + } + printf("%s expected value around %.*fe%d, bit pattern:\n ", + co, precision, rem, e); + bitpattern((char *) &val, sizeof(val)); + printf ("%s\n", oc); + printf("%s sscanf gave %s, bit pattern:\n ", + co, f_rep(precision, (Long_double) new)); + bitpattern((char *) &new, sizeof(new)); + printf ("%s\n", oc); + printf("%s difference= %s%s\n\n", + co, f_rep(precision, (Long_double) (val-new)), oc); + } +} + +Procedure Validate(prec, val, req, same) int prec, same; Long_double val, req; { + Unexpected(15); + if (!same) { + printf("%s*** Verify failed for above #define!\n", co); + if (setjmp(lab) == 0) { /* for the case that req == nan */ + printf(" Compiler has %s for value%s\n", + f_rep(prec, req), oc); + } else { + printf(" Compiler has %s for value%s\n", + "an unusable number", oc); + } + if (setjmp(lab) == 0) { + F_check(prec, (Long_double) req); + } /*else forget it*/ + if (setjmp(lab) == 0) { + if (req > 0.0 && val > 0.0) { + printf("%s difference= %s%s\n", + co, f_rep(prec, val-req), oc); + } + } /*else forget it*/ + Unexpected(16); + printf("\n"); + bugs++; + } else if (val != req) { + if (stdc) { + printf("%s*** Verify failed for above #define!\n", co); + printf(" Constant has the wrong precision%s\n", + oc); + bugs++; + } else eek_a_bug("the cast didn't work"); + printf("\n"); + } +} + +int FPROP(bits_per_byte) int bits_per_byte; { + /* Properties of floating types, using algorithms by Cody and Waite + from MA Malcolm, as modified by WM Gentleman and SB Marovich. + Further extended by S Pemberton. + + Returns the number of digits in the fraction. + */ + + volatile int i, f_radix, iexp, irnd, mrnd, f_rounds, f_mant_dig, + iz, k, inf, machep, f_max_exp, f_min_exp, mx, negeps, + mantbits, digs, f_dig, trap, + hidden, normal, f_min_10_exp, f_max_10_exp; + volatile Number a, b, base, basein, basem1, f_epsilon, epsneg, + f_max, newxmax, f_min, xminner, y, y1, z, z1, z2; + + Unexpected(17); + + Vprintf("%sPROPERTIES OF %s:%s\n", co, THING, oc); + + /* Base and size of mantissa **************************************/ + /* First repeatedly double until adding 1 has no effect. */ + /* For instance, if base is 10, with 3 significant digits */ + /* it will try 1, 2, 4, 8, ... 512, 1024, and stop there, */ + /* since 1024 is only representable as 1020. */ + a=1.0; + if (setjmp(lab)==0) { /* inexact trap? */ + do { a=Sum(a, a); } + while (Diff(Diff(Sum(a, 1.0), a), 1.0) == 0.0); + } else { + fprintf(stderr, "*** Program got loss-of-precision trap!\n"); + /* And supporting those is just TOO much trouble! */ + exit(bugs+1); + } + Unexpected(18); + /* Now double until you find a number that can be added to the */ + /* above number. For 1020 this is 8 or 16, depending whether the */ + /* result is rounded or truncated. */ + /* In either case the result is 1030. 1030-1020= the base, 10. */ + b=1.0; + do { b=Sum(b, b); } while ((base=Diff(Sum(a, b), a)) == 0.0); + f_radix=base; + Vprintf("%sBase = %d%s\n", co, f_radix, oc); + + /* Sanity check; if base<2, I can't guarantee the rest will work */ + if (f_radix < 2) { + eek_a_bug("Function return or parameter passing faulty? (This is a guess.)"); + printf("\n"); + return(0); + } + +#ifdef PASS1 /* only for FLT */ + if (F) i_define("FLT", "_RADIX", (long) f_radix, (long) F_RADIX); +#endif + + /* Now the number of digits precision: */ + f_mant_dig=0; b=1.0; + do { f_mant_dig++; b=Mul(b, base); } + while (Diff(Diff(Sum(b,1.0),b),1.0) == 0.0); + f_dig=floor_log(10, (Long_double)(b/base)) + (base==10?1:0); + Vprintf("%sSignificant base digits = %d %s %d %s%s\n", + co, f_mant_dig, "(= at least", f_dig, "decimal digits)", oc); + if (F) i_define(Fname, "_MANT_DIG", (long) f_mant_dig, + (long) F_MANT_DIG); + if (F) i_define(Fname, "_DIG", (long) f_dig, (long) F_DIG); + digs= ceil_log(10, (Long_double)b); /* the number of digits to printf */ + + /* Rounding *******************************************************/ + basem1=Diff(base, 0.5); + if (Diff(Sum(a, basem1), a) != 0.0) { + if (f_radix == 2) basem1=0.375; + else basem1=1.0; + if (Diff(Sum(a, basem1), a) != 0.0) irnd=2; /* away from 0 */ + else irnd=1; /* to nearest */ + } else irnd=0; /* towards 0 */ + + basem1=Diff(base, 0.5); + + if (Diff(Diff(-a, basem1), -a) != 0.0) { + if (f_radix == 2) basem1=0.375; + else basem1=1.0; + if (Diff(Diff(-a, basem1), -a) != 0.0) mrnd=2; /* away from 0*/ + else mrnd=1; /* to nearest */ + } else mrnd=0; /* towards 0 */ + + f_rounds=4; /* Unknown rounding */ + if (irnd==0 && mrnd==0) f_rounds=0; /* zero = chops */ + if (irnd==1 && mrnd==1) f_rounds=1; /* nearest */ + if (irnd==2 && mrnd==0) f_rounds=2; /* +inf */ + if (irnd==0 && mrnd==2) f_rounds=3; /* -inf */ + + if (f_rounds != 4) { + Vprintf("%sArithmetic rounds towards ", co); + switch (f_rounds) { + case 0: Vprintf("zero (i.e. it chops)"); break; + case 1: Vprintf("nearest"); break; + case 2: Vprintf("+infinity"); break; + case 3: Vprintf("-infinity"); break; + default: Vprintf("???"); break; + } + Vprintf("%s\n", oc); + } else { /* Hmm, try to give some help here: */ + Vprintf("%sArithmetic rounds oddly: %s\n", co, oc); + Vprintf("%s Negative numbers %s%s\n", + co, mrnd==0 ? "towards zero" : + mrnd==1 ? "to nearest" : + "away from zero", + oc); + Vprintf("%s Positive numbers %s%s\n", + co, irnd==0 ? "towards zero" : + irnd==1 ? "to nearest" : + "away from zero", + oc); + } + /* An extra goody */ + if (f_radix == 2 && f_rounds == 1) { + if (Diff(Sum(a, 1.0), a) != 0.0) { + Vprintf("%s Tie breaking rounds up%s\n", co, oc); + } else if (Diff(Sum(a, 3.0), a) == 4.0) { + Vprintf("%s Tie breaking rounds to even%s\n", co, oc); + } else { + Vprintf("%s Tie breaking rounds down%s\n", co, oc); + } + } +#ifdef PASS1 /* only for FLT */ + if (F) i_define("FLT", "_ROUNDS", (long) f_rounds, (long) F_ROUNDS); +#endif + + /* Various flavours of epsilon ************************************/ + negeps=f_mant_dig+f_mant_dig; + basein=1.0/base; + a=1.0; + for(i=1; i<=negeps; i++) a*=basein; + + b=a; + while (Diff(Diff(1.0, a), 1.0) == 0.0) { + a*=base; + negeps--; + } + negeps= -negeps; + Vprintf("%sSmallest x such that 1.0-base**x != 1.0 = %d%s\n", + co, negeps, oc); + + epsneg=a; + if ((f_radix!=2) && irnd) { + /* a=(a*(1.0+a))/(1.0+1.0); => */ + a=Div(Mul(a, Sum(1.0, a)), Sum(1.0, 1.0)); + /* if ((1.0-a)-1.0 != 0.0) epsneg=a; => */ + if (Diff(Diff(1.0, a), 1.0) != 0.0) epsneg=a; + } + Vprintf("%sSmall x such that 1.0-x != 1.0 = %s%s\n", + co, f_rep(digs, (Long_double) epsneg), oc); + /* it may not be the smallest */ + if (V) F_check(digs, (Long_double) epsneg); + Unexpected(19); + + machep= -f_mant_dig-f_mant_dig; + a=b; + while (Diff(Sum(1.0, a), 1.0) == 0.0) { a*=base; machep++; } + Vprintf("%sSmallest x such that 1.0+base**x != 1.0 = %d%s\n", + co, machep, oc); + + f_epsilon=a; + if ((f_radix!=2) && irnd) { + /* a=(a*(1.0+a))/(1.0+1.0); => */ + a=Div(Mul(a, Sum(1.0, a)), Sum(1.0, 1.0)); + /* if ((1.0+a)-1.0 != 0.0) f_epsilon=a; => */ + if (Diff(Sum(1.0, a), 1.0) != 0.0) f_epsilon=a; + } + Vprintf("%sSmallest x such that 1.0+x != 1.0 = %s%s\n", + co, f_rep(digs, (Long_double) f_epsilon), oc); + /* Possible loss of precision warnings here from non-stdc compilers: */ + if (F) f_define(Fname, "_EPSILON", digs, (Long_double) f_epsilon, MARK); + if (V || F) F_check(digs, (Long_double) f_epsilon); + Unexpected(20); + if (F) Validate(digs, (Long_double) f_epsilon, (Long_double) F_EPSILON, + f_epsilon == Self(F_EPSILON)); + Unexpected(21); + + /* Extra chop info *************************************************/ + if (f_rounds == 0) { + if (Diff(Mul(Sum(1.0,f_epsilon),1.0),1.0) != 0.0) { + Vprintf("%sAlthough arithmetic chops, it uses guard digits%s\n", co, oc); + } + } + + /* Size of and minimum normalised exponent ************************/ + y=0; i=0; k=1; z=basein; z1=(1.0+f_epsilon)/base; + + /* Coarse search for the largest power of two */ + if (setjmp(lab)==0) { /* for underflow trap */ /* Yields i, k, y, y1 */ + do { + y=z; y1=z1; + z=Mul(y,y); z1=Mul(z1, y); + a=Mul(z,1.0); + z2=Div(z1,y); + if (z2 != y1) break; + if ((Sum(a,a) == 0.0) || (fabs(z) >= y)) break; + i++; + k+=k; + } while(1); + } else { + Vprintf("%s%s underflow generates a trap%s\n", co, Thing, oc); + } + Unexpected(22); + + if (f_radix != 10) { + iexp=i+1; /* for the sign */ + mx=k+k; + } else { + iexp=2; + iz=f_radix; + while (k >= iz) { iz*=f_radix; iexp++; } + mx=iz+iz-1; + } + + /* Fine tune starting with y and y1 */ + if (setjmp(lab)==0) { /* for underflow trap */ /* Yields k, f_min */ + do { + f_min=y; z1=y1; + y=Div(y,base); y1=Div(y1,base); + a=Mul(y,1.0); + z2=Mul(y1,base); + if (z2 != z1) break; + if ((Sum(a,a) == 0.0) || (fabs(y) >= f_min)) break; + k++; + } while (1); + } + Unexpected(23); + + f_min_exp=(-k)+1; + + if ((mx <= k+k-3) && (f_radix != 10)) { mx+=mx; iexp+=1; } + Vprintf("%sNumber of bits used for exponent = %d%s\n", co, iexp, oc); + Vprintf("%sMinimum normalised exponent = %d%s\n", co, f_min_exp, oc); + if (F) i_define(Fname, "_MIN_EXP", (long) f_min_exp, (long) F_MIN_EXP); + + if (setjmp(lab)==0) { + Vprintf("%sMinimum normalised positive number = %s%s\n", + co, f_rep(digs, (Long_double) f_min), oc); + } else { + eek_a_bug("printf can't print the smallest normalised number"); + printf("\n"); + } + Unexpected(24); + /* Possible loss of precision warnings here from non-stdc compilers: */ + if (setjmp(lab) == 0) { + if (F) f_define(Fname, "_MIN", digs, (Long_double) f_min, MARK); + if (V || F) F_check(digs, (Long_double) f_min); + } else { + eek_a_bug("xxx_MIN caused a trap"); + printf("\n"); + } + + if (setjmp(lab) == 0) { + if (F) Validate(digs, (Long_double) f_min, (Long_double) F_MIN, + f_min == Self(F_MIN)); + } else { + printf("%s*** Verify failed for above #define!\n %s %s\n\n", + co, "Compiler has an unusable number for value", oc); + bugs++; + } + Unexpected(25); + + a=1.0; f_min_10_exp=0; + while (a > f_min*10.0) { a/=10.0; f_min_10_exp--; } + if (F) i_define(Fname, "_MIN_10_EXP", (long) f_min_10_exp, + (long) F_MIN_10_EXP); + + /* Minimum exponent ************************************************/ + if (setjmp(lab)==0) { /* for underflow trap */ /* Yields xminner */ + do { + xminner=y; + y=Div(y,base); + a=Mul(y,1.0); + if ((Sum(a,a) == 0.0) || (fabs(y) >= xminner)) break; + } while (1); + } + Unexpected(26); + + if (xminner != 0.0 && xminner != f_min) { + normal= 0; + Vprintf("%sThe smallest numbers are not kept normalised%s\n", + co, oc); + if (setjmp(lab)==0) { + Vprintf("%sSmallest unnormalised positive number = %s%s\n", + co, f_rep(digs, (Long_double) xminner), oc); + if (V) F_check(digs, (Long_double) xminner); + } else { + eek_a_bug("printf can't print the smallest unnormalised number."); + printf("\n"); + } + Unexpected(27); + } else { + normal= 1; + Vprintf("%sThe smallest numbers are normalised%s\n", co, oc); + } + + /* Maximum exponent ************************************************/ + f_max_exp=2; f_max=1.0; newxmax=base+1.0; + inf=0; trap=0; + while (f_max